Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

313 рядки
12 KiB

  1. /*
  2. * jQuery canvasResize plugin
  3. *
  4. * Version: 1.2.0
  5. * Date (d/m/y): 02/10/12
  6. * Update (d/m/y): 14/05/13
  7. * Original author: @gokercebeci
  8. * Licensed under the MIT license
  9. * - This plugin working with jquery.exif.js
  10. * (It's under the MPL License http://www.nihilogic.dk/licenses/mpl-license.txt)
  11. * Demo: http://ios6-image-resize.gokercebeci.com/
  12. *
  13. * - I fixed iOS6 Safari's image file rendering issue for large size image (over mega-pixel)
  14. * using few functions from https://github.com/stomita/ios-imagefile-megapixel
  15. * (detectSubsampling, )
  16. * And fixed orientation issue by edited http://blog.nihilogic.dk/2008/05/jquery-exif-data-plugin.html
  17. * Thanks, Shinichi Tomita and Jacob Seidelin
  18. */
  19. (function($) {
  20. var pluginName = 'canvasResize',
  21. methods = {
  22. newsize: function(w, h, W, H, C) {
  23. var c = C ? 'h' : '';
  24. if ((W && w > W) || (H && h > H)) {
  25. var r = w / h;
  26. if ((r >= 1 || H === 0) && W && !C) {
  27. w = W;
  28. h = (W / r) >> 0;
  29. } else if (C && r <= (W / H)) {
  30. w = W;
  31. h = (W / r) >> 0;
  32. c = 'w';
  33. } else {
  34. w = (H * r) >> 0;
  35. h = H;
  36. }
  37. }
  38. return {
  39. 'width': w,
  40. 'height': h,
  41. 'cropped': c
  42. };
  43. },
  44. dataURLtoBlob: function(data) {
  45. var mimeString = data.split(',')[0].split(':')[1].split(';')[0];
  46. var byteString = atob(data.split(',')[1]);
  47. var ab = new ArrayBuffer(byteString.length);
  48. var ia = new Uint8Array(ab);
  49. for (var i = 0; i < byteString.length; i++) {
  50. ia[i] = byteString.charCodeAt(i);
  51. }
  52. var bb = (window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder);
  53. if (bb) {
  54. // console.log('BlobBuilder');
  55. bb = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder)();
  56. bb.append(ab);
  57. return bb.getBlob(mimeString);
  58. } else {
  59. // console.log('Blob');
  60. bb = new Blob([ab], {
  61. 'type': (mimeString)
  62. });
  63. return bb;
  64. }
  65. },
  66. /**
  67. * Detect subsampling in loaded image.
  68. * In iOS, larger images than 2M pixels may be subsampled in rendering.
  69. */
  70. detectSubsampling: function(img) {
  71. var iw = img.width, ih = img.height;
  72. if (iw * ih > 1048576) { // subsampling may happen over megapixel image
  73. var canvas = document.createElement('canvas');
  74. canvas.width = canvas.height = 1;
  75. var ctx = canvas.getContext('2d');
  76. ctx.drawImage(img, -iw + 1, 0);
  77. // subsampled image becomes half smaller in rendering size.
  78. // check alpha channel value to confirm image is covering edge pixel or not.
  79. // if alpha value is 0 image is not covering, hence subsampled.
  80. return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
  81. } else {
  82. return false;
  83. }
  84. },
  85. /**
  86. * Update the orientation according to the specified rotation angle
  87. */
  88. rotate: function(orientation, angle) {
  89. var o = {
  90. // nothing
  91. 1: {90: 6, 180: 3, 270: 8},
  92. // horizontal flip
  93. 2: {90: 7, 180: 4, 270: 5},
  94. // 180 rotate left
  95. 3: {90: 8, 180: 1, 270: 6},
  96. // vertical flip
  97. 4: {90: 5, 180: 2, 270: 7},
  98. // vertical flip + 90 rotate right
  99. 5: {90: 2, 180: 7, 270: 4},
  100. // 90 rotate right
  101. 6: {90: 3, 180: 8, 270: 1},
  102. // horizontal flip + 90 rotate right
  103. 7: {90: 4, 180: 5, 270: 2},
  104. // 90 rotate left
  105. 8: {90: 1, 180: 6, 270: 3}
  106. };
  107. return o[orientation][angle] ? o[orientation][angle] : orientation;
  108. },
  109. /**
  110. * Transform canvas coordination according to specified frame size and orientation
  111. * Orientation value is from EXIF tag
  112. */
  113. transformCoordinate: function(canvas, width, height, orientation) {
  114. //console.log(width, height);
  115. switch (orientation) {
  116. case 5:
  117. case 6:
  118. case 7:
  119. case 8:
  120. canvas.width = height;
  121. canvas.height = width;
  122. break;
  123. default:
  124. canvas.width = width;
  125. canvas.height = height;
  126. }
  127. var ctx = canvas.getContext('2d');
  128. switch (orientation) {
  129. case 1:
  130. // nothing
  131. break;
  132. case 2:
  133. // horizontal flip
  134. ctx.translate(width, 0);
  135. ctx.scale(-1, 1);
  136. break;
  137. case 3:
  138. // 180 rotate left
  139. ctx.translate(width, height);
  140. ctx.rotate(Math.PI);
  141. break;
  142. case 4:
  143. // vertical flip
  144. ctx.translate(0, height);
  145. ctx.scale(1, -1);
  146. break;
  147. case 5:
  148. // vertical flip + 90 rotate right
  149. ctx.rotate(0.5 * Math.PI);
  150. ctx.scale(1, -1);
  151. break;
  152. case 6:
  153. // 90 rotate right
  154. ctx.rotate(0.5 * Math.PI);
  155. ctx.translate(0, -height);
  156. break;
  157. case 7:
  158. // horizontal flip + 90 rotate right
  159. ctx.rotate(0.5 * Math.PI);
  160. ctx.translate(width, -height);
  161. ctx.scale(-1, 1);
  162. break;
  163. case 8:
  164. // 90 rotate left
  165. ctx.rotate(-0.5 * Math.PI);
  166. ctx.translate(-width, 0);
  167. break;
  168. default:
  169. break;
  170. }
  171. },
  172. /**
  173. * Detecting vertical squash in loaded image.
  174. * Fixes a bug which squash image vertically while drawing into canvas for some images.
  175. */
  176. detectVerticalSquash: function(img, iw, ih) {
  177. var canvas = document.createElement('canvas');
  178. canvas.width = 1;
  179. canvas.height = ih;
  180. var ctx = canvas.getContext('2d');
  181. ctx.drawImage(img, 0, 0);
  182. var data = ctx.getImageData(0, 0, 1, ih).data;
  183. // search image edge pixel position in case it is squashed vertically.
  184. var sy = 0;
  185. var ey = ih;
  186. var py = ih;
  187. while (py > sy) {
  188. var alpha = data[(py - 1) * 4 + 3];
  189. if (alpha === 0) {
  190. ey = py;
  191. } else {
  192. sy = py;
  193. }
  194. py = (ey + sy) >> 1;
  195. }
  196. var ratio = py / ih;
  197. return ratio === 0 ? 1 : ratio;
  198. },
  199. callback: function(d) {
  200. return d;
  201. }
  202. },
  203. defaults = {
  204. width: 300,
  205. height: 0,
  206. crop: false,
  207. quality: 80,
  208. 'callback': methods.callback
  209. };
  210. function Plugin(file, options) {
  211. this.file = file;
  212. this.options = $.extend({}, defaults, options);
  213. this._defaults = defaults;
  214. this._name = pluginName;
  215. this.init();
  216. }
  217. Plugin.prototype = {
  218. init: function() {
  219. //this.options.init(this);
  220. var $this = this;
  221. var file = this.file;
  222. var reader = new FileReader();
  223. reader.onloadend = function(e) {
  224. var dataURL = e.target.result;
  225. var img = new Image();
  226. img.onload = function(e) {
  227. // Read Orientation Data in EXIF
  228. $(img).exifLoadFromDataURL(function() {
  229. var orientation = $(img).exif('Orientation')[0] || 1;
  230. orientation = methods.rotate(orientation, $this.options.rotate);
  231. // CW or CCW ? replace width and height
  232. var size = (orientation >= 5 && orientation <= 8)
  233. ? methods.newsize(img.height, img.width, $this.options.width, $this.options.height, $this.options.crop)
  234. : methods.newsize(img.width, img.height, $this.options.width, $this.options.height, $this.options.crop);
  235. var iw = img.width, ih = img.height;
  236. var width = size.width, height = size.height;
  237. //console.log(iw, ih, size.width, size.height, orientation);
  238. var canvas = document.createElement("canvas");
  239. var ctx = canvas.getContext("2d");
  240. ctx.save();
  241. methods.transformCoordinate(canvas, width, height, orientation);
  242. // over image size
  243. if (methods.detectSubsampling(img)) {
  244. iw /= 2;
  245. ih /= 2;
  246. }
  247. var d = 1024; // size of tiling canvas
  248. var tmpCanvas = document.createElement('canvas');
  249. tmpCanvas.width = tmpCanvas.height = d;
  250. var tmpCtx = tmpCanvas.getContext('2d');
  251. var vertSquashRatio = methods.detectVerticalSquash(img, iw, ih);
  252. var sy = 0;
  253. while (sy < ih) {
  254. var sh = sy + d > ih ? ih - sy : d;
  255. var sx = 0;
  256. while (sx < iw) {
  257. var sw = sx + d > iw ? iw - sx : d;
  258. tmpCtx.clearRect(0, 0, d, d);
  259. tmpCtx.drawImage(img, -sx, -sy);
  260. var dx = Math.floor(sx * width / iw);
  261. var dw = Math.ceil(sw * width / iw);
  262. var dy = Math.floor(sy * height / ih / vertSquashRatio);
  263. var dh = Math.ceil(sh * height / ih / vertSquashRatio);
  264. ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh);
  265. sx += d;
  266. }
  267. sy += d;
  268. }
  269. ctx.restore();
  270. tmpCanvas = tmpCtx = null;
  271. // if cropped or rotated width and height data replacing issue
  272. var newcanvas = document.createElement('canvas');
  273. newcanvas.width = size.cropped === 'h' ? height : width;
  274. newcanvas.height = size.cropped === 'w' ? width : height;
  275. var x = size.cropped === 'h' ? (height - width) * .5 : 0;
  276. var y = size.cropped === 'w' ? (width - height) * .5 : 0;
  277. newctx = newcanvas.getContext('2d');
  278. newctx.drawImage(canvas, x, y, width, height);
  279. if (file.type === "image/png") {
  280. var data = newcanvas.toDataURL(file.type);
  281. } else {
  282. var data = newcanvas.toDataURL("image/jpeg", ($this.options.quality * .01));
  283. }
  284. // CALLBACK
  285. $this.options.callback(data, width, height);
  286. });
  287. };
  288. img.src = dataURL;
  289. // =====================================================
  290. };
  291. reader.readAsDataURL(file);
  292. }
  293. };
  294. $[pluginName] = function(file, options) {
  295. if (typeof file === 'string')
  296. return methods[file](options);
  297. else
  298. new Plugin(file, options);
  299. };
  300. })(jQuery);