|
1 | 1 | /* |
2 | | - * JavaScript Load Image 1.2.1 |
| 2 | + * JavaScript Load Image 1.3 |
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 | + * |
8 | 11 | * Licensed under the MIT license: |
9 | 12 | * http://www.opensource.org/licenses/MIT |
10 | 13 | */ |
11 | 14 |
|
12 | | -/*jslint nomen: true */ |
| 15 | +/*jslint nomen: true, bitwise: true */ |
13 | 16 | /*global window, document, URL, webkitURL, Blob, File, FileReader, define */ |
14 | 17 |
|
15 | 18 | (function ($) { |
|
34 | 37 | // (Firefox 3.6) support the File API but not Blobs: |
35 | 38 | (window.File && file instanceof File)) { |
36 | 39 | url = oUrl = loadImage.createObjectURL(file); |
| 40 | + // Store the file type for resize processing: |
| 41 | + img._type = file.type; |
37 | 42 | } else { |
38 | | - url = file; |
| 43 | + callback({"type": "error"}); // this led to a broken image request in IE9: url = file; |
39 | 44 | } |
40 | 45 | if (url) { |
41 | 46 | img.src = url; |
42 | 47 | return img; |
43 | 48 | } |
44 | | - return loadImage.readFile(file, function (url) { |
45 | | - img.src = url; |
| 49 | + return loadImage.readFile(file, function (e) { |
| 50 | + var target = e.target; |
| 51 | + if (target && target.result) { |
| 52 | + img.src = target.result; |
| 53 | + } else { |
| 54 | + callback(e); |
| 55 | + } |
46 | 56 | }); |
47 | 57 | }, |
48 | 58 | // The check for URL.revokeObjectURL fixes an issue with Opera 12, |
|
51 | 61 | (window.URL && URL.revokeObjectURL && URL) || |
52 | 62 | (window.webkitURL && webkitURL); |
53 | 63 |
|
| 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; |
| 81 | + }; |
| 82 | + |
| 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; |
| 110 | + }; |
| 111 | + |
| 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; |
| 155 | + }; |
| 156 | + |
54 | 157 | // Scales the given image (img or canvas HTML element) |
55 | 158 | // using the given options. |
56 | 159 | // Returns a canvas object if the browser supports canvas |
|
66 | 169 | (options.minHeight || height) / height |
67 | 170 | ); |
68 | 171 | if (scale > 1) { |
69 | | - width = parseInt(width * scale, 10); |
70 | | - height = parseInt(height * scale, 10); |
| 172 | + width = (width * scale) << 0; |
| 173 | + height = (height * scale) << 0; |
71 | 174 | } |
72 | 175 | scale = Math.min( |
73 | 176 | (options.maxWidth || width) / width, |
74 | 177 | (options.maxHeight || height) / height |
75 | 178 | ); |
76 | 179 | if (scale < 1) { |
77 | | - width = parseInt(width * scale, 10); |
78 | | - height = parseInt(height * scale, 10); |
| 180 | + width = (width * scale) << 0; |
| 181 | + height = (height * scale) << 0; |
79 | 182 | } |
80 | 183 | if (img.getContext || (options.canvas && canvas.getContext)) { |
81 | 184 | canvas.width = width; |
82 | 185 | canvas.height = height; |
83 | | - canvas.getContext('2d') |
84 | | - .drawImage(img, 0, 0, width, height); |
| 186 | + if (img._type === 'image/jpeg') { |
| 187 | + loadImage |
| 188 | + .renderImageToCanvas(img, canvas, width, height); |
| 189 | + } else { |
| 190 | + canvas.getContext('2d') |
| 191 | + .drawImage(img, 0, 0, width, height); |
| 192 | + } |
85 | 193 | return canvas; |
86 | 194 | } |
87 | 195 | img.width = width; |
|
98 | 206 | }; |
99 | 207 |
|
100 | 208 | // Loads a given File object via FileReader interface, |
101 | | - // invokes the callback with a data url: |
| 209 | + // invokes the callback with the event object (load or error). |
| 210 | + // The result can be read via event.target.result: |
102 | 211 | loadImage.readFile = function (file, callback) { |
103 | 212 | if (window.FileReader && FileReader.prototype.readAsDataURL) { |
104 | 213 | var fileReader = new FileReader(); |
105 | | - fileReader.onload = function (e) { |
106 | | - callback(e.target.result); |
107 | | - }; |
| 214 | + fileReader.onload = fileReader.onerror = callback; |
108 | 215 | fileReader.readAsDataURL(file); |
109 | 216 | return fileReader; |
110 | 217 | } |
|
0 commit comments