Table of Contents

Intro

Plupload supports manipulating images (JPEGs and PNGs) on client-side, which includes downsizing them, dropping their quality (for JPEGs only) and stripping off the meta headers (for JPEGs only as well) - all to make them smaller in size and save the bandwidth.

Might be very handy, when image is uploaded only to become a tiny avatar, etc. Currently it is not suitable for generating high-quality images (see #707), because it is using a default algorithm (apparently a so called nearest neighbor interpolation) for resizing. We are planning to adapt a bilinear interpolation algorithm in the nearest releases.

Lets build up on the code that we wrote for [[Getting Started]].

Options

resize option is a compound object with some sub-options:

  • width - if image is wider, it will be resized (if not specified, original image width will be used).
  • height - if image is higher, it will be resized (if not specified original image height will be used).
  • crop - whether to crop the portion of the image specified by width and height, instead of resizing (default false).
  • fit - controls whether the cropped portion should be scaled to fit the specified dimensions or not (default false).
  • resample - what resampling algorithm to use during resize; currently only bilinear resampling is supported (default default, which means that no resampling will happen)
  • multipass - whether to use gradual resizing or do it in one step (default true - better quality, but slower)
  • type - the MIME type of the resulting image (default image/jpeg)
  • quality - quality of resulting JPEG (PNGs are not affected) (default 90).
  • preserve_headers - whether to preserve JPEG meta headers (PNGs are not affected), e.g.: Exif, Gps, IPTC, etc (default true).

Enable resizing

To enable resizing on the client-side we need to pass in resize option with new width and height (obviously resize is not the best name for the option, since currently we can only downsize). Because we are building up on [[Getting Started]] code, updated configuration should look something like this:

var uploader = new plupload.Uploader({
  browse_button: 'browse', // this can be an id of a DOM element or the DOM element itself
  url: 'upload.php',
  resize: {
    width: 100,
    height: 100 
  }
});

Plupload will take the larger side of the image and resize it to fit the specified dimensions. The other side will be resized proportionally. Bot downscaling and upscaling is supported.

It is worth to mention that having resize option in configuration doesn't mean that Plupload will be constrained to images only (there's another option for that). It simply means that if Plupload will encounter an image in the queue it will try to process it prior to uploading (if it meets the requirements), according to the specified settings. All other file types will be uploaded as usual.

Crop

If proportional resizing is not what you are looking for and you'd rather simply cut out the portion of the image, try another sub-option - crop. Being a mixed variable, by default it is set to false, which means that crop is disabled. If all you want is - cut out the rectangle of the specific size right from the center of the image, simply set it to true. However we support targeted cropping, which means that you can specify the exact corner to cut the rectangle from, either by supplying one of the supported constants, like LEFT_TOP or their short versions using only initials - LT. Here is the list of supported constants and their short equivalents:

  • LEFT_TOP or LT - left top corner
  • CENTER_TOP or CT - the center of the top side
  • RIGHT_TOP or RT - right top corner
  • RIGHT_CENTER or RC - the center of the right side
  • RIGHT_BOTTOM or RB - right bottom corner
  • CENTER_BOTTOM or CB - the center of the bottom side
  • LEFT_BOTTOM or LB - left bottom corner
  • LEFT_CENTER or LC - the center of the left side
  • CENTER_CENTER or CC - the center (default)

So the following piece of code for example will crop 100x100 rectangle from the top left corner of the image.

var uploader = new plupload.Uploader({
  ...
  resize: {
    width: 100,
    height: 100,
    crop: 'LEFT_TOP'
  }
});

Important point to take into account is that the portion will be cropped out without any scaling! This is important because previous versions of Plupload cropped and scaled to fit simultaneously. We decided to separate these features and fitting functionality now has a standalone sub-option - fit.

Crop and Fit

Fitting functionality obviously has no sense without Crop operation. Without Crop operation there is nothing to fit. So by itself fit sub-option, which by default is set to false, doesn't do anything. It works together with crop, that should be enabled one way or another.

On its own crop doesn't do any scaling on the portion of the image that it cuts out. And this is useful in some cases, but it's completely inapplicable when the real goal is to acquire miniature of the given image and fit it into specific dimensions. In other words lets say we want a 100 by 100 thumbnail. That's when the fit sub-option comes into play. You simply need to set it to true.

So this is how you crop 100x100 thumb of the given image:

var uploader = new plupload.Uploader({
  ...
  resize: {
    width: 100,
    height: 100,
    crop: true, // will make a center-oriented crop by default
    fit: true
  }
});

Resampling

Almost all technologies that Plupload depends on use Nearest Neighbour algorithm for their image resizing operations. This might be ok for majority of generic tasks, like generation of thumbs for example, where quality doesn't matter. But there are cases when quality matters or better to say - cases when its absence becomes too noticeable, like for example resizing of the image with lots of tiny details.

Plupload supports bilinear resampling. Here is how you enable it:

var uploader = new plupload.Uploader({
  ...
  resize: {
    width: 100,
    height: 100,
    resample: 'bilinear'
  }
});

We've left a room for more resampling algorithms, by not making resample option boolean.

Gradual Resizing

Resizing is by its nature destructive operation. Downscaling the image requires to throw some pixels away and upscaling - just opposite - coming up with non-existent pixels and addiing them to the image. Results of this fraud (basically) go more or less unnoticeable when original and resulting images are comparable in size, but as the scaling factor increases, defects become more and more obvious. Our solution to this is gradual resizing, or incremental - whatever you choose to call it. Despite of fancy name, the idea is simple - if dimensions of the original image and resulting one differ dramatically, we are going to resize it in steps and fill the gaps in pixels gradually. If resampling is enabled, we will do this even more precisely.

If you do not care or want the result as fast as possible, you can simply set multipass option to false.

Decrease quality JPEGs only

quality sub-option can be used with other resizing options or without them, since sometimes it might be required to decrease the size of the image without changing its dimensions. Hence it can be:

resize: {
  width: 100,
  height: 100,
  crop: true,
  quality: 70
}

as well as simply:

resize: {
  quality: 70
}

It is worth to mention once more that this is applicable only to JPEGs, since PNG is lossless format and simply ignores quality gradations.

Strip meta headers JPEGs only

It is normal for JPEGs to have meta headers inside: Exif, Gps, IPTC, etc. Usually you would want them to survive resizing operation and that's what happens by default. But when you do not care about Exif and such and all you need is the smallest possible file size, you might want them to get stripped and here how you do it:

resize: {
  preserve_headers: false
}

You might save some additional bytes with this. If meta headers contain Orientation tag, JPEG will be auto-rotated accordingly.

Limitations

Obviously client-side and specifically browser environment cannot be as powerful (not yet at least) as the server-side might be. So somewhere there must be a limitation on the resolution that might be handled in the browsers or their add-ons. We assume it to be 6500 by 6500 pixels (about 42MP). I say assume, because there's no way to figure out the actual top line or detect when browser (or its add-on) runs out of memory - if this happens it simply hangs (the best case). So we came up with the safe margin, where browser can still reliably operate (read - breathe) and if either side of the image is larger than that margin, Plupload will simply bail out and upload the image as is, without any tampering.

Fork me on GitHub