|
9 | 9 | * https://opensource.org/licenses/MIT |
10 | 10 | */ |
11 | 11 |
|
12 | | -/* global define, module, Promise, webkitURL */ |
| 12 | +/* global define, module, Promise */ |
13 | 13 |
|
14 | 14 | ;(function ($) { |
15 | 15 | 'use strict' |
16 | 16 |
|
| 17 | + var urlAPI = $.URL || $.webkitURL |
| 18 | + |
| 19 | + /** |
| 20 | + * Creates an object URL for a given File object. |
| 21 | + * |
| 22 | + * @param {Blob} blob Blob object |
| 23 | + * @returns {string|boolean} Returns object URL if API exists, else false. |
| 24 | + */ |
| 25 | + function createObjectURL(blob) { |
| 26 | + return urlAPI ? urlAPI.createObjectURL(blob) : false |
| 27 | + } |
| 28 | + |
| 29 | + /** |
| 30 | + * Revokes a given object URL. |
| 31 | + * |
| 32 | + * @param {string} url Blob object URL |
| 33 | + * @returns {undefined|boolean} Returns undefined if API exists, else false. |
| 34 | + */ |
| 35 | + function revokeObjectURL(url) { |
| 36 | + return urlAPI ? urlAPI.revokeObjectURL(url) : false |
| 37 | + } |
| 38 | + |
| 39 | + /** |
| 40 | + * Helper function to revoke an object URL |
| 41 | + * |
| 42 | + * @param {string} url Blob Object URL |
| 43 | + * @param {object} [options] Options object |
| 44 | + */ |
| 45 | + function revokeHelper(url, options) { |
| 46 | + if (url && url.slice(0, 5) === 'blob:' && !(options && options.noRevoke)) { |
| 47 | + revokeObjectURL(url) |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + /** |
| 52 | + * Loads a given File object via FileReader interface. |
| 53 | + * |
| 54 | + * @param {Blob} file Blob object |
| 55 | + * @param {Function} onload Load event callback |
| 56 | + * @param {Function} [onerror] Error/Abort event callback |
| 57 | + * @param {string} [method=readAsDataURL] FileReader method |
| 58 | + * @returns {FileReader|boolean} Returns FileReader if API exists, else false. |
| 59 | + */ |
| 60 | + function readFile(file, onload, onerror, method) { |
| 61 | + if (!$.FileReader) return false |
| 62 | + var reader = new FileReader() |
| 63 | + reader.onload = function () { |
| 64 | + onload.call(reader, this.result) |
| 65 | + } |
| 66 | + if (onerror) { |
| 67 | + reader.onabort = reader.onerror = function () { |
| 68 | + onerror.call(reader, this.error) |
| 69 | + } |
| 70 | + } |
| 71 | + var readerMethod = reader[method || 'readAsDataURL'] |
| 72 | + if (readerMethod) { |
| 73 | + readerMethod.call(reader, file) |
| 74 | + return reader |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + /** |
| 79 | + * Cross-frame instanceof check. |
| 80 | + * |
| 81 | + * @param {string} type Instance type |
| 82 | + * @param {object} obj Object instance |
| 83 | + * @returns {boolean} Returns true if the object is of the given instance. |
| 84 | + */ |
| 85 | + function isInstanceOf(type, obj) { |
| 86 | + // Cross-frame instanceof check |
| 87 | + return Object.prototype.toString.call(obj) === '[object ' + type + ']' |
| 88 | + } |
| 89 | + |
| 90 | + /** |
| 91 | + * @typedef { HTMLImageElement|HTMLCanvasElement } Result |
| 92 | + */ |
| 93 | + |
17 | 94 | /** |
18 | 95 | * Loads an image for a given File object. |
19 | 96 | * |
20 | | - * @param {File|Blob|string} file File or Blob object or image URL |
| 97 | + * @param {Blob|string} file Blob object or image URL |
21 | 98 | * @param {Function|object} [callback] Image load event callback or options |
22 | 99 | * @param {object} [options] Options object |
23 | | - * @returns {HTMLImageElement|HTMLCanvasElement|FileReader|Promise} Object |
| 100 | + * @returns {HTMLImageElement|FileReader|Promise<Result>} Object |
24 | 101 | */ |
25 | 102 | function loadImage(file, callback, options) { |
26 | 103 | /** |
27 | 104 | * Promise executor |
28 | 105 | * |
29 | 106 | * @param {Function} resolve Resolution function |
30 | 107 | * @param {Function} reject Rejection function |
31 | | - * @returns {HTMLImageElement|HTMLCanvasElement|FileReader} Object |
| 108 | + * @returns {HTMLImageElement|FileReader} Object |
32 | 109 | */ |
33 | 110 | function executor(resolve, reject) { |
34 | 111 | var img = document.createElement('img') |
|
45 | 122 | // Not using Promises |
46 | 123 | if (resolve) resolve(img, data) |
47 | 124 | return |
| 125 | + } else if (img instanceof Error) { |
| 126 | + reject(img) |
| 127 | + return |
48 | 128 | } |
49 | 129 | data = data || {} // eslint-disable-line no-param-reassign |
50 | 130 | data.image = img |
|
58 | 138 | */ |
59 | 139 | function fetchBlobCallback(blob, err) { |
60 | 140 | if (err && $.console) console.log(err) // eslint-disable-line no-console |
61 | | - if (blob && loadImage.isInstanceOf('Blob', blob)) { |
| 141 | + if (blob && isInstanceOf('Blob', blob)) { |
62 | 142 | file = blob // eslint-disable-line no-param-reassign |
63 | | - url = loadImage.createObjectURL(file) |
| 143 | + url = createObjectURL(file) |
64 | 144 | } else { |
65 | 145 | url = file |
66 | 146 | if (options && options.crossOrigin) { |
|
70 | 150 | img.src = url |
71 | 151 | } |
72 | 152 | img.onerror = function (event) { |
73 | | - return loadImage.onerror(img, event, file, url, reject, options) |
| 153 | + revokeHelper(url, options) |
| 154 | + if (reject) reject.call(img, event) |
74 | 155 | } |
75 | | - img.onload = function (event) { |
76 | | - return loadImage.onload(img, event, file, url, resolveWrapper, options) |
| 156 | + img.onload = function () { |
| 157 | + revokeHelper(url, options) |
| 158 | + var data = { |
| 159 | + originalWidth: img.naturalWidth || img.width, |
| 160 | + originalHeight: img.naturalHeight || img.height |
| 161 | + } |
| 162 | + try { |
| 163 | + loadImage.transform(img, options, resolveWrapper, file, data) |
| 164 | + } catch (error) { |
| 165 | + if (reject) reject(error) |
| 166 | + } |
77 | 167 | } |
78 | 168 | if (typeof file === 'string') { |
79 | 169 | if (loadImage.requiresMetaData(options)) { |
|
82 | 172 | fetchBlobCallback() |
83 | 173 | } |
84 | 174 | return img |
85 | | - } else if ( |
86 | | - loadImage.isInstanceOf('Blob', file) || |
87 | | - // Files are also Blob instances, but some browsers |
88 | | - // (Firefox 3.6) support the File API but not Blobs: |
89 | | - loadImage.isInstanceOf('File', file) |
90 | | - ) { |
91 | | - url = loadImage.createObjectURL(file) |
| 175 | + } else if (isInstanceOf('Blob', file) || isInstanceOf('File', file)) { |
| 176 | + url = createObjectURL(file) |
92 | 177 | if (url) { |
93 | 178 | img.src = url |
94 | 179 | return img |
95 | 180 | } |
96 | | - return loadImage.readFile(file, function (e) { |
97 | | - var target = e.target |
98 | | - if (target && target.result) { |
99 | | - img.src = target.result |
100 | | - } else if (reject) { |
101 | | - reject(e) |
102 | | - } |
103 | | - }) |
| 181 | + return readFile( |
| 182 | + file, |
| 183 | + function (url) { |
| 184 | + img.src = url |
| 185 | + }, |
| 186 | + reject |
| 187 | + ) |
104 | 188 | } |
105 | 189 | } |
106 | 190 | if ($.Promise && typeof callback !== 'function') { |
|
109 | 193 | } |
110 | 194 | return executor(callback, callback) |
111 | 195 | } |
112 | | - // The check for URL.revokeObjectURL fixes an issue with Opera 12, |
113 | | - // which provides URL.createObjectURL but doesn't properly implement it: |
114 | | - var urlAPI = |
115 | | - ($.createObjectURL && $) || |
116 | | - ($.URL && URL.revokeObjectURL && URL) || |
117 | | - ($.webkitURL && webkitURL) |
118 | | - |
119 | | - /** |
120 | | - * Helper function to revoke an object URL |
121 | | - * |
122 | | - * @param {string} url Blob Object URL |
123 | | - * @param {object} [options] Options object |
124 | | - */ |
125 | | - function revokeHelper(url, options) { |
126 | | - if (url && url.slice(0, 5) === 'blob:' && !(options && options.noRevoke)) { |
127 | | - loadImage.revokeObjectURL(url) |
128 | | - } |
129 | | - } |
130 | 196 |
|
131 | 197 | // Determines if metadata should be loaded automatically. |
132 | 198 | // Requires the load image meta extension to load metadata. |
|
141 | 207 | callback() |
142 | 208 | } |
143 | 209 |
|
144 | | - loadImage.isInstanceOf = function (type, obj) { |
145 | | - // Cross-frame instanceof check |
146 | | - return Object.prototype.toString.call(obj) === '[object ' + type + ']' |
147 | | - } |
148 | | - |
149 | 210 | loadImage.transform = function (img, options, callback, file, data) { |
150 | 211 | callback(img, data) |
151 | 212 | } |
152 | 213 |
|
153 | | - loadImage.onerror = function (img, event, file, url, callback, options) { |
154 | | - revokeHelper(url, options) |
155 | | - if (callback) { |
156 | | - callback.call(img, event) |
157 | | - } |
158 | | - } |
159 | | - |
160 | | - loadImage.onload = function (img, event, file, url, callback, options) { |
161 | | - revokeHelper(url, options) |
162 | | - loadImage.transform(img, options, callback, file, { |
163 | | - originalWidth: img.naturalWidth || img.width, |
164 | | - originalHeight: img.naturalHeight || img.height |
165 | | - }) |
166 | | - } |
167 | | - |
168 | | - loadImage.createObjectURL = function (file) { |
169 | | - return urlAPI ? urlAPI.createObjectURL(file) : false |
170 | | - } |
171 | | - |
172 | | - loadImage.revokeObjectURL = function (url) { |
173 | | - return urlAPI ? urlAPI.revokeObjectURL(url) : false |
174 | | - } |
175 | | - |
176 | | - // Loads a given File object via FileReader interface, |
177 | | - // invokes the callback with the event object (load or error). |
178 | | - // The result can be read via event.target.result: |
179 | | - loadImage.readFile = function (file, callback, method) { |
180 | | - if ($.FileReader) { |
181 | | - var fileReader = new FileReader() |
182 | | - fileReader.onload = fileReader.onerror = callback |
183 | | - // eslint-disable-next-line no-param-reassign |
184 | | - method = method || 'readAsDataURL' |
185 | | - if (fileReader[method]) { |
186 | | - fileReader[method](file) |
187 | | - return fileReader |
188 | | - } |
189 | | - } |
190 | | - return false |
191 | | - } |
192 | | - |
193 | 214 | loadImage.global = $ |
| 215 | + loadImage.readFile = readFile |
| 216 | + loadImage.isInstanceOf = isInstanceOf |
| 217 | + loadImage.createObjectURL = createObjectURL |
| 218 | + loadImage.revokeObjectURL = revokeObjectURL |
194 | 219 |
|
195 | 220 | if (typeof define === 'function' && define.amd) { |
196 | 221 | define(function () { |
|
0 commit comments