SkillAgentSearch skills...

Exifr

šŸ“· The fastest and most versatile JS EXIF reading library.

Install / Use

/learn @MikeKovarik/Exifr
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<img src="https://raw.githubusercontent.com/MikeKovarik/exifr/master/logo/blue-small.png" width="160" alt="exifr">

Build Status Coverage Status gzip size Dependency Status jsDelivr downloads npm downloads size NPM Version

Usage • Installation • Quick start • Demos • API • Perf • Changelog • FAQ • Contributing

šŸ“· The fastest and most versatile JavaScript EXIF reading library.

Try it yourself - demo page & playground.

Features

<img src="https://raw.githubusercontent.com/MikeKovarik/exifr/master/logo/readme-gif.gif" width="35%" align="right">

Works everywhere, parses anything you throw at it.

  • šŸŽļø Fastest EXIF lib: +-1ms per file
  • šŸ—ƒļø Any input: buffers, url, <img> tag, and more
  • šŸ“· Files: .jpg, .tif, .png, .heic, .avif, .iiq
  • šŸ”Ž Segments: TIFF (EXIF, GPS, etc...), XMP, ICC, IPTC, JFIF, IHDR
  • šŸ“‘ Reads only first few bytes
  • šŸ”¬ Skips parsing tags you don't need
  • ✨ Isomorphic: Browser & Node.js
  • šŸ—œļø No dependencies
  • šŸ–¼ļø Extracts thumbnail
  • šŸ’” Salvages broken files
  • 🧩 Modular
  • šŸ“š Customizable tag dictionaries
  • šŸ“¦ Bundled as UMD/CJS or ESM
  • āœ” Tested and benchmarked
  • šŸ¤™ Promises
  • šŸ•ø Supports even ~IE11~ IE10
<details> <summary>and more (click to expand)</summary> <ul> <li>XMP Parser - minimalistic, reliable, without dependencies</li> <li>XMP Extended</li> <li>Multi-segment ICC</li> <li>Extracts all ICC tags (RedMatrixColumn, GreenTRC, B2A2, etc...)</li> <li>TIFF dictionaries contain less frequently used, non-standard and proprietary TIFF/EXIF tags (only in full bundle)</li> <li>Handles UCS2 formatted strings (XPTitle tag), instead of leaving it as a buffer</li> <li>Normalizes strings</li> <li>Revives dates into Date class instances</li> <li>Converts GPS coords from DMS to DD format. From `<code>GPSLatitude</code>, <code>GPSLatitudeRef</code> tags (<code>[50, 17, 58.57]</code> & <code>"N"</code>) to single <code>latitude</code> value (<code>50.29960</code>).</li> <li>Instructs how to rotate photo with exifr.rotation() and accounts for quirky autorotation behavior of iOs Safari and Chrome 81 and newer</li> </ul> </details>

You don't need to read the whole file to tell if there's EXIF in it. And you don't need to extract all the data when you're looking for just a few tags. Exifr just jumps through the file structure, from pointer to pointer. Instead of reading it byte by byte, from beginning to end.

Exifr does what no other JS lib does. It's efficient and blazing fast!

| Segments | JPEG | TIFF / IIQ | HEIF (HEIC, AVIF) | PNG | |-|-|-|-|-| | EXIF/TIFF, GPS | āœ” | āœ” | āœ” | āœ” | | XMP | āœ” | āœ” | āŒ | āœ” | | IPTC | āœ” | āœ” | āŒ | 🟔 (If it's a part of IHDR) | | ICC | āœ” | āœ” | āœ” | āœ” (Node.js only, requires zlib) | | Thumbnail | āœ” | āŒ | āŒ | āŒ | | JFIF (JPEG header) | āœ” | ⚫ | ⚫ | ⚫ | | IHDR (PNG header) | ⚫ | ⚫ | ⚫ | āœ” |

Usage

file can be any binary format (Buffer, Uint8Array, Blob and more), <img> element, string path or url.

options specify what segments and blocks to parse, filters what tags to pick or skip.

| API | Returns | Description | |-|-|-| |exifr.parse(file)|object|Parses IFD0, EXIF, GPS blocks| |exifr.parse(file, true)|object|Parses everything| |exifr.parse(file, ['Model', 'FNumber', ...])|object|Parses only specified tags| |exifr.parse(file, {options})|object|Custom settings| |exifr.gps(file)|{latitude, longitude}|Parses only GPS coords| |exifr.orientation(file)|number|Parses only orientation| |exifr.rotation(file)|object|Info how to rotate the photo| |exifr.thumbnail(file)|Buffer\|Uint8Array binary|Extracts embedded thumbnail| |exifr.thumbnailUrl(file)|string Object URL|Browser only| |exifr.sidecar(file)|object|Parses sidecar file|

Installation

npm install exifr

Exifr comes in three prebuilt bundles. It's a good idea to start development with full and then scale down to lite, mini, or better yet, build your own around modular core.

// Modern Node.js can import CommonJS
import exifr from 'exifr' // => exifr/dist/full.umd.cjs
// Explicily import ES Module
import exifr from 'exifr/dist/full.esm.mjs' // to use ES Modules
// CommonJS, old Node.js
var exifr = require('exifr') // => exifr/dist/full.umd.cjs
<!-- ES Module in modern browsers -->
<script type="module">import exifr from 'node_modules/exifr/dist/lite.esm.js';</script>
<!-- classic UMD script -->
<script src="https://cdn.jsdelivr.net/npm/exifr/dist/lite.umd.js"></script>
<!-- IE10 & old browsers. You also need Promise polyfill -->
<script src="https://cdn.jsdelivr.net/npm/exifr/dist/lite.legacy.umd.js"></script>

Browsers: lite and mini are recommended because of balance between features and file size. UMD format attaches the library to global window.exifr object.

IE & old browsers: legacy builds come bundled with polyfills. Learn more.

Bundles & formats

  • full - Contains everything. Intended for use in Node.js.
  • lite - Reads JPEG and HEIC. Parses TIFF/EXIF and XMP.
  • mini - Stripped down to basics. Parses most useful TIFF/EXIF from JPEGs. Has no tag dictionaries.

Of course, you can use the full version in browser, or use any other build in Node.js.

  • ESM - Modern syntax for use in modern browsers and Node.js. <br>Uses import syntax.
  • UMD - Universal format for browsers and Node.js. <br>Supports CJS require('exifr'), AMD/RequireJS and global window.exifr.
  • legacy UMD - For use in older browsers (up to IE10). <br>Bundled with polyfills & shims, except for Promise polyfill. Learn more here.
<details> <summary>Detailed comparison (click to expand)</summary>

| | full | lite | mini | core | |-----------------|------|------|------|------| | chunked<br>file readers | BlobReader<br>UrlFetcher (+ Node.js)<br>FsReader<br>Base64Reader | BlobReader<br>UrlFetcher (Browser only) | BlobReader | none | | file parsers | *.jpg<br>*.heic<br>*.tif/*.iiq<br>*.png | *.jpg<br>*.heic | *.jpg | none | | segment<br>parsers | TIFF (EXIF)<br>IPTC<br>XMP<br>ICC<br>JFIF<br>IHDR | TIFF (EXIF)<br>XMP | TIFF (EXIF) | none | | dictionaries | TIFF (+ less frequent tags)<br>IPTC<br>ICC<br>JFIF<br>IHDR | only TIFF keys<br>(IFD0, EXIF, GPS) | none | none | | size +- | 73 Kb | 45 Kb | 29 Kb | 15 Kb | | gzipped | 22 Kb | 12 Kb | 8 Kb | 4 Kb | | file | full.esm.js<br>full.esm.mjs<br>full.umd.js<br>full.umd.cjs<br>full.legacy.umd.js | lite.esm.js<br>lite.esm.mjs<br>lite.umd.js<br>lite.umd.cjs<br>lite.legacy.umd.js | mini.esm.js<br>mini.esm.mjs<br>mini.umd.js<br>mini.umd.cjs<br>mini.legacy.umd.js | Learn more |

</details>

ESM, .js .mjs .cjs extensions, "main", "module", "type":"module"

TL;DR: All bundles are available in two identical copies. .mjs and .js for ESM. .cjs and .js for UMD. Pick one that works with your tooling or webserver.

<details> <summary>(click to expand for more info)</summary>

Current state of ESM is complicated. Node.js can already handle ESM files with .mjs extension and modules with "type":"module" in package.json. Turns out the "type":"module" approach alone is not yet ready for production. Some bundlers and tools may work or break with .mjs extension, whereas it's important for Node.js. The same applies to the new .cjs extension (introduced in Node.js 13).

The library is written in ESM, with .mjs extensions and transpiled to both ESM and UMD formats.

The "main" (field in package.json) entry point is now full.umd.cjs but you can still use ESM by explicitly importing full.esm.mjs. "module" field (used by some tools) points to full.esm.mjs.

If your webserver isn't configured to handle .mjs or .cjs files you can use their identical .js clone. For example full.esm.mjs is identical to full.esm.js. So is lite.esm.cjs to lite.esm.js. Just pick one that fits your tools or environment.

</details>

Named exports vs default export

Exifr exports both named exports and a default export - object containing all the named exports.

You can use import * as exifr from 'exifr' as well as import exifr from 'exifr' (recommended).

Examples

// exifr reads the file from disk, only a few hundred bytes.
exifr.parse('./myimage.jpg')
  .then(output => console.log('Camera:', output.Make, output.Model))
// Or read the file on your own and feed the buffer into exifr.
fs.readFile('./myimage.jpg')
  .then(exifr.parse)
  .then(output => console.log('Camera:', output.Make, output.Model))

Extract only certain tags

// only GPS
let {latitude, longitude} = await exifr.gps('./myimage.jpg')
// only orientation
let num = await exifr.orientation(blob)
// only three tags
let output = await exifr.parse(file, ['ISO', 'Ori
View on GitHub
GitHub Stars1.2k
CategoryDevelopment
Updated9d ago
Forks78

Languages

JavaScript

Security Score

100/100

Audited on Mar 19, 2026

No findings