jquery.fileupload-image.js 12 KB

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