1 | # JavaScript Load Image
|
2 |
|
3 | > A JavaScript library to load and transform image files.
|
4 |
|
5 | ## Contents
|
6 |
|
7 | - [Demo](https://blueimp.github.io/JavaScript-Load-Image/)
|
8 | - [Description](#description)
|
9 | - [Setup](#setup)
|
10 | - [Usage](#usage)
|
11 | - [Image loading](#image-loading)
|
12 | - [Image scaling](#image-scaling)
|
13 | - [Requirements](#requirements)
|
14 | - [Browser support](#browser-support)
|
15 | - [API](#api)
|
16 | - [Callback](#callback)
|
17 | - [Function signature](#function-signature)
|
18 | - [Cancel image loading](#cancel-image-loading)
|
19 | - [Callback arguments](#callback-arguments)
|
20 | - [Error handling](#error-handling)
|
21 | - [Promise](#promise)
|
22 | - [Options](#options)
|
23 | - [maxWidth](#maxwidth)
|
24 | - [maxHeight](#maxheight)
|
25 | - [minWidth](#minwidth)
|
26 | - [minHeight](#minheight)
|
27 | - [sourceWidth](#sourcewidth)
|
28 | - [sourceHeight](#sourceheight)
|
29 | - [top](#top)
|
30 | - [right](#right)
|
31 | - [bottom](#bottom)
|
32 | - [left](#left)
|
33 | - [contain](#contain)
|
34 | - [cover](#cover)
|
35 | - [aspectRatio](#aspectratio)
|
36 | - [pixelRatio](#pixelratio)
|
37 | - [downsamplingRatio](#downsamplingratio)
|
38 | - [imageSmoothingEnabled](#imagesmoothingenabled)
|
39 | - [imageSmoothingQuality](#imagesmoothingquality)
|
40 | - [crop](#crop)
|
41 | - [orientation](#orientation)
|
42 | - [meta](#meta)
|
43 | - [canvas](#canvas)
|
44 | - [crossOrigin](#crossorigin)
|
45 | - [noRevoke](#norevoke)
|
46 | - [Metadata parsing](#metadata-parsing)
|
47 | - [Image head](#image-head)
|
48 | - [Exif parser](#exif-parser)
|
49 | - [Exif Thumbnail](#exif-thumbnail)
|
50 | - [Exif IFD](#exif-ifd)
|
51 | - [GPSInfo IFD](#gpsinfo-ifd)
|
52 | - [Interoperability IFD](#interoperability-ifd)
|
53 | - [Exif parser options](#exif-parser-options)
|
54 | - [Exif writer](#exif-writer)
|
55 | - [IPTC parser](#iptc-parser)
|
56 | - [IPTC parser options](#iptc-parser-options)
|
57 | - [License](#license)
|
58 | - [Credits](#credits)
|
59 |
|
60 | ## Description
|
61 |
|
62 | JavaScript Load Image is a library to load images provided as `File` or `Blob`
|
63 | objects or via `URL`. It returns an optionally **scaled**, **cropped** or
|
64 | **rotated** HTML `img` or `canvas` element.
|
65 |
|
66 | It also provides methods to parse image metadata to extract
|
67 | [IPTC](https://iptc.org/standards/photo-metadata/) and
|
68 | [Exif](https://en.wikipedia.org/wiki/Exif) tags as well as embedded thumbnail
|
69 | images, to overwrite the Exif Orientation value and to restore the complete
|
70 | image header after resizing.
|
71 |
|
72 | ## Setup
|
73 |
|
74 | Install via [NPM](https://www.npmjs.com/package/blueimp-load-image):
|
75 |
|
76 | ```sh
|
77 | npm install blueimp-load-image
|
78 | ```
|
79 |
|
80 | This will install the JavaScript files inside
|
81 | `./node_modules/blueimp-load-image/js/` relative to your current directory, from
|
82 | where you can copy them into a folder that is served by your web server.
|
83 |
|
84 | Next include the combined and minified JavaScript Load Image script in your HTML
|
85 | markup:
|
86 |
|
87 | ```html
|
88 | <script src="js/load-image.all.min.js"></script>
|
89 | ```
|
90 |
|
91 | Or alternatively, choose which components you want to include:
|
92 |
|
93 | ```html
|
94 | <!-- required for all operations -->
|
95 | <script src="js/load-image.js"></script>
|
96 |
|
97 | <!-- required for scaling, cropping and as dependency for rotation -->
|
98 | <script src="js/load-image-scale.js"></script>
|
99 |
|
100 | <!-- required to parse meta data and to restore the complete image head -->
|
101 | <script src="js/load-image-meta.js"></script>
|
102 |
|
103 | <!-- required to parse meta data from images loaded via URL -->
|
104 | <script src="js/load-image-fetch.js"></script>
|
105 |
|
106 | <!-- required for rotation and cross-browser image orientation -->
|
107 | <script src="js/load-image-orientation.js"></script>
|
108 |
|
109 | <!-- required to parse Exif tags and cross-browser image orientation -->
|
110 | <script src="js/load-image-exif.js"></script>
|
111 |
|
112 | <!-- required to display text mappings for Exif tags -->
|
113 | <script src="js/load-image-exif-map.js"></script>
|
114 |
|
115 | <!-- required to parse IPTC tags -->
|
116 | <script src="js/load-image-iptc.js"></script>
|
117 |
|
118 | <!-- required to display text mappings for IPTC tags -->
|
119 | <script src="js/load-image-iptc-map.js"></script>
|
120 | ```
|
121 |
|
122 | ## Usage
|
123 |
|
124 | ### Image loading
|
125 |
|
126 | In your application code, use the `loadImage()` function with
|
127 | [callback](#callback) style:
|
128 |
|
129 | ```js
|
130 | document.getElementById('file-input').onchange = function () {
|
131 | loadImage(
|
132 | this.files[0],
|
133 | function (img) {
|
134 | document.body.appendChild(img)
|
135 | },
|
136 | { maxWidth: 600 } // Options
|
137 | )
|
138 | }
|
139 | ```
|
140 |
|
141 | Or use the [Promise](#promise) based API like this ([requires](#requirements) a
|
142 | polyfill for older browsers):
|
143 |
|
144 | ```js
|
145 | document.getElementById('file-input').onchange = function () {
|
146 | loadImage(this.files[0], { maxWidth: 600 }).then(function (data) {
|
147 | document.body.appendChild(data.image)
|
148 | })
|
149 | }
|
150 | ```
|
151 |
|
152 | With
|
153 | [async/await](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await)
|
154 | (requires a modern browser or a code transpiler like
|
155 | [Babel](https://babeljs.io/) or [TypeScript](https://www.typescriptlang.org/)):
|
156 |
|
157 | ```js
|
158 | document.getElementById('file-input').onchange = async function () {
|
159 | let data = await loadImage(this.files[0], { maxWidth: 600 })
|
160 | document.body.appendChild(data.image)
|
161 | }
|
162 | ```
|
163 |
|
164 | ### Image scaling
|
165 |
|
166 | It is also possible to use the image scaling functionality directly with an
|
167 | existing image:
|
168 |
|
169 | ```js
|
170 | var scaledImage = loadImage.scale(
|
171 | img, // img or canvas element
|
172 | { maxWidth: 600 }
|
173 | )
|
174 | ```
|
175 |
|
176 | ## Requirements
|
177 |
|
178 | The JavaScript Load Image library has zero dependencies, but benefits from the
|
179 | following two
|
180 | [polyfills](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill):
|
181 |
|
182 | - [blueimp-canvas-to-blob](https://github.com/blueimp/JavaScript-Canvas-to-Blob)
|
183 | for browsers without native
|
184 | [HTMLCanvasElement.toBlob](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob)
|
185 | support, to create `Blob` objects out of `canvas` elements.
|
186 | - [promise-polyfill](https://github.com/taylorhakes/promise-polyfill) to be able
|
187 | to use the
|
188 | [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
|
189 | based `loadImage` API in Browsers without native `Promise` support.
|
190 |
|
191 | ## Browser support
|
192 |
|
193 | Browsers which implement the following APIs support all options:
|
194 |
|
195 | - Loading images from File and Blob objects:
|
196 | - [URL.createObjectURL](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL)
|
197 | or
|
198 | [FileReader.readAsDataURL](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL)
|
199 | - Parsing meta data:
|
200 | - [FileReader.readAsArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsArrayBuffer)
|
201 | - [Blob.slice](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice)
|
202 | - [DataView](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView)
|
203 | (no [BigInt](https://developer.mozilla.org/en-US/docs/Glossary/BigInt)
|
204 | support required)
|
205 | - Parsing meta data from images loaded via URL:
|
206 | - [fetch Response.blob](https://developer.mozilla.org/en-US/docs/Web/API/Body/blob)
|
207 | or
|
208 | [XMLHttpRequest.responseType blob](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType#blob)
|
209 | - Promise based API:
|
210 | - [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
|
211 |
|
212 | This includes (but is not limited to) the following browsers:
|
213 |
|
214 | - Chrome 32+
|
215 | - Firefox 29+
|
216 | - Safari 8+
|
217 | - Mobile Chrome 42+ (Android)
|
218 | - Mobile Firefox 50+ (Android)
|
219 | - Mobile Safari 8+ (iOS)
|
220 | - Edge 74+
|
221 | - Edge Legacy 12+
|
222 | - Internet Explorer 10+ `*`
|
223 |
|
224 | `*` Internet Explorer [requires](#requirements) a polyfill for the `Promise`
|
225 | based API.
|
226 |
|
227 | Loading an image from a URL and applying transformations (scaling, cropping and
|
228 | rotating - except `orientation:true`, which requires reading meta data) is
|
229 | supported by all browsers which implement the
|
230 | [HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement)
|
231 | interface.
|
232 |
|
233 | Loading an image from a URL and scaling it in size is supported by all browsers
|
234 | which implement the
|
235 | [img](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) element and
|
236 | has been tested successfully with browser engines as old as Internet Explorer 5
|
237 | (via
|
238 | [IE11's emulation mode](<https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/samples/dn255001(v=vs.85)>)).
|
239 |
|
240 | The `loadImage()` function applies options using
|
241 | [progressive enhancement](https://en.wikipedia.org/wiki/Progressive_enhancement)
|
242 | and falls back to a configuration that is supported by the browser, e.g. if the
|
243 | `canvas` element is not supported, an equivalent `img` element is returned.
|
244 |
|
245 | ## API
|
246 |
|
247 | ### Callback
|
248 |
|
249 | #### Function signature
|
250 |
|
251 | The `loadImage()` function accepts a
|
252 | [File](https://developer.mozilla.org/en-US/docs/Web/API/File) or
|
253 | [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) object or an image
|
254 | URL as first argument.
|
255 |
|
256 | If a [File](https://developer.mozilla.org/en-US/docs/Web/API/File) or
|
257 | [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) is passed as
|
258 | parameter, it returns an HTML `img` element if the browser supports the
|
259 | [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) API, alternatively a
|
260 | [FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader) object
|
261 | if the `FileReader` API is supported, or `false`.
|
262 |
|
263 | It always returns an HTML
|
264 | [img](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Img) element
|
265 | when passing an image URL:
|
266 |
|
267 | ```js
|
268 | var loadingImage = loadImage(
|
269 | 'https://example.org/image.png',
|
270 | function (img) {
|
271 | document.body.appendChild(img)
|
272 | },
|
273 | { maxWidth: 600 }
|
274 | )
|
275 | ```
|
276 |
|
277 | #### Cancel image loading
|
278 |
|
279 | Some browsers (e.g. Chrome) will cancel the image loading process if the `src`
|
280 | property of an `img` element is changed.
|
281 | To avoid unnecessary requests, we can use the
|
282 | [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs)
|
283 | of a 1x1 pixel transparent GIF image as `src` target to cancel the original
|
284 | image download.
|
285 |
|
286 | To disable callback handling, we can also unset the image event handlers and for
|
287 | maximum browser compatibility, cancel the file reading process if the returned
|
288 | object is a
|
289 | [FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader)
|
290 | instance:
|
291 |
|
292 | ```js
|
293 | var loadingImage = loadImage(
|
294 | 'https://example.org/image.png',
|
295 | function (img) {
|
296 | document.body.appendChild(img)
|
297 | },
|
298 | { maxWidth: 600 }
|
299 | )
|
300 |
|
301 | if (loadingImage) {
|
302 | // Unset event handling for the loading image:
|
303 | loadingImage.onload = loadingImage.onerror = null
|
304 |
|
305 | // Cancel image loading process:
|
306 | if (loadingImage.abort) {
|
307 | // FileReader instance, stop the file reading process:
|
308 | loadingImage.abort()
|
309 | } else {
|
310 | // HTMLImageElement element, cancel the original image request by changing
|
311 | // the target source to the data URL of a 1x1 pixel transparent image GIF:
|
312 | loadingImage.src =
|
313 | 'data:image/gif;base64,' +
|
314 | 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
|
315 | }
|
316 | }
|
317 | ```
|
318 |
|
319 | **Please note:**
|
320 | The `img` element (or `FileReader` instance) for the loading image is only
|
321 | returned when using the callback style API and not available with the
|
322 | [Promise](#promise) based API.
|
323 |
|
324 | #### Callback arguments
|
325 |
|
326 | For the callback style API, the second argument to `loadImage()` must be a
|
327 | `callback` function, which is called when the image has been loaded or an error
|
328 | occurred while loading the image.
|
329 |
|
330 | The callback function is passed two arguments:
|
331 |
|
332 | 1. An HTML [img](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img)
|
333 | element or
|
334 | [canvas](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)
|
335 | element, or an
|
336 | [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) object of
|
337 | type `error`.
|
338 | 2. An object with the original image dimensions as properties and potentially
|
339 | additional [metadata](#metadata-parsing).
|
340 |
|
341 | ```js
|
342 | loadImage(
|
343 | fileOrBlobOrUrl,
|
344 | function (img, data) {
|
345 | document.body.appendChild(img)
|
346 | console.log('Original image width: ', data.originalWidth)
|
347 | console.log('Original image height: ', data.originalHeight)
|
348 | },
|
349 | { maxWidth: 600, meta: true }
|
350 | )
|
351 | ```
|
352 |
|
353 | **Please note:**
|
354 | The original image dimensions reflect the natural width and height of the loaded
|
355 | image before applying any transformation.
|
356 | For consistent values across browsers, [metadata](#metadata-parsing) parsing has
|
357 | to be enabled via `meta:true`, so `loadImage` can detect automatic image
|
358 | orientation and normalize the dimensions.
|
359 |
|
360 | #### Error handling
|
361 |
|
362 | Example code implementing error handling:
|
363 |
|
364 | ```js
|
365 | loadImage(
|
366 | fileOrBlobOrUrl,
|
367 | function (img, data) {
|
368 | if (img.type === 'error') {
|
369 | console.error('Error loading image file')
|
370 | } else {
|
371 | document.body.appendChild(img)
|
372 | }
|
373 | },
|
374 | { maxWidth: 600 }
|
375 | )
|
376 | ```
|
377 |
|
378 | ### Promise
|
379 |
|
380 | If the `loadImage()` function is called without a `callback` function as second
|
381 | argument and the
|
382 | [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
|
383 | API is available, it returns a `Promise` object:
|
384 |
|
385 | ```js
|
386 | loadImage(fileOrBlobOrUrl, { maxWidth: 600, meta: true })
|
387 | .then(function (data) {
|
388 | document.body.appendChild(data.image)
|
389 | console.log('Original image width: ', data.originalWidth)
|
390 | console.log('Original image height: ', data.originalHeight)
|
391 | })
|
392 | .catch(function (err) {
|
393 | // Handling image loading errors
|
394 | console.log(err)
|
395 | })
|
396 | ```
|
397 |
|
398 | The `Promise` resolves with an object with the following properties:
|
399 |
|
400 | - `image`: An HTML
|
401 | [img](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) or
|
402 | [canvas](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API) element.
|
403 | - `originalWidth`: The original width of the image.
|
404 | - `originalHeight`: The original height of the image.
|
405 |
|
406 | Please also read the note about original image dimensions normalization in the
|
407 | [callback arguments](#callback-arguments) section.
|
408 |
|
409 | If [metadata](#metadata-parsing) has been parsed, additional properties might be
|
410 | present on the object.
|
411 |
|
412 | If image loading fails, the `Promise` rejects with an
|
413 | [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) object of type
|
414 | `error`.
|
415 |
|
416 | ## Options
|
417 |
|
418 | The optional options argument to `loadImage()` allows to configure the image
|
419 | loading.
|
420 |
|
421 | It can be used the following way with the callback style:
|
422 |
|
423 | ```js
|
424 | loadImage(
|
425 | fileOrBlobOrUrl,
|
426 | function (img) {
|
427 | document.body.appendChild(img)
|
428 | },
|
429 | {
|
430 | maxWidth: 600,
|
431 | maxHeight: 300,
|
432 | minWidth: 100,
|
433 | minHeight: 50,
|
434 | canvas: true
|
435 | }
|
436 | )
|
437 | ```
|
438 |
|
439 | Or the following way with the `Promise` based API:
|
440 |
|
441 | ```js
|
442 | loadImage(fileOrBlobOrUrl, {
|
443 | maxWidth: 600,
|
444 | maxHeight: 300,
|
445 | minWidth: 100,
|
446 | minHeight: 50,
|
447 | canvas: true
|
448 | }).then(function (data) {
|
449 | document.body.appendChild(data.image)
|
450 | })
|
451 | ```
|
452 |
|
453 | All settings are optional. By default, the image is returned as HTML `img`
|
454 | element without any image size restrictions.
|
455 |
|
456 | ### maxWidth
|
457 |
|
458 | Defines the maximum width of the `img`/`canvas` element.
|
459 |
|
460 | ### maxHeight
|
461 |
|
462 | Defines the maximum height of the `img`/`canvas` element.
|
463 |
|
464 | ### minWidth
|
465 |
|
466 | Defines the minimum width of the `img`/`canvas` element.
|
467 |
|
468 | ### minHeight
|
469 |
|
470 | Defines the minimum height of the `img`/`canvas` element.
|
471 |
|
472 | ### sourceWidth
|
473 |
|
474 | The width of the sub-rectangle of the source image to draw into the destination
|
475 | canvas.
|
476 | Defaults to the source image width and requires `canvas: true`.
|
477 |
|
478 | ### sourceHeight
|
479 |
|
480 | The height of the sub-rectangle of the source image to draw into the destination
|
481 | canvas.
|
482 | Defaults to the source image height and requires `canvas: true`.
|
483 |
|
484 | ### top
|
485 |
|
486 | The top margin of the sub-rectangle of the source image.
|
487 | Defaults to `0` and requires `canvas: true`.
|
488 |
|
489 | ### right
|
490 |
|
491 | The right margin of the sub-rectangle of the source image.
|
492 | Defaults to `0` and requires `canvas: true`.
|
493 |
|
494 | ### bottom
|
495 |
|
496 | The bottom margin of the sub-rectangle of the source image.
|
497 | Defaults to `0` and requires `canvas: true`.
|
498 |
|
499 | ### left
|
500 |
|
501 | The left margin of the sub-rectangle of the source image.
|
502 | Defaults to `0` and requires `canvas: true`.
|
503 |
|
504 | ### contain
|
505 |
|
506 | Scales the image up/down to contain it in the max dimensions if set to `true`.
|
507 | This emulates the CSS feature
|
508 | [background-image: contain](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Backgrounds_and_Borders/Resizing_background_images#contain).
|
509 |
|
510 | ### cover
|
511 |
|
512 | Scales the image up/down to cover the max dimensions with the image dimensions
|
513 | if set to `true`.
|
514 | This emulates the CSS feature
|
515 | [background-image: cover](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Backgrounds_and_Borders/Resizing_background_images#cover).
|
516 |
|
517 | ### aspectRatio
|
518 |
|
519 | Crops the image to the given aspect ratio (e.g. `16/9`).
|
520 | Setting the `aspectRatio` also enables the `crop` option.
|
521 |
|
522 | ### pixelRatio
|
523 |
|
524 | Defines the ratio of the canvas pixels to the physical image pixels on the
|
525 | screen.
|
526 | Should be set to
|
527 | [window.devicePixelRatio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio)
|
528 | unless the scaled image is not rendered on screen.
|
529 | Defaults to `1` and requires `canvas: true`.
|
530 |
|
531 | ### downsamplingRatio
|
532 |
|
533 | Defines the ratio in which the image is downsampled (scaled down in steps).
|
534 | By default, images are downsampled in one step.
|
535 | With a ratio of `0.5`, each step scales the image to half the size, before
|
536 | reaching the target dimensions.
|
537 | Requires `canvas: true`.
|
538 |
|
539 | ### imageSmoothingEnabled
|
540 |
|
541 | If set to `false`,
|
542 | [disables image smoothing](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled).
|
543 | Defaults to `true` and requires `canvas: true`.
|
544 |
|
545 | ### imageSmoothingQuality
|
546 |
|
547 | Sets the
|
548 | [quality of image smoothing](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality).
|
549 | Possible values: `'low'`, `'medium'`, `'high'`
|
550 | Defaults to `'low'` and requires `canvas: true`.
|
551 |
|
552 | ### crop
|
553 |
|
554 | Crops the image to the `maxWidth`/`maxHeight` constraints if set to `true`.
|
555 | Enabling the `crop` option also enables the `canvas` option.
|
556 |
|
557 | ### orientation
|
558 |
|
559 | Transform the canvas according to the specified Exif orientation, which can be
|
560 | an `integer` in the range of `1` to `8` or the boolean value `true`.
|
561 |
|
562 | When set to `true`, it will set the orientation value based on the Exif data of
|
563 | the image, which will be parsed automatically if the Exif extension is
|
564 | available.
|
565 |
|
566 | Exif orientation values to correctly display the letter F:
|
567 |
|
568 | ```
|
569 | 1 2
|
570 | ██████ ██████
|
571 | ██ ██
|
572 | ████ ████
|
573 | ██ ██
|
574 | ██ ██
|
575 |
|
576 | 3 4
|
577 | ██ ██
|
578 | ██ ██
|
579 | ████ ████
|
580 | ██ ██
|
581 | ██████ ██████
|
582 |
|
583 | 5 6
|
584 | ██████████ ██
|
585 | ██ ██ ██ ██
|
586 | ██ ██████████
|
587 |
|
588 | 7 8
|
589 | ██ ██████████
|
590 | ██ ██ ██ ██
|
591 | ██████████ ██
|
592 | ```
|
593 |
|
594 | Setting `orientation` to `true` enables the `canvas` and `meta` options, unless
|
595 | the browser supports automatic image orientation (see
|
596 | [browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)).
|
597 |
|
598 | Setting `orientation` to `1` enables the `canvas` and `meta` options if the
|
599 | browser does support automatic image orientation (to allow reset of the
|
600 | orientation).
|
601 |
|
602 | Setting `orientation` to an integer in the range of `2` to `8` always enables
|
603 | the `canvas` option and also enables the `meta` option if the browser supports
|
604 | automatic image orientation (again to allow reset).
|
605 |
|
606 | ### meta
|
607 |
|
608 | Automatically parses the image metadata if set to `true`.
|
609 |
|
610 | If metadata has been found, the data object passed as second argument to the
|
611 | callback function has additional properties (see
|
612 | [metadata parsing](#metadata-parsing)).
|
613 |
|
614 | If the file is given as URL and the browser supports the
|
615 | [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) or the
|
616 | XHR
|
617 | [responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
|
618 | `blob`, fetches the file as `Blob` to be able to parse the metadata.
|
619 |
|
620 | ### canvas
|
621 |
|
622 | Returns the image as
|
623 | [canvas](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API) element if
|
624 | set to `true`.
|
625 |
|
626 | ### crossOrigin
|
627 |
|
628 | Sets the `crossOrigin` property on the `img` element for loading
|
629 | [CORS enabled images](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image).
|
630 |
|
631 | ### noRevoke
|
632 |
|
633 | By default, the
|
634 | [created object URL](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL)
|
635 | is revoked after the image has been loaded, except when this option is set to
|
636 | `true`.
|
637 |
|
638 | ## Metadata parsing
|
639 |
|
640 | If the Load Image Meta extension is included, it is possible to parse image meta
|
641 | data automatically with the `meta` option:
|
642 |
|
643 | ```js
|
644 | loadImage(
|
645 | fileOrBlobOrUrl,
|
646 | function (img, data) {
|
647 | console.log('Original image head: ', data.imageHead)
|
648 | console.log('Exif data: ', data.exif) // requires exif extension
|
649 | console.log('IPTC data: ', data.iptc) // requires iptc extension
|
650 | },
|
651 | { meta: true }
|
652 | )
|
653 | ```
|
654 |
|
655 | Or alternatively via `loadImage.parseMetaData`, which can be used with an
|
656 | available `File` or `Blob` object as first argument:
|
657 |
|
658 | ```js
|
659 | loadImage.parseMetaData(
|
660 | fileOrBlob,
|
661 | function (data) {
|
662 | console.log('Original image head: ', data.imageHead)
|
663 | console.log('Exif data: ', data.exif) // requires exif extension
|
664 | console.log('IPTC data: ', data.iptc) // requires iptc extension
|
665 | },
|
666 | {
|
667 | maxMetaDataSize: 262144
|
668 | }
|
669 | )
|
670 | ```
|
671 |
|
672 | Or using the
|
673 | [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
|
674 | based API:
|
675 |
|
676 | ```js
|
677 | loadImage
|
678 | .parseMetaData(fileOrBlob, {
|
679 | maxMetaDataSize: 262144
|
680 | })
|
681 | .then(function (data) {
|
682 | console.log('Original image head: ', data.imageHead)
|
683 | console.log('Exif data: ', data.exif) // requires exif extension
|
684 | console.log('IPTC data: ', data.iptc) // requires iptc extension
|
685 | })
|
686 | ```
|
687 |
|
688 | The Metadata extension adds additional options used for the `parseMetaData`
|
689 | method:
|
690 |
|
691 | - `maxMetaDataSize`: Maximum number of bytes of metadata to parse.
|
692 | - `disableImageHead`: Disable parsing the original image head.
|
693 | - `disableMetaDataParsers`: Disable parsing metadata (image head only)
|
694 |
|
695 | ### Image head
|
696 |
|
697 | Resized JPEG images can be combined with their original image head via
|
698 | `loadImage.replaceHead`, which requires the resized image as `Blob` object as
|
699 | first argument and an `ArrayBuffer` image head as second argument.
|
700 |
|
701 | With callback style, the third argument must be a `callback` function, which is
|
702 | called with the new `Blob` object:
|
703 |
|
704 | ```js
|
705 | loadImage(
|
706 | fileOrBlobOrUrl,
|
707 | function (img, data) {
|
708 | if (data.imageHead) {
|
709 | img.toBlob(function (blob) {
|
710 | loadImage.replaceHead(blob, data.imageHead, function (newBlob) {
|
711 | // do something with the new Blob object
|
712 | })
|
713 | }, 'image/jpeg')
|
714 | }
|
715 | },
|
716 | { meta: true, canvas: true, maxWidth: 800 }
|
717 | )
|
718 | ```
|
719 |
|
720 | Or using the
|
721 | [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
|
722 | based API like this:
|
723 |
|
724 | ```js
|
725 | loadImage(fileOrBlobOrUrl, { meta: true, canvas: true, maxWidth: 800 })
|
726 | .then(function (data) {
|
727 | if (!data.imageHead) throw new Error('Could not parse image metadata')
|
728 | return new Promise(function (resolve) {
|
729 | data.image.toBlob(function (blob) {
|
730 | data.blob = blob
|
731 | resolve(data)
|
732 | }, 'image/jpeg')
|
733 | })
|
734 | })
|
735 | .then(function (data) {
|
736 | return loadImage.replaceHead(data.blob, data.imageHead)
|
737 | })
|
738 | .then(function (blob) {
|
739 | // do something with the new Blob object
|
740 | })
|
741 | .catch(function (err) {
|
742 | console.error(err)
|
743 | })
|
744 | ```
|
745 |
|
746 | **Please note:**
|
747 | `Blob` objects of resized images can be created via
|
748 | [HTMLCanvasElement.toBlob](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob).
|
749 | [blueimp-canvas-to-blob](https://github.com/blueimp/JavaScript-Canvas-to-Blob)
|
750 | provides a polyfill for browsers without native `canvas.toBlob()` support.
|
751 |
|
752 | ### Exif parser
|
753 |
|
754 | If you include the Load Image Exif Parser extension, the argument passed to the
|
755 | callback for `parseMetaData` will contain the following additional properties if
|
756 | Exif data could be found in the given image:
|
757 |
|
758 | - `exif`: The parsed Exif tags
|
759 | - `exifOffsets`: The parsed Exif tag offsets
|
760 | - `exifTiffOffset`: TIFF header offset (used for offset pointers)
|
761 | - `exifLittleEndian`: little endian order if true, big endian if false
|
762 |
|
763 | The `exif` object stores the parsed Exif tags:
|
764 |
|
765 | ```js
|
766 | var orientation = data.exif[0x0112] // Orientation
|
767 | ```
|
768 |
|
769 | The `exif` and `exifOffsets` objects also provide a `get()` method to retrieve
|
770 | the tag value/offset via the tag's mapped name:
|
771 |
|
772 | ```js
|
773 | var orientation = data.exif.get('Orientation')
|
774 | var orientationOffset = data.exifOffsets.get('Orientation')
|
775 | ```
|
776 |
|
777 | By default, only the following names are mapped:
|
778 |
|
779 | - `Orientation`
|
780 | - `Thumbnail` (see [Exif Thumbnail](#exif-thumbnail))
|
781 | - `Exif` (see [Exif IFD](#exif-ifd))
|
782 | - `GPSInfo` (see [GPSInfo IFD](#gpsinfo-ifd))
|
783 | - `Interoperability` (see [Interoperability IFD](#interoperability-ifd))
|
784 |
|
785 | If you also include the Load Image Exif Map library, additional tag mappings
|
786 | become available, as well as three additional methods:
|
787 |
|
788 | - `exif.getText()`
|
789 | - `exif.getName()`
|
790 | - `exif.getAll()`
|
791 |
|
792 | ```js
|
793 | var orientationText = data.exif.getText('Orientation') // e.g. "Rotate 90° CW"
|
794 |
|
795 | var name = data.exif.getName(0x0112) // "Orientation"
|
796 |
|
797 | // A map of all parsed tags with their mapped names/text as keys/values:
|
798 | var allTags = data.exif.getAll()
|
799 | ```
|
800 |
|
801 | #### Exif Thumbnail
|
802 |
|
803 | Example code displaying a thumbnail image embedded into the Exif metadata:
|
804 |
|
805 | ```js
|
806 | loadImage(
|
807 | fileOrBlobOrUrl,
|
808 | function (img, data) {
|
809 | var exif = data.exif
|
810 | var thumbnail = exif && exif.get('Thumbnail')
|
811 | var blob = thumbnail && thumbnail.get('Blob')
|
812 | if (blob) {
|
813 | loadImage(
|
814 | blob,
|
815 | function (thumbImage) {
|
816 | document.body.appendChild(thumbImage)
|
817 | },
|
818 | { orientation: exif.get('Orientation') }
|
819 | )
|
820 | }
|
821 | },
|
822 | { meta: true }
|
823 | )
|
824 | ```
|
825 |
|
826 | #### Exif IFD
|
827 |
|
828 | Example code displaying data from the Exif IFD (Image File Directory) that
|
829 | contains Exif specified TIFF tags:
|
830 |
|
831 | ```js
|
832 | loadImage(
|
833 | fileOrBlobOrUrl,
|
834 | function (img, data) {
|
835 | var exifIFD = data.exif && data.exif.get('Exif')
|
836 | if (exifIFD) {
|
837 | // Map of all Exif IFD tags with their mapped names/text as keys/values:
|
838 | console.log(exifIFD.getAll())
|
839 | // A specific Exif IFD tag value:
|
840 | console.log(exifIFD.get('UserComment'))
|
841 | }
|
842 | },
|
843 | { meta: true }
|
844 | )
|
845 | ```
|
846 |
|
847 | #### GPSInfo IFD
|
848 |
|
849 | Example code displaying data from the Exif IFD (Image File Directory) that
|
850 | contains [GPS](https://en.wikipedia.org/wiki/Global_Positioning_System) info:
|
851 |
|
852 | ```js
|
853 | loadImage(
|
854 | fileOrBlobOrUrl,
|
855 | function (img, data) {
|
856 | var gpsInfo = data.exif && data.exif.get('GPSInfo')
|
857 | if (gpsInfo) {
|
858 | // Map of all GPSInfo tags with their mapped names/text as keys/values:
|
859 | console.log(gpsInfo.getAll())
|
860 | // A specific GPSInfo tag value:
|
861 | console.log(gpsInfo.get('GPSLatitude'))
|
862 | }
|
863 | },
|
864 | { meta: true }
|
865 | )
|
866 | ```
|
867 |
|
868 | #### Interoperability IFD
|
869 |
|
870 | Example code displaying data from the Exif IFD (Image File Directory) that
|
871 | contains Interoperability data:
|
872 |
|
873 | ```js
|
874 | loadImage(
|
875 | fileOrBlobOrUrl,
|
876 | function (img, data) {
|
877 | var interoperabilityData = data.exif && data.exif.get('Interoperability')
|
878 | if (interoperabilityData) {
|
879 | // The InteroperabilityIndex tag value:
|
880 | console.log(interoperabilityData.get('InteroperabilityIndex'))
|
881 | }
|
882 | },
|
883 | { meta: true }
|
884 | )
|
885 | ```
|
886 |
|
887 | #### Exif parser options
|
888 |
|
889 | The Exif parser adds additional options:
|
890 |
|
891 | - `disableExif`: Disables Exif parsing when `true`.
|
892 | - `disableExifOffsets`: Disables storing Exif tag offsets when `true`.
|
893 | - `includeExifTags`: A map of Exif tags to include for parsing (includes all but
|
894 | the excluded tags by default).
|
895 | - `excludeExifTags`: A map of Exif tags to exclude from parsing (defaults to
|
896 | exclude `Exif` `MakerNote`).
|
897 |
|
898 | An example parsing only Orientation, Thumbnail and ExifVersion tags:
|
899 |
|
900 | ```js
|
901 | loadImage.parseMetaData(
|
902 | fileOrBlob,
|
903 | function (data) {
|
904 | console.log('Exif data: ', data.exif)
|
905 | },
|
906 | {
|
907 | includeExifTags: {
|
908 | 0x0112: true, // Orientation
|
909 | ifd1: {
|
910 | 0x0201: true, // JPEGInterchangeFormat (Thumbnail data offset)
|
911 | 0x0202: true // JPEGInterchangeFormatLength (Thumbnail data length)
|
912 | },
|
913 | 0x8769: {
|
914 | // ExifIFDPointer
|
915 | 0x9000: true // ExifVersion
|
916 | }
|
917 | }
|
918 | }
|
919 | )
|
920 | ```
|
921 |
|
922 | An example excluding `Exif` `MakerNote` and `GPSInfo`:
|
923 |
|
924 | ```js
|
925 | loadImage.parseMetaData(
|
926 | fileOrBlob,
|
927 | function (data) {
|
928 | console.log('Exif data: ', data.exif)
|
929 | },
|
930 | {
|
931 | excludeExifTags: {
|
932 | 0x8769: {
|
933 | // ExifIFDPointer
|
934 | 0x927c: true // MakerNote
|
935 | },
|
936 | 0x8825: true // GPSInfoIFDPointer
|
937 | }
|
938 | }
|
939 | )
|
940 | ```
|
941 |
|
942 | ### Exif writer
|
943 |
|
944 | The Exif parser extension also includes a minimal writer that allows to override
|
945 | the Exif `Orientation` value in the parsed `imageHead` `ArrayBuffer`:
|
946 |
|
947 | ```js
|
948 | loadImage(
|
949 | fileOrBlobOrUrl,
|
950 | function (img, data) {
|
951 | if (data.imageHead && data.exif) {
|
952 | // Reset Exif Orientation data:
|
953 | loadImage.writeExifData(data.imageHead, data, 'Orientation', 1)
|
954 | img.toBlob(function (blob) {
|
955 | loadImage.replaceHead(blob, data.imageHead, function (newBlob) {
|
956 | // do something with newBlob
|
957 | })
|
958 | }, 'image/jpeg')
|
959 | }
|
960 | },
|
961 | { meta: true, orientation: true, canvas: true, maxWidth: 800 }
|
962 | )
|
963 | ```
|
964 |
|
965 | **Please note:**
|
966 | The Exif writer relies on the Exif tag offsets being available as
|
967 | `data.exifOffsets` property, which requires that Exif data has been parsed from
|
968 | the image.
|
969 | The Exif writer can only change existing values, not add new tags, e.g. it
|
970 | cannot add an Exif `Orientation` tag for an image that does not have one.
|
971 |
|
972 | ### IPTC parser
|
973 |
|
974 | If you include the Load Image IPTC Parser extension, the argument passed to the
|
975 | callback for `parseMetaData` will contain the following additional properties if
|
976 | IPTC data could be found in the given image:
|
977 |
|
978 | - `iptc`: The parsed IPTC tags
|
979 | - `iptcOffsets`: The parsed IPTC tag offsets
|
980 |
|
981 | The `iptc` object stores the parsed IPTC tags:
|
982 |
|
983 | ```js
|
984 | var objectname = data.iptc[5]
|
985 | ```
|
986 |
|
987 | The `iptc` and `iptcOffsets` objects also provide a `get()` method to retrieve
|
988 | the tag value/offset via the tag's mapped name:
|
989 |
|
990 | ```js
|
991 | var objectname = data.iptc.get('ObjectName')
|
992 | ```
|
993 |
|
994 | By default, only the following names are mapped:
|
995 |
|
996 | - `ObjectName`
|
997 |
|
998 | If you also include the Load Image IPTC Map library, additional tag mappings
|
999 | become available, as well as three additional methods:
|
1000 |
|
1001 | - `iptc.getText()`
|
1002 | - `iptc.getName()`
|
1003 | - `iptc.getAll()`
|
1004 |
|
1005 | ```js
|
1006 | var keywords = data.iptc.getText('Keywords') // e.g.: ['Weather','Sky']
|
1007 |
|
1008 | var name = data.iptc.getName(5) // ObjectName
|
1009 |
|
1010 | // A map of all parsed tags with their mapped names/text as keys/values:
|
1011 | var allTags = data.iptc.getAll()
|
1012 | ```
|
1013 |
|
1014 | #### IPTC parser options
|
1015 |
|
1016 | The IPTC parser adds additional options:
|
1017 |
|
1018 | - `disableIptc`: Disables IPTC parsing when true.
|
1019 | - `disableIptcOffsets`: Disables storing IPTC tag offsets when `true`.
|
1020 | - `includeIptcTags`: A map of IPTC tags to include for parsing (includes all but
|
1021 | the excluded tags by default).
|
1022 | - `excludeIptcTags`: A map of IPTC tags to exclude from parsing (defaults to
|
1023 | exclude `ObjectPreviewData`).
|
1024 |
|
1025 | An example parsing only the `ObjectName` tag:
|
1026 |
|
1027 | ```js
|
1028 | loadImage.parseMetaData(
|
1029 | fileOrBlob,
|
1030 | function (data) {
|
1031 | console.log('IPTC data: ', data.iptc)
|
1032 | },
|
1033 | {
|
1034 | includeIptcTags: {
|
1035 | 5: true // ObjectName
|
1036 | }
|
1037 | }
|
1038 | )
|
1039 | ```
|
1040 |
|
1041 | An example excluding `ApplicationRecordVersion` and `ObjectPreviewData`:
|
1042 |
|
1043 | ```js
|
1044 | loadImage.parseMetaData(
|
1045 | fileOrBlob,
|
1046 | function (data) {
|
1047 | console.log('IPTC data: ', data.iptc)
|
1048 | },
|
1049 | {
|
1050 | excludeIptcTags: {
|
1051 | 0: true, // ApplicationRecordVersion
|
1052 | 202: true // ObjectPreviewData
|
1053 | }
|
1054 | }
|
1055 | )
|
1056 | ```
|
1057 |
|
1058 | ## License
|
1059 |
|
1060 | The JavaScript Load Image library is released under the
|
1061 | [MIT license](https://opensource.org/licenses/MIT).
|
1062 |
|
1063 | ## Credits
|
1064 |
|
1065 | - Original image metadata handling implemented with the help and contribution of
|
1066 | Achim Stöhr.
|
1067 | - Original Exif tags mapping based on Jacob Seidelin's
|
1068 | [exif-js](https://github.com/exif-js/exif-js) library.
|
1069 | - Original IPTC parser implementation by
|
1070 | [Dave Bevan](https://github.com/bevand10).
|