jquery.fileupload-image.js 12 KB

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