jquery.fileupload-image.js 11 KB

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