jquery.fileupload-image.js 12 KB

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