/js/jquery.fileupload-image.js

https://github.com/chrissbarnett/jQuery-File-Upload · JavaScript · 313 lines · 242 code · 16 blank · 55 comment · 40 complexity · bea0fe82a056bf6bbc9a07fbdfb9fd58 MD5 · raw file

  1. /*
  2. * jQuery File Upload Image Preview & Resize Plugin 1.7.2
  3. * https://github.com/blueimp/jQuery-File-Upload
  4. *
  5. * Copyright 2013, Sebastian Tschan
  6. * https://blueimp.net
  7. *
  8. * Licensed under the MIT license:
  9. * http://www.opensource.org/licenses/MIT
  10. */
  11. /* jshint nomen:false */
  12. /* global define, window, Blob */
  13. (function (factory) {
  14. 'use strict';
  15. if (typeof define === 'function' && define.amd) {
  16. // Register as an anonymous AMD module:
  17. define([
  18. 'jquery',
  19. 'load-image',
  20. 'load-image-meta',
  21. 'load-image-exif',
  22. 'load-image-ios',
  23. 'canvas-to-blob',
  24. './jquery.fileupload-process'
  25. ], factory);
  26. } else {
  27. // Browser globals:
  28. factory(
  29. window.jQuery,
  30. window.loadImage
  31. );
  32. }
  33. }(function ($, loadImage) {
  34. 'use strict';
  35. // Prepend to the default processQueue:
  36. $.blueimp.fileupload.prototype.options.processQueue.unshift(
  37. {
  38. action: 'loadImageMetaData',
  39. disableImageHead: '@',
  40. disableExif: '@',
  41. disableExifThumbnail: '@',
  42. disableExifSub: '@',
  43. disableExifGps: '@',
  44. disabled: '@disableImageMetaDataLoad'
  45. },
  46. {
  47. action: 'loadImage',
  48. // Use the action as prefix for the "@" options:
  49. prefix: true,
  50. fileTypes: '@',
  51. maxFileSize: '@',
  52. noRevoke: '@',
  53. disabled: '@disableImageLoad'
  54. },
  55. {
  56. action: 'resizeImage',
  57. // Use "image" as prefix for the "@" options:
  58. prefix: 'image',
  59. maxWidth: '@',
  60. maxHeight: '@',
  61. minWidth: '@',
  62. minHeight: '@',
  63. crop: '@',
  64. orientation: '@',
  65. forceResize: '@',
  66. disabled: '@disableImageResize'
  67. },
  68. {
  69. action: 'saveImage',
  70. quality: '@imageQuality',
  71. type: '@imageType',
  72. disabled: '@disableImageResize'
  73. },
  74. {
  75. action: 'saveImageMetaData',
  76. disabled: '@disableImageMetaDataSave'
  77. },
  78. {
  79. action: 'resizeImage',
  80. // Use "preview" as prefix for the "@" options:
  81. prefix: 'preview',
  82. maxWidth: '@',
  83. maxHeight: '@',
  84. minWidth: '@',
  85. minHeight: '@',
  86. crop: '@',
  87. orientation: '@',
  88. thumbnail: '@',
  89. canvas: '@',
  90. disabled: '@disableImagePreview'
  91. },
  92. {
  93. action: 'setImage',
  94. name: '@imagePreviewName',
  95. disabled: '@disableImagePreview'
  96. },
  97. {
  98. action: 'deleteImageReferences',
  99. disabled: '@disableImageReferencesDeletion'
  100. }
  101. );
  102. // The File Upload Resize plugin extends the fileupload widget
  103. // with image resize functionality:
  104. $.widget('blueimp.fileupload', $.blueimp.fileupload, {
  105. options: {
  106. // The regular expression for the types of images to load:
  107. // matched against the file type:
  108. loadImageFileTypes: /^image\/(gif|jpeg|png|svg\+xml)$/,
  109. // The maximum file size of images to load:
  110. loadImageMaxFileSize: 10000000, // 10MB
  111. // The maximum width of resized images:
  112. imageMaxWidth: 1920,
  113. // The maximum height of resized images:
  114. imageMaxHeight: 1080,
  115. // Defines the image orientation (1-8) or takes the orientation
  116. // value from Exif data if set to true:
  117. imageOrientation: false,
  118. // Define if resized images should be cropped or only scaled:
  119. imageCrop: false,
  120. // Disable the resize image functionality by default:
  121. disableImageResize: true,
  122. // The maximum width of the preview images:
  123. previewMaxWidth: 80,
  124. // The maximum height of the preview images:
  125. previewMaxHeight: 80,
  126. // Defines the preview orientation (1-8) or takes the orientation
  127. // value from Exif data if set to true:
  128. previewOrientation: true,
  129. // Create the preview using the Exif data thumbnail:
  130. previewThumbnail: true,
  131. // Define if preview images should be cropped or only scaled:
  132. previewCrop: false,
  133. // Define if preview images should be resized as canvas elements:
  134. previewCanvas: true
  135. },
  136. processActions: {
  137. // Loads the image given via data.files and data.index
  138. // as img element, if the browser supports the File API.
  139. // Accepts the options fileTypes (regular expression)
  140. // and maxFileSize (integer) to limit the files to load:
  141. loadImage: function (data, options) {
  142. if (options.disabled) {
  143. return data;
  144. }
  145. var that = this,
  146. file = data.files[data.index],
  147. dfd = $.Deferred();
  148. if (($.type(options.maxFileSize) === 'number' &&
  149. file.size > options.maxFileSize) ||
  150. (options.fileTypes && !options.fileTypes.test(file.type)) || !loadImage(
  151. file,
  152. function (img) {
  153. if (img.src) {
  154. data.img = img;
  155. }
  156. dfd.resolveWith(that, [data]);
  157. },
  158. options
  159. )) {
  160. return data;
  161. }
  162. return dfd.promise();
  163. },
  164. // Resizes the image given as data.canvas or data.img
  165. // and updates data.canvas or data.img with the resized image.
  166. // Also stores the resized image as preview property.
  167. // Accepts the options maxWidth, maxHeight, minWidth,
  168. // minHeight, canvas and crop:
  169. resizeImage: function (data, options) {
  170. if (options.disabled || !(data.canvas || data.img)) {
  171. return data;
  172. }
  173. options = $.extend({canvas: true}, options);
  174. var that = this,
  175. dfd = $.Deferred(),
  176. img = (options.canvas && data.canvas) || data.img,
  177. resolve = function (newImg) {
  178. if (newImg && (newImg.width !== img.width ||
  179. newImg.height !== img.height ||
  180. options.forceResize)) {
  181. data[newImg.getContext ? 'canvas' : 'img'] = newImg;
  182. }
  183. data.preview = newImg;
  184. dfd.resolveWith(that, [data]);
  185. },
  186. thumbnail;
  187. if (data.exif) {
  188. if (options.orientation === true) {
  189. options.orientation = data.exif.get('Orientation');
  190. }
  191. if (options.thumbnail) {
  192. thumbnail = data.exif.get('Thumbnail');
  193. if (thumbnail) {
  194. loadImage(thumbnail, resolve, options);
  195. return dfd.promise();
  196. }
  197. }
  198. // Prevent orienting the same image twice:
  199. if (data.orientation) {
  200. delete options.orientation;
  201. } else {
  202. data.orientation = options.orientation;
  203. }
  204. }
  205. if (img) {
  206. resolve(loadImage.scale(img, options));
  207. return dfd.promise();
  208. }
  209. return data;
  210. },
  211. // Saves the processed image given as data.canvas
  212. // inplace at data.index of data.files:
  213. saveImage: function (data, options) {
  214. if (!data.canvas || options.disabled) {
  215. return data;
  216. }
  217. var that = this,
  218. file = data.files[data.index],
  219. dfd = $.Deferred();
  220. if (data.canvas.toBlob) {
  221. data.canvas.toBlob(
  222. function (blob) {
  223. if (!blob.name) {
  224. if (file.type === blob.type) {
  225. blob.name = file.name;
  226. } else if (file.name) {
  227. blob.name = file.name.replace(
  228. /\..+$/,
  229. '.' + blob.type.substr(6)
  230. );
  231. }
  232. }
  233. // Don't restore invalid meta data:
  234. if (file.type !== blob.type) {
  235. delete data.imageHead;
  236. }
  237. // Store the created blob at the position
  238. // of the original file in the files list:
  239. data.files[data.index] = blob;
  240. dfd.resolveWith(that, [data]);
  241. },
  242. options.type || file.type,
  243. options.quality
  244. );
  245. } else {
  246. return data;
  247. }
  248. return dfd.promise();
  249. },
  250. loadImageMetaData: function (data, options) {
  251. if (options.disabled) {
  252. return data;
  253. }
  254. var that = this,
  255. dfd = $.Deferred();
  256. loadImage.parseMetaData(data.files[data.index], function (result) {
  257. $.extend(data, result);
  258. dfd.resolveWith(that, [data]);
  259. }, options);
  260. return dfd.promise();
  261. },
  262. saveImageMetaData: function (data, options) {
  263. if (!(data.imageHead && data.canvas &&
  264. data.canvas.toBlob && !options.disabled)) {
  265. return data;
  266. }
  267. var file = data.files[data.index],
  268. blob = new Blob([
  269. data.imageHead,
  270. // Resized images always have a head size of 20 bytes,
  271. // including the JPEG marker and a minimal JFIF header:
  272. this._blobSlice.call(file, 20)
  273. ], {type: file.type});
  274. blob.name = file.name;
  275. data.files[data.index] = blob;
  276. return data;
  277. },
  278. // Sets the resized version of the image as a property of the
  279. // file object, must be called after "saveImage":
  280. setImage: function (data, options) {
  281. if (data.preview && !options.disabled) {
  282. data.files[data.index][options.name || 'preview'] = data.preview;
  283. }
  284. return data;
  285. },
  286. deleteImageReferences: function (data, options) {
  287. if (!options.disabled) {
  288. delete data.img;
  289. delete data.canvas;
  290. delete data.preview;
  291. delete data.imageHead;
  292. }
  293. return data;
  294. }
  295. }
  296. });
  297. }));