2 * jQuery File Upload Image Preview & Resize Plugin
3 * https://github.com/blueimp/jQuery-File-Upload
5 * Copyright 2013, Sebastian Tschan
8 * Licensed under the MIT license:
9 * https://opensource.org/licenses/MIT
12 /* global define, require */
16 if (typeof define === 'function' && define.amd) {
17 // Register as an anonymous AMD module:
24 'load-image-orientation',
26 './jquery.fileupload-process'
28 } else if (typeof exports === 'object') {
32 require('blueimp-load-image/js/load-image'),
33 require('blueimp-load-image/js/load-image-meta'),
34 require('blueimp-load-image/js/load-image-scale'),
35 require('blueimp-load-image/js/load-image-exif'),
36 require('blueimp-load-image/js/load-image-orientation'),
37 require('blueimp-canvas-to-blob'),
38 require('./jquery.fileupload-process')
42 factory(window.jQuery, window.loadImage);
44 })(function ($, loadImage) {
47 // Prepend to the default processQueue:
48 $.blueimp.fileupload.prototype.options.processQueue.unshift(
50 action: 'loadImageMetaData',
52 disableImageHead: '@',
53 disableMetaDataParsers: '@',
55 disableExifOffsets: '@',
59 disableIptcOffsets: '@',
62 disabled: '@disableImageMetaDataLoad'
66 // Use the action as prefix for the "@" options:
71 disabled: '@disableImageLoad'
74 action: 'resizeImage',
75 // Use "image" as prefix for the "@" options:
84 disabled: '@disableImageResize',
85 imageSmoothingQuality: '@imageSmoothingQuality'
89 quality: '@imageQuality',
91 disabled: '@disableImageResize'
94 action: 'saveImageMetaData',
95 disabled: '@disableImageMetaDataSave'
98 action: 'resizeImage',
99 // Use "preview" as prefix for the "@" options:
109 disabled: '@disableImagePreview'
113 name: '@imagePreviewName',
114 disabled: '@disableImagePreview'
117 action: 'deleteImageReferences',
118 disabled: '@disableImageReferencesDeletion'
122 // The File Upload Resize plugin extends the fileupload widget
123 // with image resize functionality:
124 $.widget('blueimp.fileupload', $.blueimp.fileupload, {
126 // The regular expression for the types of images to load:
127 // matched against the file type:
128 loadImageFileTypes: /^image\/(gif|jpeg|png|svg\+xml)$/,
129 // The maximum file size of images to load:
130 loadImageMaxFileSize: 10000000, // 10MB
131 // The maximum width of resized images:
133 // The maximum height of resized images:
134 imageMaxHeight: 1080,
135 // Defines the image orientation (1-8) or takes the orientation
136 // value from Exif data if set to true:
137 imageOrientation: true,
138 // Define if resized images should be cropped or only scaled:
140 // Disable the resize image functionality by default:
141 disableImageResize: true,
142 // The maximum width of the preview images:
144 // The maximum height of the preview images:
145 previewMaxHeight: 80,
146 // Defines the preview orientation (1-8) or takes the orientation
147 // value from Exif data if set to true:
148 previewOrientation: true,
149 // Create the preview using the Exif data thumbnail:
150 previewThumbnail: true,
151 // Define if preview images should be cropped or only scaled:
153 // Define if preview images should be resized as canvas elements:
158 // Loads the image given via data.files and data.index
159 // as img element, if the browser supports the File API.
160 // Accepts the options fileTypes (regular expression)
161 // and maxFileSize (integer) to limit the files to load:
162 loadImage: function (data, options) {
163 if (options.disabled) {
167 file = data.files[data.index],
168 // eslint-disable-next-line new-cap
171 ($.type(options.maxFileSize) === 'number' &&
172 file.size > options.maxFileSize) ||
173 (options.fileTypes && !options.fileTypes.test(file.type)) ||
180 dfd.resolveWith(that, [data]);
187 return dfd.promise();
190 // Resizes the image given as data.canvas or data.img
191 // and updates data.canvas or data.img with the resized image.
192 // Also stores the resized image as preview property.
193 // Accepts the options maxWidth, maxHeight, minWidth,
194 // minHeight, canvas and crop:
195 resizeImage: function (data, options) {
196 if (options.disabled || !(data.canvas || data.img)) {
199 // eslint-disable-next-line no-param-reassign
200 options = $.extend({ canvas: true }, options);
202 // eslint-disable-next-line new-cap
204 img = (options.canvas && data.canvas) || data.img,
205 resolve = function (newImg) {
208 (newImg.width !== img.width ||
209 newImg.height !== img.height ||
212 data[newImg.getContext ? 'canvas' : 'img'] = newImg;
214 data.preview = newImg;
215 dfd.resolveWith(that, [data]);
219 if (data.exif && options.thumbnail) {
220 thumbnail = data.exif.get('Thumbnail');
221 thumbnailBlob = thumbnail && thumbnail.get('Blob');
223 options.orientation = data.exif.get('Orientation');
224 loadImage(thumbnailBlob, resolve, options);
225 return dfd.promise();
228 if (data.orientation) {
229 // Prevent orienting the same image twice:
230 delete options.orientation;
232 data.orientation = options.orientation || loadImage.orientation;
235 resolve(loadImage.scale(img, options, data));
236 return dfd.promise();
241 // Saves the processed image given as data.canvas
242 // inplace at data.index of data.files:
243 saveImage: function (data, options) {
244 if (!data.canvas || options.disabled) {
248 file = data.files[data.index],
249 // eslint-disable-next-line new-cap
251 if (data.canvas.toBlob) {
255 if (file.type === blob.type) {
256 blob.name = file.name;
257 } else if (file.name) {
258 blob.name = file.name.replace(
260 '.' + blob.type.substr(6)
264 // Don't restore invalid meta data:
265 if (file.type !== blob.type) {
266 delete data.imageHead;
268 // Store the created blob at the position
269 // of the original file in the files list:
270 data.files[data.index] = blob;
271 dfd.resolveWith(that, [data]);
273 options.type || file.type,
279 return dfd.promise();
282 loadImageMetaData: function (data, options) {
283 if (options.disabled) {
287 // eslint-disable-next-line new-cap
289 loadImage.parseMetaData(
290 data.files[data.index],
292 $.extend(data, result);
293 dfd.resolveWith(that, [data]);
297 return dfd.promise();
300 saveImageMetaData: function (data, options) {
305 data.canvas.toBlob &&
312 file = data.files[data.index],
313 // eslint-disable-next-line new-cap
315 if (data.orientation === true && data.exifOffsets) {
316 // Reset Exif Orientation data:
317 loadImage.writeExifData(data.imageHead, data, 'Orientation', 1);
319 loadImage.replaceHead(file, data.imageHead, function (blob) {
320 blob.name = file.name;
321 data.files[data.index] = blob;
322 dfd.resolveWith(that, [data]);
324 return dfd.promise();
327 // Sets the resized version of the image as a property of the
328 // file object, must be called after "saveImage":
329 setImage: function (data, options) {
330 if (data.preview && !options.disabled) {
331 data.files[data.index][options.name || 'preview'] = data.preview;
336 deleteImageReferences: function (data, options) {
337 if (!options.disabled) {
341 delete data.imageHead;