@colorhythm/exiftool-wasm
Built with ExifTool 13.62 · wrapper 1.0.7.
ExifTool powered by WebAssembly to extract and write metadata from files in browsers and Node.js environments using zeroperl.
Installation
npm install @colorhythm/exiftool-wasm
Description
This package provides a WebAssembly-based implementation of ExifTool that works in both browser and Node.js environments. It leverages zeroperl to execute ExifTool without requiring any native binaries or system dependencies.
Usage
Basic Usage
import { parseMetadata } from '@colorhythm/exiftool-wasm';
// Browser usage with File API
document.querySelector('input[type="file"]').addEventListener('change', async (event) => {
const file = event.target.files[0];
const result = await parseMetadata(file);
if (result.success) {
console.log(result.data);
} else {
console.error('Error:', result.error);
}
});
Writing Metadata
import { writeMetadata } from '@colorhythm/exiftool-wasm';
const result = await writeMetadata(file, {
'Author': 'John Doe',
'Title': 'My Photo',
'Keywords': 'nature,photography'
});
if (result.success) {
// result.data contains the modified file as Uint8Array
const modifiedBlob = new Blob([result.data]);
}
Extracting Specific Metadata
import { parseMetadata } from '@colorhythm/exiftool-wasm';
const result = await parseMetadata(file, {
args: ['-Author', '-CreateDate', '-Make', '-Model']
});
if (result.success) {
console.log(result.data);
}
JSON Output
import { parseMetadata } from '@colorhythm/exiftool-wasm';
const result = await parseMetadata(file, {
args: ['-json', '-n'],
transform: (data) => JSON.parse(data)
});
if (result.success) {
// Typed access to properties
console.log(result.data); // { ... }
}
Extracting Embedded Binaries
Pass binary: true to receive stdout as a raw Uint8Array — required for
ExifTool's -b output (embedded thumbnails/previews, MPF images and HDR
gain maps, depth maps, ICC profiles, trailer payloads), which is not UTF-8
and would be corrupted by text decoding.
import { parseMetadata } from '@colorhythm/exiftool-wasm';
const result = await parseMetadata(file, {
// -m ignores minor warnings, -q suppresses info messages — recommended,
// since any stderr output is treated as failure.
args: ['-b', '-ThumbnailImage', '-m', '-q'],
binary: true,
});
if (result.success) {
const blob = new Blob([result.data], { type: 'image/jpeg' });
// result.data is a byte-exact Uint8Array
}
Notes:
transformis not applied in binary mode.- Extracting multiple
-btags in one call concatenates their bytes on stdout with no delimiter — extract one tag per call, or useargs: ['-json', '-b', ...](withoutbinary) to get each tag as abase64:-prefixed string in JSON.
Important Notes
- In browser environments, pass the
Fileobject directly from file inputs. Do not convert it to an ArrayBuffer or Uint8Array. - This package uses asynchronous web APIs for file processing which allows handling files without loading the entire input into memory. Files over 2 GB are not covered by the automated release gate; runtime and format limitations still apply.
- ExifTool is executed entirely within the browser or Node.js environment - no server requests are made for metadata extraction.
API Reference
parseMetadata()
async function parseMetadata<TReturn = string>(
file: Binaryfile | File,
options: ExifToolOptions<TReturn> = {}
): Promise<ExifToolOutput<TReturn>>
Parameters
file: Either a browserFileobject or aBinaryfileobject withnameanddataproperties.options: Configuration options for the metadata extraction.
writeMetadata()
async function writeMetadata(
file: Binaryfile | File,
tags: ExifTags,
options: ExifToolOptions = {}
): Promise<ExifToolOutput<ArrayBuffer>>
Parameters
file: Either a browserFileobject or aBinaryfileobject withnameanddataproperties.tags: Object containing metadata tags to write, where keys are tag names and values are tag values.options: Configuration options for the write operation.
Return Value
Returns a Promise that resolves to an ExifToolOutput object:
type ExifToolOutput<TOutput> =
| {
success: true;
data: TOutput;
error: string;
exitCode: 0;
}
| {
success: false;
data: undefined;
error: string;
exitCode: number | undefined;
};
Build and verify
The package vendors its zeroperl-ts adapter. Its binary-output and Worker fixes are intentional; an update must not replace that source wholesale with the standalone zeroperl-ts package.
Use Node.js 24 and Bun 1.3.10:
npm ci
bun run build
npm test
build removes previous output before emitting declarations and the browser ESM
bundle. The paired src/exiftool and src/zeroperl/zeroperl.wasm inputs come from
a single build of zeroperl. Immutable
runtime and companion-test revisions are recorded in release-config.json.
For full release validation, supply an extracted official ExifTool source tree whose archive checksum has been verified:
npx playwright install chrome webkit
EXIFTOOL_VERSION=$(node -p "require('./exiftool-build.json').upstream.version")
npm run test:release -- --expected-version "$EXIFTOOL_VERSION" \
--source "/absolute/path/to/Image-ExifTool-$EXIFTOOL_VERSION" \
--output /absolute/path/to/release-evidence
This packs the actual npm artifact, tests it in Node and in browser Window and
module Worker contexts, and compares metadata against native ExifTool. Required
checks include custom -config tags, exact binary bytes, Unicode write/read,
unchanged input bytes, default WASM asset loading, and MacRoman QuickTime tags.
Browser automation covers Chrome and Playwright WebKit. Actual Safari,
Firefox, and files over 2 GB are not release-gate coverage.
Version identity and automatic releases
Starting with the automated releases, each npm tarball includes
exiftool-build.json, exported as @colorhythm/exiftool-wasm/build-info. It
records the exact ExifTool version, official source checksum and Git revision,
Perl version, build repository revisions, workflow URL, and packaged-file hashes.
The npm package version identifies our wrapper release separately from Phil's
ExifTool version. CLI -ver returns the exact runtime version string; JSON
metadata uses a number and may drop trailing zeros.
The private release controller
dispatches a check hourly at minute 23 when activated. The public release
workflow also supports manual dispatch.
It publishes automatically only after all validation passes and the repository
variable EXIFTOOL_AUTO_PUBLISH is true. The exact tested tarball is published,
then downloaded from npm and checked before a release tag is created. A build
pin or source commit alone is never treated as proof of publication.
See release operations for activation, retries, provenance, and controller configuration.
Acknowledgments
This package stands on the shoulders of three projects, with our thanks:
- ExifTool by Phil Harvey — three decades of metadata craft; his engine supplies the metadata interpretation.
- uswriting/exiftool by Andrew Sampson — the original ExifTool-in-WebAssembly wrapper this package is forked from.
- zeroperl (6over3 / Andrew Sampson) — the sandboxed Perl-to-WASI runtime that makes running ExifTool in a browser possible at all.
Our fork adds byte-safe binary extraction (binary: true), Worker-scope
support, -config-first handling, and packaging fixes — see the commit
history.
License
Apache License, Version 2.0