GitHub - blueimp/JavaScript-Load-Image: Load images provided as File or Blob objects or via URL. Retrieve an optionally scaled, cropped or rotated HTML img or canvas element. Use methods to parse image metadata to extract IPTC and Exif tags as well as embedded thumbnail images, to overwrite the Exif Orientation value and to restore the complete image header after resizing. (original) (raw)

JavaScript Load Image

A JavaScript library to load and transform image files.

Contents

Description

JavaScript Load Image is a library to load images provided as File or Blobobjects or via URL. It returns an optionally scaled, cropped orrotated HTML img or canvas element.

It also provides methods to parse image metadata to extractIPTC andExif tags as well as embedded thumbnail images, to overwrite the Exif Orientation value and to restore the complete image header after resizing.

Setup

Install via NPM:

npm install blueimp-load-image

This will install the JavaScript files inside./node_modules/blueimp-load-image/js/ relative to your current directory, from where you can copy them into a folder that is served by your web server.

Next include the combined and minified JavaScript Load Image script in your HTML markup:

Or alternatively, choose which components you want to include:

Usage

Image loading

In your application code, use the loadImage() function withcallback style:

document.getElementById('file-input').onchange = function () { loadImage( this.files[0], function (img) { document.body.appendChild(img) }, { maxWidth: 600 } // Options ) }

Or use the Promise based API like this (requires a polyfill for older browsers):

document.getElementById('file-input').onchange = function () { loadImage(this.files[0], { maxWidth: 600 }).then(function (data) { document.body.appendChild(data.image) }) }

Withasync/await(requires a modern browser or a code transpiler likeBabel or TypeScript):

document.getElementById('file-input').onchange = async function () { let data = await loadImage(this.files[0], { maxWidth: 600 }) document.body.appendChild(data.image) }

Image scaling

It is also possible to use the image scaling functionality directly with an existing image:

var scaledImage = loadImage.scale( img, // img or canvas element { maxWidth: 600 } )

Requirements

The JavaScript Load Image library has zero dependencies, but benefits from the following twopolyfills:

Browser support

Browsers which implement the following APIs support all options:

This includes (but is not limited to) the following browsers:

* Internet Explorer requires a polyfill for the Promisebased API.

Loading an image from a URL and applying transformations (scaling, cropping and rotating - except orientation:true, which requires reading meta data) is supported by all browsers which implement theHTMLCanvasElementinterface.

Loading an image from a URL and scaling it in size is supported by all browsers which implement theimg element and has been tested successfully with browser engines as old as Internet Explorer 5 (viaIE11's emulation mode).

The loadImage() function applies options usingprogressive enhancementand falls back to a configuration that is supported by the browser, e.g. if thecanvas element is not supported, an equivalent img element is returned.

API

Callback

Function signature

The loadImage() function accepts aFile orBlob object or an image URL as first argument.

If a File orBlob is passed as parameter, it returns an HTML img element if the browser supports theURL API, alternatively aFileReader object if the FileReader API is supported, or false.

It always returns an HTMLimg element when passing an image URL:

var loadingImage = loadImage( 'https://example.org/image.png', function (img) { document.body.appendChild(img) }, { maxWidth: 600 } )

Cancel image loading

Some browsers (e.g. Chrome) will cancel the image loading process if the srcproperty of an img element is changed.
To avoid unnecessary requests, we can use thedata URLof a 1x1 pixel transparent GIF image as src target to cancel the original image download.

To disable callback handling, we can also unset the image event handlers and for maximum browser compatibility, cancel the file reading process if the returned object is aFileReaderinstance:

var loadingImage = loadImage( 'https://example.org/image.png', function (img) { document.body.appendChild(img) }, { maxWidth: 600 } )

if (loadingImage) { // Unset event handling for the loading image: loadingImage.onload = loadingImage.onerror = null

// Cancel image loading process: if (loadingImage.abort) { // FileReader instance, stop the file reading process: loadingImage.abort() } else { // HTMLImageElement element, cancel the original image request by changing // the target source to the data URL of a 1x1 pixel transparent image GIF: loadingImage.src = 'data:image/gif;base64,' + 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' } }

Please note:
The img element (or FileReader instance) for the loading image is only returned when using the callback style API and not available with thePromise based API.

Callback arguments

For the callback style API, the second argument to loadImage() must be acallback function, which is called when the image has been loaded or an error occurred while loading the image.

The callback function is passed two arguments:

  1. An HTML imgelement orcanvaselement, or anEvent object of type error.
  2. An object with the original image dimensions as properties and potentially additional metadata.

loadImage( fileOrBlobOrUrl, function (img, data) { document.body.appendChild(img) console.log('Original image width: ', data.originalWidth) console.log('Original image height: ', data.originalHeight) }, { maxWidth: 600, meta: true } )

Please note:
The original image dimensions reflect the natural width and height of the loaded image before applying any transformation.
For consistent values across browsers, metadata parsing has to be enabled via meta:true, so loadImage can detect automatic image orientation and normalize the dimensions.

Error handling

Example code implementing error handling:

loadImage( fileOrBlobOrUrl, function (img, data) { if (img.type === 'error') { console.error('Error loading image file') } else { document.body.appendChild(img) } }, { maxWidth: 600 } )

Promise

If the loadImage() function is called without a callback function as second argument and thePromiseAPI is available, it returns a Promise object:

loadImage(fileOrBlobOrUrl, { maxWidth: 600, meta: true }) .then(function (data) { document.body.appendChild(data.image) console.log('Original image width: ', data.originalWidth) console.log('Original image height: ', data.originalHeight) }) .catch(function (err) { // Handling image loading errors console.log(err) })

The Promise resolves with an object with the following properties:

Please also read the note about original image dimensions normalization in thecallback arguments section.

If metadata has been parsed, additional properties might be present on the object.

If image loading fails, the Promise rejects with anEvent object of typeerror.

Options

The optional options argument to loadImage() allows to configure the image loading.

It can be used the following way with the callback style:

loadImage( fileOrBlobOrUrl, function (img) { document.body.appendChild(img) }, { maxWidth: 600, maxHeight: 300, minWidth: 100, minHeight: 50, canvas: true } )

Or the following way with the Promise based API:

loadImage(fileOrBlobOrUrl, { maxWidth: 600, maxHeight: 300, minWidth: 100, minHeight: 50, canvas: true }).then(function (data) { document.body.appendChild(data.image) })

All settings are optional. By default, the image is returned as HTML imgelement without any image size restrictions.

maxWidth

Defines the maximum width of the img/canvas element.

maxHeight

Defines the maximum height of the img/canvas element.

minWidth

Defines the minimum width of the img/canvas element.

minHeight

Defines the minimum height of the img/canvas element.

sourceWidth

The width of the sub-rectangle of the source image to draw into the destination canvas.
Defaults to the source image width and requires canvas: true.

sourceHeight

The height of the sub-rectangle of the source image to draw into the destination canvas.
Defaults to the source image height and requires canvas: true.

top

The top margin of the sub-rectangle of the source image.
Defaults to 0 and requires canvas: true.

The right margin of the sub-rectangle of the source image.
Defaults to 0 and requires canvas: true.

bottom

The bottom margin of the sub-rectangle of the source image.
Defaults to 0 and requires canvas: true.

left

The left margin of the sub-rectangle of the source image.
Defaults to 0 and requires canvas: true.

contain

Scales the image up/down to contain it in the max dimensions if set to true.
This emulates the CSS featurebackground-image: contain.

cover

Scales the image up/down to cover the max dimensions with the image dimensions if set to true.
This emulates the CSS featurebackground-image: cover.

aspectRatio

Crops the image to the given aspect ratio (e.g. 16/9).
Setting the aspectRatio also enables the crop option.

pixelRatio

Defines the ratio of the canvas pixels to the physical image pixels on the screen.
Should be set towindow.devicePixelRatiounless the scaled image is not rendered on screen.
Defaults to 1 and requires canvas: true.

downsamplingRatio

Defines the ratio in which the image is downsampled (scaled down in steps).
By default, images are downsampled in one step.
With a ratio of 0.5, each step scales the image to half the size, before reaching the target dimensions.
Requires canvas: true.

imageSmoothingEnabled

If set to false,disables image smoothing.
Defaults to true and requires canvas: true.

imageSmoothingQuality

Sets thequality of image smoothing.
Possible values: 'low', 'medium', 'high'
Defaults to 'low' and requires canvas: true.

crop

Crops the image to the maxWidth/maxHeight constraints if set to true.
Enabling the crop option also enables the canvas option.

orientation

Transform the canvas according to the specified Exif orientation, which can be an integer in the range of 1 to 8 or the boolean value true.

When set to true, it will set the orientation value based on the Exif data of the image, which will be parsed automatically if the Exif extension is available.

Exif orientation values to correctly display the letter F:

    1             2
  ██████        ██████
  ██                ██
  ████            ████
  ██                ██
  ██                ██

    3             4
      ██        ██
      ██        ██
    ████        ████
      ██        ██
  ██████        ██████

    5             6
██████████    ██
██  ██        ██  ██
██            ██████████

    7             8
        ██    ██████████
    ██  ██        ██  ██
██████████            ██

Setting orientation to true enables the canvas and meta options, unless the browser supports automatic image orientation (seebrowser support for image-orientation).

Setting orientation to 1 enables the canvas and meta options if the browser does support automatic image orientation (to allow reset of the orientation).

Setting orientation to an integer in the range of 2 to 8 always enables the canvas option and also enables the meta option if the browser supports automatic image orientation (again to allow reset).

meta

Automatically parses the image metadata if set to true.

If metadata has been found, the data object passed as second argument to the callback function has additional properties (seemetadata parsing).

If the file is given as URL and the browser supports thefetch API or the XHRresponseType blob, fetches the file as Blob to be able to parse the metadata.

canvas

Returns the image ascanvas element if set to true.

crossOrigin

Sets the crossOrigin property on the img element for loadingCORS enabled images.

noRevoke

By default, thecreated object URLis revoked after the image has been loaded, except when this option is set totrue.

Metadata parsing

If the Load Image Meta extension is included, it is possible to parse image meta data automatically with the meta option:

loadImage( fileOrBlobOrUrl, function (img, data) { console.log('Original image head: ', data.imageHead) console.log('Exif data: ', data.exif) // requires exif extension console.log('IPTC data: ', data.iptc) // requires iptc extension }, { meta: true } )

Or alternatively via loadImage.parseMetaData, which can be used with an available File or Blob object as first argument:

loadImage.parseMetaData( fileOrBlob, function (data) { console.log('Original image head: ', data.imageHead) console.log('Exif data: ', data.exif) // requires exif extension console.log('IPTC data: ', data.iptc) // requires iptc extension }, { maxMetaDataSize: 262144 } )

Or using thePromisebased API:

loadImage .parseMetaData(fileOrBlob, { maxMetaDataSize: 262144 }) .then(function (data) { console.log('Original image head: ', data.imageHead) console.log('Exif data: ', data.exif) // requires exif extension console.log('IPTC data: ', data.iptc) // requires iptc extension })

The Metadata extension adds additional options used for the parseMetaDatamethod:

Image head

Resized JPEG images can be combined with their original image head vialoadImage.replaceHead, which requires the resized image as Blob object as first argument and an ArrayBuffer image head as second argument.

With callback style, the third argument must be a callback function, which is called with the new Blob object:

loadImage( fileOrBlobOrUrl, function (img, data) { if (data.imageHead) { img.toBlob(function (blob) { loadImage.replaceHead(blob, data.imageHead, function (newBlob) { // do something with the new Blob object }) }, 'image/jpeg') } }, { meta: true, canvas: true, maxWidth: 800 } )

Or using thePromisebased API like this:

loadImage(fileOrBlobOrUrl, { meta: true, canvas: true, maxWidth: 800 }) .then(function (data) { if (!data.imageHead) throw new Error('Could not parse image metadata') return new Promise(function (resolve) { data.image.toBlob(function (blob) { data.blob = blob resolve(data) }, 'image/jpeg') }) }) .then(function (data) { return loadImage.replaceHead(data.blob, data.imageHead) }) .then(function (blob) { // do something with the new Blob object }) .catch(function (err) { console.error(err) })

Please note:
Blob objects of resized images can be created viaHTMLCanvasElement.toBlob.
blueimp-canvas-to-blobprovides a polyfill for browsers without native canvas.toBlob() support.

Exif parser

If you include the Load Image Exif Parser extension, the argument passed to the callback for parseMetaData will contain the following additional properties if Exif data could be found in the given image:

The exif object stores the parsed Exif tags:

var orientation = data.exif[0x0112] // Orientation

The exif and exifOffsets objects also provide a get() method to retrieve the tag value/offset via the tag's mapped name:

var orientation = data.exif.get('Orientation') var orientationOffset = data.exifOffsets.get('Orientation')

By default, only the following names are mapped:

If you also include the Load Image Exif Map library, additional tag mappings become available, as well as three additional methods:

var orientationText = data.exif.getText('Orientation') // e.g. "Rotate 90° CW"

var name = data.exif.getName(0x0112) // "Orientation"

// A map of all parsed tags with their mapped names/text as keys/values: var allTags = data.exif.getAll()

Exif Thumbnail

Example code displaying a thumbnail image embedded into the Exif metadata:

loadImage( fileOrBlobOrUrl, function (img, data) { var exif = data.exif var thumbnail = exif && exif.get('Thumbnail') var blob = thumbnail && thumbnail.get('Blob') if (blob) { loadImage( blob, function (thumbImage) { document.body.appendChild(thumbImage) }, { orientation: exif.get('Orientation') } ) } }, { meta: true } )

Exif IFD

Example code displaying data from the Exif IFD (Image File Directory) that contains Exif specified TIFF tags:

loadImage( fileOrBlobOrUrl, function (img, data) { var exifIFD = data.exif && data.exif.get('Exif') if (exifIFD) { // Map of all Exif IFD tags with their mapped names/text as keys/values: console.log(exifIFD.getAll()) // A specific Exif IFD tag value: console.log(exifIFD.get('UserComment')) } }, { meta: true } )

GPSInfo IFD

Example code displaying data from the Exif IFD (Image File Directory) that contains GPS info:

loadImage( fileOrBlobOrUrl, function (img, data) { var gpsInfo = data.exif && data.exif.get('GPSInfo') if (gpsInfo) { // Map of all GPSInfo tags with their mapped names/text as keys/values: console.log(gpsInfo.getAll()) // A specific GPSInfo tag value: console.log(gpsInfo.get('GPSLatitude')) } }, { meta: true } )

Interoperability IFD

Example code displaying data from the Exif IFD (Image File Directory) that contains Interoperability data:

loadImage( fileOrBlobOrUrl, function (img, data) { var interoperabilityData = data.exif && data.exif.get('Interoperability') if (interoperabilityData) { // The InteroperabilityIndex tag value: console.log(interoperabilityData.get('InteroperabilityIndex')) } }, { meta: true } )

Exif parser options

The Exif parser adds additional options:

An example parsing only Orientation, Thumbnail and ExifVersion tags:

loadImage.parseMetaData( fileOrBlob, function (data) { console.log('Exif data: ', data.exif) }, { includeExifTags: { 0x0112: true, // Orientation ifd1: { 0x0201: true, // JPEGInterchangeFormat (Thumbnail data offset) 0x0202: true // JPEGInterchangeFormatLength (Thumbnail data length) }, 0x8769: { // ExifIFDPointer 0x9000: true // ExifVersion } } } )

An example excluding Exif MakerNote and GPSInfo:

loadImage.parseMetaData( fileOrBlob, function (data) { console.log('Exif data: ', data.exif) }, { excludeExifTags: { 0x8769: { // ExifIFDPointer 0x927c: true // MakerNote }, 0x8825: true // GPSInfoIFDPointer } } )

Exif writer

The Exif parser extension also includes a minimal writer that allows to override the Exif Orientation value in the parsed imageHead ArrayBuffer:

loadImage( fileOrBlobOrUrl, function (img, data) { if (data.imageHead && data.exif) { // Reset Exif Orientation data: loadImage.writeExifData(data.imageHead, data, 'Orientation', 1) img.toBlob(function (blob) { loadImage.replaceHead(blob, data.imageHead, function (newBlob) { // do something with newBlob }) }, 'image/jpeg') } }, { meta: true, orientation: true, canvas: true, maxWidth: 800 } )

Please note:
The Exif writer relies on the Exif tag offsets being available asdata.exifOffsets property, which requires that Exif data has been parsed from the image.
The Exif writer can only change existing values, not add new tags, e.g. it cannot add an Exif Orientation tag for an image that does not have one.

IPTC parser

If you include the Load Image IPTC Parser extension, the argument passed to the callback for parseMetaData will contain the following additional properties if IPTC data could be found in the given image:

The iptc object stores the parsed IPTC tags:

var objectname = data.iptc[5]

The iptc and iptcOffsets objects also provide a get() method to retrieve the tag value/offset via the tag's mapped name:

var objectname = data.iptc.get('ObjectName')

By default, only the following names are mapped:

If you also include the Load Image IPTC Map library, additional tag mappings become available, as well as three additional methods:

var keywords = data.iptc.getText('Keywords') // e.g.: ['Weather','Sky']

var name = data.iptc.getName(5) // ObjectName

// A map of all parsed tags with their mapped names/text as keys/values: var allTags = data.iptc.getAll()

IPTC parser options

The IPTC parser adds additional options:

An example parsing only the ObjectName tag:

loadImage.parseMetaData( fileOrBlob, function (data) { console.log('IPTC data: ', data.iptc) }, { includeIptcTags: { 5: true // ObjectName } } )

An example excluding ApplicationRecordVersion and ObjectPreviewData:

loadImage.parseMetaData( fileOrBlob, function (data) { console.log('IPTC data: ', data.iptc) }, { excludeIptcTags: { 0: true, // ApplicationRecordVersion 202: true // ObjectPreviewData } } )

License

The JavaScript Load Image library is released under theMIT license.

Credits