|
1 | 1 | /* |
2 | | - * JavaScript Load Image 1.4.1 |
| 2 | + * JavaScript Load Image 1.5 |
3 | 3 | * https://github.com/blueimp/JavaScript-Load-Image |
4 | 4 | * |
5 | 5 | * Copyright 2011, Sebastian Tschan |
|
77 | 77 |
|
78 | 78 | // Detects subsampling in JPEG images: |
79 | 79 | loadImage.detectSubsampling = function (img) { |
80 | | - var iw = img.width, |
81 | | - ih = img.height, |
82 | | - canvas, |
83 | | - ctx; |
84 | | - if (iw * ih > 1024 * 1024) { // only consider mexapixel images |
| 80 | + var canvas, |
| 81 | + context; |
| 82 | + if (img.width * img.height > 1024 * 1024) { // only consider mexapixel images |
85 | 83 | canvas = document.createElement('canvas'); |
86 | 84 | canvas.width = canvas.height = 1; |
87 | | - ctx = canvas.getContext('2d'); |
88 | | - ctx.drawImage(img, -iw + 1, 0); |
| 85 | + context = canvas.getContext('2d'); |
| 86 | + context.drawImage(img, -img.width + 1, 0); |
89 | 87 | // subsampled image becomes half smaller in rendering size. |
90 | 88 | // check alpha channel value to confirm image is covering edge pixel or not. |
91 | 89 | // if alpha value is 0 image is not covering, hence subsampled. |
92 | | - return ctx.getImageData(0, 0, 1, 1).data[3] === 0; |
| 90 | + return context.getImageData(0, 0, 1, 1).data[3] === 0; |
93 | 91 | } |
94 | 92 | return false; |
95 | 93 | }; |
96 | 94 |
|
97 | 95 | // Detects vertical squash in JPEG images: |
98 | | - loadImage.detectVerticalSquash = function (img, ih) { |
| 96 | + loadImage.detectVerticalSquash = function (img, correctedHeight) { |
99 | 97 | var canvas = document.createElement('canvas'), |
100 | | - ctx = canvas.getContext('2d'), |
| 98 | + context = canvas.getContext('2d'), |
101 | 99 | data, |
102 | 100 | sy, |
103 | 101 | ey, |
104 | 102 | py, |
105 | 103 | alpha; |
106 | 104 | canvas.width = 1; |
107 | | - canvas.height = ih; |
108 | | - ctx.drawImage(img, 0, 0); |
109 | | - data = ctx.getImageData(0, 0, 1, ih).data; |
| 105 | + canvas.height = correctedHeight; |
| 106 | + context.drawImage(img, 0, 0); |
| 107 | + data = context.getImageData(0, 0, 1, correctedHeight).data; |
110 | 108 | // search image edge pixel position in case it is squashed vertically: |
111 | 109 | sy = 0; |
112 | | - ey = ih; |
113 | | - py = ih; |
| 110 | + ey = correctedHeight; |
| 111 | + py = correctedHeight; |
114 | 112 | while (py > sy) { |
115 | 113 | alpha = data[(py - 1) * 4 + 3]; |
116 | 114 | if (alpha === 0) { |
|
120 | 118 | } |
121 | 119 | py = (ey + sy) >> 1; |
122 | 120 | } |
123 | | - return (py / ih) || 1; |
| 121 | + return (py / correctedHeight) || 1; |
124 | 122 | }; |
125 | 123 |
|
126 | 124 | // Renders image to canvas while working around iOS image scaling bugs: |
127 | 125 | // https://github.com/blueimp/JavaScript-Load-Image/issues/13 |
128 | | - loadImage.renderImageToCanvas = function (img, canvas, width, height) { |
129 | | - var iw = img.width, |
130 | | - ih = img.height, |
131 | | - ctx = canvas.getContext('2d'), |
132 | | - vertSquashRatio, |
133 | | - d = 1024, // size of tiling canvas |
| 126 | + loadImage.renderImageToCanvas = function ( |
| 127 | + canvas, |
| 128 | + img, |
| 129 | + sourceX, |
| 130 | + sourceY, |
| 131 | + sourceWidth, |
| 132 | + sourceHeight, |
| 133 | + destX, |
| 134 | + destY, |
| 135 | + destWidth, |
| 136 | + destHeight |
| 137 | + ) { |
| 138 | + var context = canvas.getContext('2d'), |
134 | 139 | tmpCanvas = document.createElement('canvas'), |
135 | | - tmpCtx, |
136 | | - dw, |
137 | | - dh, |
138 | | - dx, |
139 | | - dy, |
140 | | - sx, |
141 | | - sy; |
142 | | - ctx.save(); |
| 140 | + tileSize = tmpCanvas.width = tmpCanvas.height = 1024, |
| 141 | + tmpContext = tmpCanvas.getContext('2d'), |
| 142 | + vertSquashRatio, |
| 143 | + tileX, |
| 144 | + tileY; |
| 145 | + context.save(); |
143 | 146 | if (loadImage.detectSubsampling(img)) { |
144 | | - iw /= 2; |
145 | | - ih /= 2; |
| 147 | + sourceWidth /= 2; |
| 148 | + sourceHeight /= 2; |
146 | 149 | } |
147 | | - vertSquashRatio = loadImage.detectVerticalSquash(img, ih); |
148 | | - tmpCanvas.width = tmpCanvas.height = d; |
149 | | - tmpCtx = tmpCanvas.getContext('2d'); |
150 | | - dw = Math.ceil(d * width / iw); |
151 | | - dh = Math.ceil(d * height / ih / vertSquashRatio); |
152 | | - dy = 0; |
153 | | - sy = 0; |
154 | | - while (sy < ih) { |
155 | | - dx = 0; |
156 | | - sx = 0; |
157 | | - while (sx < iw) { |
158 | | - tmpCtx.clearRect(0, 0, d, d); |
159 | | - tmpCtx.drawImage(img, -sx, -sy); |
160 | | - ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh); |
161 | | - sx += d; |
162 | | - dx += dw; |
| 150 | + vertSquashRatio = loadImage.detectVerticalSquash(img, sourceHeight); |
| 151 | + destWidth = Math.ceil(tileSize * destWidth / sourceWidth); |
| 152 | + destHeight = Math.ceil( |
| 153 | + tileSize * destHeight / sourceHeight / vertSquashRatio |
| 154 | + ); |
| 155 | + destY = 0; |
| 156 | + tileY = 0; |
| 157 | + while (tileY < sourceHeight) { |
| 158 | + destX = 0; |
| 159 | + tileX = 0; |
| 160 | + while (tileX < sourceWidth) { |
| 161 | + tmpContext.clearRect(0, 0, tileSize, tileSize); |
| 162 | + tmpContext.drawImage( |
| 163 | + img, |
| 164 | + sourceX, |
| 165 | + sourceY, |
| 166 | + sourceWidth, |
| 167 | + sourceHeight, |
| 168 | + -tileX, |
| 169 | + -tileY, |
| 170 | + sourceWidth, |
| 171 | + sourceHeight |
| 172 | + ); |
| 173 | + context.drawImage( |
| 174 | + tmpCanvas, |
| 175 | + 0, |
| 176 | + 0, |
| 177 | + tileSize, |
| 178 | + tileSize, |
| 179 | + destX, |
| 180 | + destY, |
| 181 | + destWidth, |
| 182 | + destHeight |
| 183 | + ); |
| 184 | + tileX += tileSize; |
| 185 | + destX += destWidth; |
163 | 186 | } |
164 | | - sy += d; |
165 | | - dy += dh; |
| 187 | + tileY += tileSize; |
| 188 | + destY += destHeight; |
166 | 189 | } |
167 | | - ctx.restore(); |
168 | | - tmpCanvas = tmpCtx = null; |
| 190 | + context.restore(); |
169 | 191 | }; |
170 | 192 |
|
171 | 193 | // Scales the given image (img or canvas HTML element) |
172 | 194 | // using the given options. |
173 | 195 | // Returns a canvas object if the browser supports canvas |
174 | | - // and the canvas option is true or a canvas object is passed |
175 | | - // as image, else the scaled image: |
| 196 | + // and the canvas or crop option is true or a canvas object |
| 197 | + // is passed as image, else the scaled image: |
176 | 198 | loadImage.scale = function (img, options) { |
177 | 199 | options = options || {}; |
178 | 200 | var canvas = document.createElement('canvas'), |
| 201 | + useCanvas = img.getContext || |
| 202 | + ((options.canvas || options.crop) && canvas.getContext), |
179 | 203 | width = img.width, |
180 | 204 | height = img.height, |
| 205 | + maxWidth = options.maxWidth, |
| 206 | + maxHeight = options.maxHeight, |
| 207 | + sourceWidth = width, |
| 208 | + sourceHeight = height, |
| 209 | + sourceX = 0, |
| 210 | + sourceY = 0, |
| 211 | + destX = 0, |
| 212 | + destY = 0, |
| 213 | + destWidth, |
| 214 | + destHeight, |
| 215 | + scale; |
| 216 | + if (useCanvas && maxWidth && maxHeight && options.crop) { |
| 217 | + destWidth = maxWidth; |
| 218 | + destHeight = maxHeight; |
| 219 | + if (width / height < maxWidth / maxHeight) { |
| 220 | + sourceHeight = maxHeight * width / maxWidth; |
| 221 | + sourceY = (height - sourceHeight) / 2; |
| 222 | + } else { |
| 223 | + sourceWidth = maxWidth * height / maxHeight; |
| 224 | + sourceX = (width - sourceWidth) / 2; |
| 225 | + } |
| 226 | + } else { |
| 227 | + destWidth = width; |
| 228 | + destHeight = height; |
181 | 229 | scale = Math.max( |
182 | | - (options.minWidth || width) / width, |
183 | | - (options.minHeight || height) / height |
| 230 | + (options.minWidth || destWidth) / destWidth, |
| 231 | + (options.minHeight || destHeight) / destHeight |
184 | 232 | ); |
185 | | - if (scale > 1) { |
186 | | - width = Math.ceil(width * scale); |
187 | | - height = Math.ceil(height * scale); |
188 | | - } |
189 | | - scale = Math.min( |
190 | | - (options.maxWidth || width) / width, |
191 | | - (options.maxHeight || height) / height |
192 | | - ); |
193 | | - if (scale < 1) { |
194 | | - width = Math.ceil(width * scale); |
195 | | - height = Math.ceil(height * scale); |
| 233 | + if (scale > 1) { |
| 234 | + destWidth = Math.ceil(destWidth * scale); |
| 235 | + destHeight = Math.ceil(destHeight * scale); |
| 236 | + } |
| 237 | + scale = Math.min( |
| 238 | + (maxWidth || destWidth) / destWidth, |
| 239 | + (maxHeight || destHeight) / destHeight |
| 240 | + ); |
| 241 | + if (scale < 1) { |
| 242 | + destWidth = Math.ceil(destWidth * scale); |
| 243 | + destHeight = Math.ceil(destHeight * scale); |
| 244 | + } |
196 | 245 | } |
197 | | - if (img.getContext || (options.canvas && canvas.getContext)) { |
198 | | - canvas.width = width; |
199 | | - canvas.height = height; |
| 246 | + if (useCanvas) { |
| 247 | + canvas.width = destWidth; |
| 248 | + canvas.height = destHeight; |
200 | 249 | if (img._type === 'image/jpeg') { |
201 | | - loadImage |
202 | | - .renderImageToCanvas(img, canvas, width, height); |
| 250 | + loadImage.renderImageToCanvas( |
| 251 | + canvas, |
| 252 | + img, |
| 253 | + sourceX, |
| 254 | + sourceY, |
| 255 | + sourceWidth, |
| 256 | + sourceHeight, |
| 257 | + destX, |
| 258 | + destY, |
| 259 | + destWidth, |
| 260 | + destHeight |
| 261 | + ); |
203 | 262 | } else { |
204 | | - canvas.getContext('2d') |
205 | | - .drawImage(img, 0, 0, width, height); |
| 263 | + canvas.getContext('2d').drawImage( |
| 264 | + img, |
| 265 | + sourceX, |
| 266 | + sourceY, |
| 267 | + sourceWidth, |
| 268 | + sourceHeight, |
| 269 | + destX, |
| 270 | + destY, |
| 271 | + destWidth, |
| 272 | + destHeight |
| 273 | + ); |
206 | 274 | } |
207 | 275 | return canvas; |
208 | 276 | } |
209 | | - img.width = width; |
210 | | - img.height = height; |
| 277 | + img.width = destWidth; |
| 278 | + img.height = destHeight; |
211 | 279 | return img; |
212 | 280 | }; |
213 | 281 |
|
|
0 commit comments