Exifr
š· The fastest and most versatile JS EXIF reading library.
Install / Use
/learn @MikeKovarik/ExifrREADME
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
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
importsyntax. - UMD - Universal format for browsers and Node.js.
<br>Supports CJS
require('exifr'), AMD/RequireJS and globalwindow.exifr. - legacy UMD - For use in older browsers (up to IE10).
<br>Bundled with polyfills & shims, except for
Promisepolyfill. Learn more here.
| | 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 |
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.
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.
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
