5.15.0
The scaling feature allows your server to breathe a bit easier as image scaling efforts are handled client-side by Fine Uploader. If your users submit any image files that can be rendered natively by the current browser, Fine Uploader will create scaled versions and upload those as well. You can tell Fine Uploader which sizes you would like it to generate and upload. You can specify size-specific text to append to each scaled image name. The scaled image can be correctly oriented by Fine Uploader before it is sent to your server. You can also ensure only scaled images, and not the original image, are uploaded. Finally, you can ask Fine Uploader to magically insert the EXIF data from the original image into each scaled image.
Generating and uploading scaled versions of each submitted
image can be as simple as specifying an array of objects with name
and maxSize
properties to indicate the scaled image
file's name and maximum size, respectively.
By default, Fine Uploader will send the original image file, along with any scaled versions you have requested via
the scaling.sizes
option. Also, by default, all scaled versions will be correctly oriented before they
are uploaded.
You must provide a sizes
array though. For example:
var uploader = new qq.FineUploader({ ... scaling: { sizes: [ {name: "small", maxSize: 100}, {name: "medium", maxSize: 300} ] } });
The code above will result in Fine Uploader generating and uploading 2 scaled versions of each user-submitted image file. The original, along with the 2 scaled versions, will appear in the UI's file list as well. If the user submits a PNG named "image.png", that will be submitted, along with another file named "image (small).png", and "image (medium).png".
The scaled versions will be scaled proportional to the original image. In this case, the "small" version will be no more than 100px high or wide, and the "medium" version will be no more than 300px wide or high.
Notice that the two scaled images do not initially have file sizes displayed in the UI. This is due to the
fact that Fine Uploader defers generation of these scaled versions until just before the images are going to be
actually uploaded. After a scaled image has been uploaded, the client-side generated version of this image is
discarded to conserve browser memory. Calls to the getFile
API method will return the associated
original file, not the scaled version. This is due to the fact that, again, the scaled version is not kept around
any longer than necessary to conserve memory. Also, generating a scaled version is an asynchronous operation, which
would require the getFile
API method return a promise, introducing a breaking
change to the API. Once a scaled image has been generated, the UI (and upload data store) will be updated
with the generated size.
Fine Uploader ensures that a group of scaled images is always uploaded in order, smallest file first. The original file is always sent last.
To conserve bandwidth, you may only want to upload smaller, scaled versions of an original image. Simply set the
scaling.sendOriginal
option to false
. The above example would be changed to:
var uploader = new qq.FineUploader({ ... scaling: { sendOriginal: false, sizes: [ {name: "small", maxSize: 100}, {name: "medium", maxSize: 300} ] } });
If you instruct Fine Uploader to NOT send the original file, it will not be uploaded, represented in the
UI, or represented in the upload data store. Effectively, the original file will be transformed into
the specified number of scaled versions. However, it will still be accessible via any API methods
that require access to the original file for your convenience. For example, calling getFile
on a scaled image will still return the original file.
If you do not want scaled versions to be represented in Fine Uploader UI's file list, simply set the Fine Uploader
UI scaling.hideScaled
option to true
. Note that this will only ensure the scaled versions
are not displayed in the UI. They will still be uploaded and represented in the upload data store.
Since they will not be represented in the UI, this means that they cannot be deleted, canceled, or manually retried
via Fine Uploader's default UI. Failures of these scaled versions will obviously not be apparent to users by
default if you elect to hide them from the UI.
If you set the scaling.includeExif
option to true
, Fine Uploader will insert the EXIF header from the
original image into each scaled image. This option is ignored unless the original image AND the target (scaled)
image are both of type "image/jpeg".
var uploader = new qq.FineUploader({ ... scaling: { includeExif: true, sizes: [ {name: "small", maxSize: 100}, {name: "medium", maxSize: 300} ] } });
In the above example, EXIF data from the original image will be inserted into both of the scaled images.
Note that, by default, the scaled images will also be re-oriented according to the parsed Orientation tag in the
original image. If you don't want Fine Uploader to do this, you must set the scaling.orient
option
to false
.
Scaling can occur on JPEGs, BMPs, GIFs, and PNGs. TIFFs are also supported, but only in Safari. The output
type is generally limited to JPEG and PNG. If the original file type happens to be anything other than a JPEG,
the output type will default to PNG. JPEG original files will be converted to scaled JPEGs by default.
You can override this via the scaling
option, but you should probably not, unless you know
what you are doing.
Fine Uploader will send request parameters along with some scaled files to make it easy for you to connect them to the original/parent file server-side and group them together. "qqparentuuid" and "qqparentsize" parameters will be sent with each scaled image upload request. These parameters link the scaled image to the parent/original image. Note that the parent images will include a "qquuid" request parameter instead. If you are using Fine Uploader S3 or Azure, these parameters will be associated with the file in your bucket or blob container.
Fine Uploader's internal image resize code delegates to the drawImage
method on the browser's native CanvasRenderingContext2D
object.
This object is used to manipulate a <canvas>
element, which represents a submitted image File
or Blob
.
Most browsers use linear interpolation when resizing images. This can lead to extreme aliasing and moire patterns
which is a deal breaker for anyone resizing images for art/photo galleries, albums, etc.
These kinds of artifacts are impossible to remove after the fact.
If speed is most important, and precise scaled image generation is not paramount, you should continue to use Fine Uploader's
internal scaling implementation. However, if you want to generate higher quality scaled images for upload, you should
instead use a third-party library to resize submitted image files, such as pica or limby-resize. As of version 5.10 of
Fine Uploader, it is extremely easy to integrate such a plug-in into this library. In fact, Fine Uploader will continue
to properly orient the submitted image file and then pass a properly sized <canvas>
to the image scaling library of
your choice to receive the resized image file, along with the original full-sized image file drawn onto a <canvas>
for reference.
The only caveat is that, due to issues with scaling larger images in iOS, you may need to continue to use
Fine Uploader's internal scaling algorithm for that particular OS, as other third-party scaling libraries
most likely do not contain logic to handle this complex case. Luckily, that is easy to account for as well.
If you'd like to, for example, use pica to generate higher-quality scaled images, simply pull pica into your project,
and contribute a scaling.customResizer
function, like so:
scaling: { customResizer: !qq.ios() && function(resizeInfo) { return new Promise(function(resolve, reject) { pica.resizeCanvas(resizeInfo.sourceCanvas, resizeInfo.targetCanvas, {}, resolve) }) }, ... }
That's it! The above code will result in a higher-quality scaled image, and pica even pushes resizing logic off to a web worker to reduce strain on the UI thread.
Do not set the scaling.hideScaled
option to true
AND the scaling.sendOriginal
option
to false
at the same time. This will result in no files being represented in the UI for images that are scalable.
Scaled files hidden from the UI when the scaling.hideScaled
option is set to true
cannot be
canceled, manually retried, or deleted via the UI, since they are not represented in the UI.
Be very careful when specifying a value for scaling.defaultType
, or a type
property for one of your
scaling.sizes
objects. The only safe values are null
(the default), "image/jpeg", and "image/png". Other
target types may not be supported by all browsers.
Be careful if you set the validation.itemLimit
option. Each Scaled image file will count towards
this item limit.
Client-side scaling and EXIF header re-insertion operations can potentially be very resource-intensive. Please keep this in mind before you enable this feature, taking into account your user base and application goals.
iOS limits the size of a <canvas>
to about 5 megapixels. Any image larger than this will be rendered as a
blank <canvas>
. This affects scaling as Fine Uploader uses <canvas>
in part of the scaling process. To
overcome this issue, Fine Uploader will further downsample scaled images that exceed this limit. You can check to
see if such a limitation is known by examining the qq.supportedFeatures.unlimitedScaledImageSize
flag.
The scaled file names will be sent with the upload request as the qqfilename
parameter.
Be sure to read this parameter when naming your file server-side.
This feature is supported on all browsers other than IE9 and older, Android 2.4 or older, and Safari 5.1 or older. Note that Android's stock browser is also not supported, due to multiple long-standing bugs in that browser with Blobs and data URIs. Chrome on Android is supported, though.