SkillAgentSearch skills...

ExifReader

A JavaScript Exif info parser.

Install / Use

/learn @mattiasw/ExifReader
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

ExifReader

ExifReader is a JavaScript library that parses image files and extracts the metadata. It can also extract an embedded thumbnail. It can be used either in a browser or from Node. Supports JPEG, TIFF, PNG, HEIC, AVIF, WebP, and GIF files with Exif, IPTC, XMP, ICC, MPF, and more metadata (depending on file type).

ExifReader is highly and easily configurable and the resulting bundle can be as small as ~4 KiB (gzipped) if you're only interested in a few tags (e.g. date and/or GPS values).

ExifReader supports module formats ESM, AMD, CommonJS, and globals and can therefore easily be used from Webpack, RequireJS, Browserify, Node etc.

You can try it out on the examples site.

Support table

| File type | Exif | IPTC | XMP | ICC | MPF | Photoshop | MakerNote | Thumbnail | Image details | | ----------|---------|---------|---------|---------|---------|---------------|--------------------|-----------|---------------| | JPEG | yes | yes | yes | yes | yes | some* | some** | yes | yes | | TIFF | yes | yes | yes | yes | ??? | some* | some** | N/A | N/A | | PNG | yes | yes | yes | yes | ??? | ??? | some** | no | yes | | HEIC/HEIF | yes | no | yes | yes | ??? | ??? | some** | yes | no | | AVIF | yes | no | yes | yes | ??? | ??? | some** | yes | no | | WebP | yes | no | yes | yes | ??? | ??? | some** | yes | yes | | GIF | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | yes |

  • MakerNote = Manufacturers' proprietary MakerNote tags.
  • Image details = image width, height, etc. read from image header.
  • N/A = The feature is not applicable to this file type.
  • ??? = may be supported in any file type using Exif but it has only been tested on JPEGs.
  • * = A draft implementation of Photoshop tags have been added with ClippingPathName and PathInformation currently supported. Photoshop tags are very different from other tags and need a lot of extra code so they have deliberately not been fully implemented. File an issue if there is something you think should really be supported.
  • ** = Some of the Canon-specific and Pentax-specific tags have been added. File an issue if you think something more should be supported.

If you're missing something that you think should be supported, file an issue with an attached example image and I'll see what I can do.

Notes for exif-js users

If you come here from the popular but now dead exif-js package, please let me know if you're missing anything from it and I will try to help you. Some notes:

  • ExifReader has a different API, hopefully better. :-)
  • XMP support in exif-js does not seem perfect. ExifReader should be a bit better on that part.
  • ExifReader works with strict mode.
  • I've been maintaining this package since 2012 and I have no plans to stop doing that anytime soon.

Table of Contents

  1. Support
  2. Installation
  3. Usage
  4. Configure a Custom Build
  5. Notes
  6. Client/Browser Support
  7. Examples
  8. Tips
  9. Known Limitations
  10. Contributing
  11. Code of Conduct
  12. License
  13. Changelog

Support

Monetary support is not necessary for me to continue working on this, but in case you like this library and want to support its development you are very welcome to click the button below. You can also use GitHub's sponsor feature on the right-hand side on the repository's main page.

<a href="https://www.buymeacoffee.com/mattiasw" target="_blank"> <img src="https://cdn.buymeacoffee.com/buttons/v2/default-violet.png" alt="Buy me a coffee" width="181" height="50"> </a>

Installation

Easiest is through npm or Bower:

npm install exifreader --save
bower install exifreader --save

If you want to clone the git repository instead:

git clone git@github.com:mattiasw/ExifReader.git
cd ExifReader
npm install

After that, the transpiled, concatenated and minified ES5 file will be in the dist folder together with a sourcemap file.

Type definitions

Type definitions for TypeScript are included in the package.

Usage

Importing

NOTE: See React Native instructions below.

ES module syntax:

import ExifReader from 'exifreader';

NOTE: TypeScript/Angular seems to sometimes have problems when using the default export. If you're seeing issues, use this syntax instead:

import * as ExifReader from 'exifreader';

CommonJS/Node modules:

const ExifReader = require('exifreader');

AMD modules:

requirejs(['/path/to/exif-reader.js'], function (ExifReader) {
    ...
});

script tag:

<script src="/path/to/exif-reader.js"></script>

Loading tags

There are two ways to load the tags. Either have ExifReader do the loading of the image file, or load the file yourself first and pass in the file buffer. The main difference is that the first one is asynchronous and the second one is synchronous unless specified.

Let ExifReader load the file (asynchronous API)

const tags = await ExifReader.load(file);
const imageDate = tags['DateTimeOriginal'].description;
const unprocessedTagValue = tags['DateTimeOriginal'].value;

Where file is one of

  • File object, the result of a form file upload (browser)
  • File path on a local file system (Node.js)
  • URL (browser or Node.js; remember that in a browser context the remote server has to set CORS headers that allow for remote loading of the file)

Tip: To read metadata from an HTMLImageElement, wait for its load event and call ExifReader.load(image.src). The browser should reuse the cached file.

Load the file yourself (synchronous API)

const tags = ExifReader.load(fileBuffer);

Where fileBuffer is one of

  • ArrayBuffer or SharedArrayBuffer (browser, Node.js)
  • Buffer (Node.js)

See the examples site for more directions on how to use the library.

Asynchronous tags

Some tags need to be parsed asynchronously. Currently this is the case for some PNG tags, more specifically compressed tags in zTXt, iTXt, and iCCP chunks. To enable this, either use the asynchronous API mentioned above or pass in async: true in the options parameter:

const tags = await ExifReader.load(file);
// or
const tags = await ExifReader.load(fileBuffer, {async: true});

For the compressed tags to work, the environment needs to support the Compression Streams API.

The reason for having an option to enable this is to not break backwards compatibility. This will probably be the default in the next major version.

Grouping

By default, Exif, IPTC and XMP tags are grouped together. This means that if e.g. Orientation exists in both Exif and XMP, the first value (Exif) will be overwritten by the second (XMP). If you need to separate between these values, pass in an options object with the property expanded set to true:

const tags = ExifReader.load(fileBuffer, {expanded: true});

Parsing XMP tags when not in a DOM environment

When using for example Node.js or a web worker, there is no native DOMParser available for parsing the XML used in XMP. In this case – and if XMP support is important to you – you can pass in a third-party parser to ExifReader. The parser needs to have a parseFromString method with the same API as the parseFromString from the DOMParser Web API.

Two libraries have been tested, xmldom and linkedom, but more might work if they follow the spec.

Here is an example using xmldom:

import {DOMParser, onErrorStopParsing} from '@xmldom/xmldom';
// ...
const tags = ExifReader.load(fileBuffer, {domParser: new DOMParser({onError: onErrorStopParsing})});

The onError option is needed to avoid a seemingly infinite loop for some XMLs. Unfortunately linkedom has the same problem but does not have this option and will therefore get stuck on these XMLs. If this happens to you, switch to xmldom and pass in the onError option. (NOTE: The native DOMParser that a web browser uses does not seem to have this issue.)

Using React Native

Import ExifReader like this:

import ExifReader from './node_modules/exifreader/src/exif-reader.js';

Make sure to update the path to point to where your node_modules is located.

For local files on the device you need to load the file yourself first, then pass in the buffer to ExifReader. Here is a template from user @hungdev:

import RNFS from 'react-native-fs';
import {decode} from 'base64-arraybuffer';
import ExifReader from 'exifreader';

const b64Buffer = await RNFS.readFile('YOUR IMAGE URI', 'base64') // Where the URI looks like this: "file:///path/to/image/IMG_0123.HEIC"
const fileBuffer = decode(b64Buffer)
const tags = ExifReader.load(fileBuffer, {expanded: true});

Related Skills

View on GitHub
GitHub Stars960
CategoryDevelopment
Updated2d ago
Forks104

Languages

JavaScript

Security Score

95/100

Audited on Mar 26, 2026

No findings