Skip to content

faffweasel/strip-metadata

Repository files navigation

@faffweasel/strip-metadata

Strips metadata (EXIF, XMP, IPTC, comments) from image and video buffers. Takes an ArrayBuffer, returns a Uint8Array.

Install

npm install @faffweasel/strip-metadata

Usage

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.

API

stripMetadata(buffer: ArrayBuffer): StripResult

Detects the format, strips metadata in one pass, and returns a StripResult. Throws Error on unsupported or malformed input.

detectFormat(buffer: ArrayBuffer): MediaFormat | null

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.

StripResult

interface StripResult {
  data: Uint8Array;       // stripped file bytes
  format: MediaFormat;    // detected format
  originalSize: number;   // buffer.byteLength before stripping
  strippedSize: number;   // data.byteLength after stripping
}

MediaFormat

type MediaFormat = 'jpeg' | 'png' | 'webp' | 'heic' | 'avif' | 'gif' | 'mp4' | 'mov';

Supported formats

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, iso2iso6, mp41, mp42, M4V , M4A , f4v , dash, avc1 brands
MOV ISOBMFF ftyp box: qt brand

What gets stripped

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

What gets preserved

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

Compatibility

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.

Licence

AGPL-3.0. See LICENCE.


faffweasel.com

Packages

 
 
 

Contributors