image-meta
Detect image type, dimensions, and orientation from raw bytes using pure JavaScript.
Repository Health
Technical Analysis
image-meta is a zero-dependency TypeScript library from the UnJS ecosystem that inspects the raw bytes of an image buffer and returns its format, width, height, and (for JPEGs) EXIF orientation, without ever touching the file extension. It operates directly on a Uint8Array, so it runs identically in Node.js, Deno, Bun, and the browser, and ships as a dual ESM/CJS build produced with unbuild.
Under the hood it is an explicit fork of the long-standing image-size project, rewritten in modern strict TypeScript with a leaner detection step: a lookup table maps the first byte of a buffer to a candidate format, and only that format’s validator runs before its calculator decodes the header fields, avoiding the need to test every handler against every input. It supports 18 formats spanning common web images, legacy raster formats, and specialized texture/icon formats.
What You Get
- Pure-JS byte detection - Identifies image type by inspecting magic bytes/headers, no native bindings or extension sniffing required.
- 18 supported formats - Handles BMP, CUR, DDS, GIF, HEIC, ICNS, ICO, JP2, J2C, JPG, KTX, PNG, PNM, PSD, SVG, TGA, TIFF, WEBP, and AVIF.
- Universal runtime support - Works on any Uint8Array, so it runs identically in Node.js, browsers, Deno, and Bun.
- Dual ESM/CJS build - Ships type definitions plus .mjs/.cjs entry points built with unbuild for drop-in use in any module system.
- JPEG orientation support - Reads EXIF orientation from JPEG headers so callers can rotate or display images correctly.
Common Use Cases
- Validating uploads before processing - A server checks an uploaded file’s real type and dimensions before resizing or storing it, rejecting anything that isn’t actually an image.
- Generating responsive image metadata - A static site generator or CMS reads width/height at build time to set width/height attributes and avoid layout shift.
- Building image processing pipelines - A CLI or serverless function inspects an image’s format up front to route it to the right transcoder or optimizer.
- Auditing media libraries - A migration script scans thousands of stored files to catalog their true format and dimensions when metadata is missing or wrong.
Under The Hood
Architecture image-meta is a small, flat module: src/index.ts exposes the single imageMeta() entry point, which delegates format detection to src/detector.ts and dimension calculation to per-format handlers registered in src/types/index.ts. The detector uses a first-byte lookup table (firstBytes) to short-circuit to the most likely format, falling back to a linear scan of all registered IImage handlers via their validate() method when the fast path doesn’t match; the matched handler’s calculate() method then reads the format-specific header structure (e.g. PNG’s IHDR chunk offsets, SVG’s regex-extracted width/height/viewBox attributes) and returns a plain ImageMeta object. There’s no class hierarchy, no dependency injection, and no shared state — each format module in src/types/*.ts is a self-contained object implementing the IImage interface (validate/calculate), so adding a new format means writing one new file and registering it in typeHandlers; nothing else in the codebase needs to change if a format handler is added or removed.
Tech Stack The package is authored in strict TypeScript, targeting Uint8Array input rather than Node’s Buffer so it works unmodified in browsers, Deno, and Bun. It has zero runtime dependencies; devDependencies are limited to build/test tooling — unbuild compiles the single src/index.ts entry to dual ESM (dist/index.mjs) and CJS (dist/index.cjs) outputs plus a .d.ts, vitest (with @vitest/coverage-v8) runs the test suite, and eslint/eslint-config-unjs plus prettier enforce style. There’s no bundler-facing framework, database, or server component — the entire footprint is the detection/parsing logic plus its build pipeline, and changelogen handles release/changelog automation via the release script.
Code Quality Testing is fixture-driven: test/index.test.ts walks test/fixtures/valid/<format>/* and test/fixtures/invalid/<format>/* directories, asserting that every valid fixture round-trips through imageMeta() to a snapshot file (*.meta) and that every invalid fixture throws — this gives extensive coverage of all 18 format handlers against real binary samples rather than mocked data, run through vitest with coverage. Error handling is explicit and typed: handlers throw TypeError with a specific message (e.g. “Invalid PNG”) rather than returning undefined or swallowing errors, and the public imageMeta() function itself throws for non-Uint8Array input and unsupported types. Naming is consistent (IImage, ImageMeta, ISize interfaces; per-format modules named by extension), the project runs in strict TypeScript mode, and a dedicated type-check step runs alongside lint and tests in CI — so linting, type-checking, and test coverage all gate every change before release.
What Makes It Unique There isn’t a novel algorithmic idea here — image-meta is an explicit, acknowledged fork of the long-standing image-size package, restructured into modern TypeScript/ESM with a broader format list (adding AVIF, HEIC, J2C, JP2, and KTX beyond image-size’s original set) and a first-byte lookup table as a minor performance optimization over pure sequential validation. Its real value is packaging and scope discipline: zero dependencies, dual ESM/CJS output, and Uint8Array-only APIs make it usable identically across Node, Bun, Deno, and the browser, a deliberate UnJS-ecosystem design choice shared with sibling packages rather than a technical innovation in image parsing itself.