|
1 | 1 | /*
|
2 |
| - * JavaScript Load Image 1.3.1 |
| 2 | + * JavaScript Load Image 1.9.0 |
3 | 3 | * https://github.com/blueimp/JavaScript-Load-Image
|
4 | 4 | *
|
5 | 5 | * Copyright 2011, Sebastian Tschan
|
6 | 6 | * https://blueimp.net
|
7 | 7 | *
|
8 |
| - * iOS image scaling fixes based on |
9 |
| - * https://github.com/stomita/ios-imagefile-megapixel |
10 |
| - * |
11 | 8 | * Licensed under the MIT license:
|
12 | 9 | * http://www.opensource.org/licenses/MIT
|
13 | 10 | */
|
14 | 11 |
|
15 |
| -/*jslint nomen: true, bitwise: true */ |
16 |
| -/*global window, document, URL, webkitURL, Blob, File, FileReader, define */ |
| 12 | +/*jslint nomen: true */ |
| 13 | +/*global define, window, document, URL, webkitURL, Blob, File, FileReader */ |
17 | 14 |
|
18 | 15 | (function ($) {
|
19 | 16 | 'use strict';
|
|
30 | 27 | if (oUrl && !(options && options.noRevoke)) {
|
31 | 28 | loadImage.revokeObjectURL(oUrl);
|
32 | 29 | }
|
33 |
| - callback(loadImage.scale(img, options)); |
| 30 | + if (callback) { |
| 31 | + callback(loadImage.scale(img, options)); |
| 32 | + } |
34 | 33 | };
|
35 |
| - if ((window.Blob && file instanceof Blob) || |
36 |
| - // Files are also Blob instances, but some browsers |
37 |
| - // (Firefox 3.6) support the File API but not Blobs: |
38 |
| - (window.File && file instanceof File)) { |
| 34 | + if (loadImage.isInstanceOf('Blob', file) || |
| 35 | + // Files are also Blob instances, but some browsers |
| 36 | + // (Firefox 3.6) support the File API but not Blobs: |
| 37 | + loadImage.isInstanceOf('File', file)) { |
39 | 38 | url = oUrl = loadImage.createObjectURL(file);
|
40 | 39 | // Store the file type for resize processing:
|
41 | 40 | img._type = file.type;
|
42 |
| - } else { |
| 41 | + } else if (typeof file === 'string') { |
43 | 42 | url = file;
|
| 43 | + if (options && options.crossOrigin) { |
| 44 | + img.crossOrigin = options.crossOrigin; |
| 45 | + } |
| 46 | + } else { |
| 47 | + return false; |
44 | 48 | }
|
45 | 49 | if (url) {
|
46 | 50 | img.src = url;
|
|
51 | 55 | if (target && target.result) {
|
52 | 56 | img.src = target.result;
|
53 | 57 | } else {
|
54 |
| - callback(e); |
| 58 | + if (callback) { |
| 59 | + callback(e); |
| 60 | + } |
55 | 61 | }
|
56 | 62 | });
|
57 | 63 | },
|
|
61 | 67 | (window.URL && URL.revokeObjectURL && URL) ||
|
62 | 68 | (window.webkitURL && webkitURL);
|
63 | 69 |
|
64 |
| - // Detects subsampling in JPEG images: |
65 |
| - loadImage.detectSubsampling = function (img) { |
66 |
| - var iw = img.width, |
67 |
| - ih = img.height, |
68 |
| - canvas, |
69 |
| - ctx; |
70 |
| - if (iw * ih > 1024 * 1024) { // only consider mexapixel images |
71 |
| - canvas = document.createElement('canvas'); |
72 |
| - canvas.width = canvas.height = 1; |
73 |
| - ctx = canvas.getContext('2d'); |
74 |
| - ctx.drawImage(img, -iw + 1, 0); |
75 |
| - // subsampled image becomes half smaller in rendering size. |
76 |
| - // check alpha channel value to confirm image is covering edge pixel or not. |
77 |
| - // if alpha value is 0 image is not covering, hence subsampled. |
78 |
| - return ctx.getImageData(0, 0, 1, 1).data[3] === 0; |
79 |
| - } |
80 |
| - return false; |
| 70 | + loadImage.isInstanceOf = function (type, obj) { |
| 71 | + // Cross-frame instanceof check |
| 72 | + return Object.prototype.toString.call(obj) === '[object ' + type + ']'; |
81 | 73 | };
|
82 | 74 |
|
83 |
| - // Detects vertical squash in JPEG images: |
84 |
| - loadImage.detectVerticalSquash = function (img, ih) { |
85 |
| - var canvas = document.createElement('canvas'), |
86 |
| - ctx = canvas.getContext('2d'), |
87 |
| - data, |
88 |
| - sy, |
89 |
| - ey, |
90 |
| - py, |
91 |
| - alpha; |
92 |
| - canvas.width = 1; |
93 |
| - canvas.height = ih; |
94 |
| - ctx.drawImage(img, 0, 0); |
95 |
| - data = ctx.getImageData(0, 0, 1, ih).data; |
96 |
| - // search image edge pixel position in case it is squashed vertically: |
97 |
| - sy = 0; |
98 |
| - ey = ih; |
99 |
| - py = ih; |
100 |
| - while (py > sy) { |
101 |
| - alpha = data[(py - 1) * 4 + 3]; |
102 |
| - if (alpha === 0) { |
103 |
| - ey = py; |
104 |
| - } else { |
105 |
| - sy = py; |
106 |
| - } |
107 |
| - py = (ey + sy) >> 1; |
108 |
| - } |
109 |
| - return (py / ih) || 1; |
| 75 | + // Transform image coordinates, allows to override e.g. |
| 76 | + // the canvas orientation based on the orientation option, |
| 77 | + // gets canvas, options passed as arguments: |
| 78 | + loadImage.transformCoordinates = function () { |
| 79 | + return; |
110 | 80 | };
|
111 | 81 |
|
112 |
| - // Renders image to canvas while working around iOS image scaling bugs: |
113 |
| - // https://github.com/blueimp/JavaScript-Load-Image/issues/13 |
114 |
| - loadImage.renderImageToCanvas = function (img, canvas, width, height) { |
115 |
| - var iw = img.width, |
116 |
| - ih = img.height, |
117 |
| - ctx = canvas.getContext('2d'), |
118 |
| - vertSquashRatio, |
119 |
| - d = 1024, // size of tiling canvas |
120 |
| - tmpCanvas = document.createElement('canvas'), |
121 |
| - tmpCtx, |
122 |
| - dw, |
123 |
| - dh, |
124 |
| - dx, |
125 |
| - dy, |
126 |
| - sx, |
127 |
| - sy; |
128 |
| - ctx.save(); |
129 |
| - if (loadImage.detectSubsampling(img)) { |
130 |
| - iw /= 2; |
131 |
| - ih /= 2; |
132 |
| - } |
133 |
| - vertSquashRatio = loadImage.detectVerticalSquash(img, ih); |
134 |
| - tmpCanvas.width = tmpCanvas.height = d; |
135 |
| - tmpCtx = tmpCanvas.getContext('2d'); |
136 |
| - dw = Math.ceil(d * width / iw); |
137 |
| - dh = Math.ceil(d * height / ih / vertSquashRatio); |
138 |
| - dy = 0; |
139 |
| - sy = 0; |
140 |
| - while (sy < ih) { |
141 |
| - dx = 0; |
142 |
| - sx = 0; |
143 |
| - while (sx < iw) { |
144 |
| - tmpCtx.clearRect(0, 0, d, d); |
145 |
| - tmpCtx.drawImage(img, -sx, -sy); |
146 |
| - ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh); |
147 |
| - sx += d; |
148 |
| - dx += dw; |
149 |
| - } |
150 |
| - sy += d; |
151 |
| - dy += dh; |
152 |
| - } |
153 |
| - ctx.restore(); |
154 |
| - tmpCanvas = tmpCtx = null; |
| 82 | + // Returns transformed options, allows to override e.g. |
| 83 | + // coordinate and dimension options based on the orientation: |
| 84 | + loadImage.getTransformedOptions = function (options) { |
| 85 | + return options; |
| 86 | + }; |
| 87 | + |
| 88 | + // Canvas render method, allows to override the |
| 89 | + // rendering e.g. to work around issues on iOS: |
| 90 | + loadImage.renderImageToCanvas = function ( |
| 91 | + canvas, |
| 92 | + img, |
| 93 | + sourceX, |
| 94 | + sourceY, |
| 95 | + sourceWidth, |
| 96 | + sourceHeight, |
| 97 | + destX, |
| 98 | + destY, |
| 99 | + destWidth, |
| 100 | + destHeight |
| 101 | + ) { |
| 102 | + canvas.getContext('2d').drawImage( |
| 103 | + img, |
| 104 | + sourceX, |
| 105 | + sourceY, |
| 106 | + sourceWidth, |
| 107 | + sourceHeight, |
| 108 | + destX, |
| 109 | + destY, |
| 110 | + destWidth, |
| 111 | + destHeight |
| 112 | + ); |
| 113 | + return canvas; |
155 | 114 | };
|
156 | 115 |
|
157 |
| - // Scales the given image (img or canvas HTML element) |
| 116 | + // This method is used to determine if the target image |
| 117 | + // should be a canvas element: |
| 118 | + loadImage.hasCanvasOption = function (options) { |
| 119 | + return options.canvas || options.crop; |
| 120 | + }; |
| 121 | + |
| 122 | + // Scales and/or crops the given image (img or canvas HTML element) |
158 | 123 | // using the given options.
|
159 | 124 | // Returns a canvas object if the browser supports canvas
|
160 |
| - // and the canvas option is true or a canvas object is passed |
161 |
| - // as image, else the scaled image: |
| 125 | + // and the hasCanvasOption method returns true or a canvas |
| 126 | + // object is passed as image, else the scaled image: |
162 | 127 | loadImage.scale = function (img, options) {
|
163 | 128 | options = options || {};
|
164 | 129 | var canvas = document.createElement('canvas'),
|
165 |
| - width = img.width, |
166 |
| - height = img.height, |
167 |
| - scale = Math.max( |
168 |
| - (options.minWidth || width) / width, |
169 |
| - (options.minHeight || height) / height |
170 |
| - ); |
171 |
| - if (scale > 1) { |
172 |
| - width = Math.ceil(width * scale); |
173 |
| - height = Math.ceil(height * scale); |
174 |
| - } |
175 |
| - scale = Math.min( |
176 |
| - (options.maxWidth || width) / width, |
177 |
| - (options.maxHeight || height) / height |
178 |
| - ); |
179 |
| - if (scale < 1) { |
180 |
| - width = Math.ceil(width * scale); |
181 |
| - height = Math.ceil(height * scale); |
| 130 | + useCanvas = img.getContext || |
| 131 | + (loadImage.hasCanvasOption(options) && canvas.getContext), |
| 132 | + width = img.naturalWidth || img.width, |
| 133 | + height = img.naturalHeight || img.height, |
| 134 | + destWidth = width, |
| 135 | + destHeight = height, |
| 136 | + maxWidth, |
| 137 | + maxHeight, |
| 138 | + minWidth, |
| 139 | + minHeight, |
| 140 | + sourceWidth, |
| 141 | + sourceHeight, |
| 142 | + sourceX, |
| 143 | + sourceY, |
| 144 | + tmp, |
| 145 | + scaleUp = function () { |
| 146 | + var scale = Math.max( |
| 147 | + (minWidth || destWidth) / destWidth, |
| 148 | + (minHeight || destHeight) / destHeight |
| 149 | + ); |
| 150 | + if (scale > 1) { |
| 151 | + destWidth = Math.ceil(destWidth * scale); |
| 152 | + destHeight = Math.ceil(destHeight * scale); |
| 153 | + } |
| 154 | + }, |
| 155 | + scaleDown = function () { |
| 156 | + var scale = Math.min( |
| 157 | + (maxWidth || destWidth) / destWidth, |
| 158 | + (maxHeight || destHeight) / destHeight |
| 159 | + ); |
| 160 | + if (scale < 1) { |
| 161 | + destWidth = Math.ceil(destWidth * scale); |
| 162 | + destHeight = Math.ceil(destHeight * scale); |
| 163 | + } |
| 164 | + }; |
| 165 | + if (useCanvas) { |
| 166 | + options = loadImage.getTransformedOptions(options); |
| 167 | + sourceX = options.left || 0; |
| 168 | + sourceY = options.top || 0; |
| 169 | + if (options.sourceWidth) { |
| 170 | + sourceWidth = options.sourceWidth; |
| 171 | + if (options.right !== undefined && options.left === undefined) { |
| 172 | + sourceX = width - sourceWidth - options.right; |
| 173 | + } |
| 174 | + } else { |
| 175 | + sourceWidth = width - sourceX - (options.right || 0); |
| 176 | + } |
| 177 | + if (options.sourceHeight) { |
| 178 | + sourceHeight = options.sourceHeight; |
| 179 | + if (options.bottom !== undefined && options.top === undefined) { |
| 180 | + sourceY = height - sourceHeight - options.bottom; |
| 181 | + } |
| 182 | + } else { |
| 183 | + sourceHeight = height - sourceY - (options.bottom || 0); |
| 184 | + } |
| 185 | + destWidth = sourceWidth; |
| 186 | + destHeight = sourceHeight; |
182 | 187 | }
|
183 |
| - if (img.getContext || (options.canvas && canvas.getContext)) { |
184 |
| - canvas.width = width; |
185 |
| - canvas.height = height; |
186 |
| - if (img._type === 'image/jpeg') { |
187 |
| - loadImage |
188 |
| - .renderImageToCanvas(img, canvas, width, height); |
| 188 | + maxWidth = options.maxWidth; |
| 189 | + maxHeight = options.maxHeight; |
| 190 | + minWidth = options.minWidth; |
| 191 | + minHeight = options.minHeight; |
| 192 | + if (useCanvas && maxWidth && maxHeight && options.crop) { |
| 193 | + destWidth = maxWidth; |
| 194 | + destHeight = maxHeight; |
| 195 | + tmp = sourceWidth / sourceHeight - maxWidth / maxHeight; |
| 196 | + if (tmp < 0) { |
| 197 | + sourceHeight = maxHeight * sourceWidth / maxWidth; |
| 198 | + if (options.top === undefined && options.bottom === undefined) { |
| 199 | + sourceY = (height - sourceHeight) / 2; |
| 200 | + } |
| 201 | + } else if (tmp > 0) { |
| 202 | + sourceWidth = maxWidth * sourceHeight / maxHeight; |
| 203 | + if (options.left === undefined && options.right === undefined) { |
| 204 | + sourceX = (width - sourceWidth) / 2; |
| 205 | + } |
| 206 | + } |
| 207 | + } else { |
| 208 | + if (options.contain || options.cover) { |
| 209 | + minWidth = maxWidth = maxWidth || minWidth; |
| 210 | + minHeight = maxHeight = maxHeight || minHeight; |
| 211 | + } |
| 212 | + if (options.cover) { |
| 213 | + scaleDown(); |
| 214 | + scaleUp(); |
189 | 215 | } else {
|
190 |
| - canvas.getContext('2d') |
191 |
| - .drawImage(img, 0, 0, width, height); |
| 216 | + scaleUp(); |
| 217 | + scaleDown(); |
192 | 218 | }
|
193 |
| - return canvas; |
194 | 219 | }
|
195 |
| - img.width = width; |
196 |
| - img.height = height; |
| 220 | + if (useCanvas) { |
| 221 | + canvas.width = destWidth; |
| 222 | + canvas.height = destHeight; |
| 223 | + loadImage.transformCoordinates( |
| 224 | + canvas, |
| 225 | + options |
| 226 | + ); |
| 227 | + return loadImage.renderImageToCanvas( |
| 228 | + canvas, |
| 229 | + img, |
| 230 | + sourceX, |
| 231 | + sourceY, |
| 232 | + sourceWidth, |
| 233 | + sourceHeight, |
| 234 | + 0, |
| 235 | + 0, |
| 236 | + destWidth, |
| 237 | + destHeight |
| 238 | + ); |
| 239 | + } |
| 240 | + img.width = destWidth; |
| 241 | + img.height = destHeight; |
197 | 242 | return img;
|
198 | 243 | };
|
199 | 244 |
|
|
208 | 253 | // Loads a given File object via FileReader interface,
|
209 | 254 | // invokes the callback with the event object (load or error).
|
210 | 255 | // The result can be read via event.target.result:
|
211 |
| - loadImage.readFile = function (file, callback) { |
212 |
| - if (window.FileReader && FileReader.prototype.readAsDataURL) { |
| 256 | + loadImage.readFile = function (file, callback, method) { |
| 257 | + if (window.FileReader) { |
213 | 258 | var fileReader = new FileReader();
|
214 | 259 | fileReader.onload = fileReader.onerror = callback;
|
215 |
| - fileReader.readAsDataURL(file); |
216 |
| - return fileReader; |
| 260 | + method = method || 'readAsDataURL'; |
| 261 | + if (fileReader[method]) { |
| 262 | + fileReader[method](file); |
| 263 | + return fileReader; |
| 264 | + } |
217 | 265 | }
|
218 | 266 | return false;
|
219 | 267 | };
|
|
0 commit comments