Strips metadata (EXIF, XMP, IPTC, comments) from image and video buffers. Takes an ArrayBuffer, returns a Uint8Array.
npm install @faffweasel/strip-metadata
import { stripMetadata } from '@faffweasel/strip-metadata';
const input: ArrayBuffer = await file.arrayBuffer();
const result = stripMetadata(input);
console.log(result.format); // e.g. 'jpeg'
console.log(result.originalSize); // bytes before stripping
console.log(result.strippedSize); // bytes after stripping
// result.data is a Uint8Array ready to upload or write
const blob = new Blob([result.data]);stripMetadata throws if the format is not recognised or the file is malformed.
Detects the format, strips metadata in one pass, and returns a StripResult. Throws Error on unsupported or malformed input.
Returns the detected format string, or null if the buffer does not match any supported format. Uses magic bytes only; does not validate the full file structure.
interface StripResult {
data: Uint8Array; // stripped file bytes
format: MediaFormat; // detected format
originalSize: number; // buffer.byteLength before stripping
strippedSize: number; // data.byteLength after stripping
}type MediaFormat = 'jpeg' | 'png' | 'webp' | 'heic' | 'avif' | 'gif' | 'mp4' | 'mov';| Format | Detection |
|---|---|
| JPEG | FF D8 FF magic bytes |
| PNG | 89 50 4E 47 0D 0A 1A 0A magic bytes |
| WebP | RIFF....WEBP magic bytes |
| HEIC | ISOBMFF ftyp box: heic, heix, hevc, hevx, heim, heis brands |
| AVIF | ISOBMFF ftyp box: avif, avis brands |
| GIF | GIF87a / GIF89a magic bytes |
| MP4 | ISOBMFF ftyp box: isom, iso2–iso6, mp41, mp42, M4V , M4A , f4v , dash, avc1 brands |
| MOV | ISOBMFF ftyp box: qt brand |
| Format | Removed |
|---|---|
| JPEG | APP1 (EXIF), APP13 (IPTC/Photoshop), COM (comments), non-ICC APP2 segments (MPF, gain maps) |
| PNG | tEXt, iTXt, zTXt (text metadata), eXIf (EXIF), tIME (timestamp), dSIG (digital signature) |
| WebP | EXIF chunk, XMP chunk; Exif and XMP flags cleared in VP8X header |
| HEIC / AVIF | Exif items and application/rdf+xml (XMP) items from the ISOBMFF meta box; iinf, iloc, and iref boxes rebuilt accordingly; absolute offsets adjusted |
| GIF | Comment extensions (0xFE), Plain Text extensions (0x01), XMP application extensions, all other unrecognised application extensions |
| MP4 / MOV | udta and meta boxes from moov and each trak; top-level free boxes; XMP uuid boxes; stco/co64 chunk offsets adjusted |
| Format | Preserved |
|---|---|
| JPEG | ICC profiles (APP2 segments with ICC_PROFILE\0 identifier), SOF/SOS/DQT/DHT and all other non-metadata segments, entropy-coded scan data |
| PNG | IHDR, IDAT, PLTE, IEND, and all other ancillary chunks not listed above |
| WebP | VP8, VP8L, VP8X, ICCP, ANIM, ANMF, and all other non-metadata chunks |
| HEIC / AVIF | All image item data; mdat content untouched |
| GIF | Graphics Control Extensions (animation timing and disposal), NETSCAPE2.0 and ANIMEXTS1.0 application extensions (loop count), all image descriptors and frame data |
| MP4 / MOV | All audio/video sample data (mdat), codec configuration, all other moov child boxes |
No browser APIs. No Node.js APIs. Pure ArrayBuffer and Uint8Array throughout.
Works in any environment that supports the ECMAScript standard library: browsers, Node.js, Deno, Bun, Cloudflare Workers, and other runtimes.
AGPL-3.0. See LICENCE.