jquery.fileupload-image.js 11 KB

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