|
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