heic-convert
Converts HEIC/HEIF images to JPEG or PNG in Node.js and the browser, using pluggable pure-JS and native Canvas encoders.
Repository Health
Technical Analysis
heic-convert is a small JavaScript library that turns HEIC/HEIF photos — the default format produced by iPhones and other modern cameras — into JPEG or PNG images that existing image pipelines can actually use. It delegates the hard part of parsing Apple’s HEIF container to the companion heic-decode package, then re-encodes the raw pixel data using either a pure-JavaScript encoder (jpeg-js/pngjs) for Node.js or the browser’s native Canvas API when bundled for client-side use.
The API exposes both a single-image conversion function and an all() variant for HEIC containers holding multiple images (e.g. Live Photos or burst shots), letting callers decode and encode only the specific frames they need rather than paying the cost for every image in the file up front.
What You Get
- A single
convert({ buffer, format, quality })function that returns a JPEG or PNG buffer/Uint8Array - A
convert.all()variant that lazily converts every image inside a multi-image HEIC container - A dedicated
heic-convert/browserentry point that encodes via the Canvas API instead of bundling a JS encoder - Configurable JPEG compression quality between 0 and 1
- A decode/encode core (
lib.js) decoupled from the specific decoder and encoder implementations it’s wired to
Common Use Cases
- Converting uploaded iPhone HEIC photos to JPEG on a Node.js server before storage or resizing
- Previewing a user-selected HEIC file as JPEG/PNG directly in the browser with no server round-trip
- Extracting a single frame from a multi-image HEIC (Live Photo/burst) without decoding every embedded image
- Batch-converting an archive of HEIC photos to PNG for tools that don’t support HEIF
Under The Hood
Architecture
The package is a thin dependency-injection-style library: lib.js exports a factory function that takes a decode function and an encode map and returns { one, all } conversion functions built around a single convertImage() step (decode → encode[format]). index.js wires that factory to the heic-decode package and to formats-node.js (pure-JS jpeg-js/pngjs encoders), while browser.js wires the identical factory to formats-browser.js (Canvas-API encoders) — the same core conversion logic backs two environment-specific builds selected simply by which entry file a consumer imports. The structure is deliberately flat, with no layering beyond entry point → lib → format modules; what would break if the core convert() contract changed is both encode maps, since each is called through the same generic encode[format]({ width, height, data, quality }) interface.
Tech Stack
Runtime dependencies are heic-decode (HEIF parsing), jpeg-js and pngjs (pure-JavaScript JPEG/PNG encoding for Node), while the browser build uses the native HTMLCanvasElement.toBlob() API instead of bundling an encoder, keeping browser bundle size down. There’s no build step for the library itself — it ships as plain CommonJS for Node >=12, and browser consumers bundle it themselves (e.g. with webpack). Development dependencies cover testing (mocha, chai), simulating browser APIs in Node (jsdom, canvas), verifying output image correctness (file-type, pixelmatch), and linting (eslint). Releases are published to npm via a GitHub Actions workflow triggered by git tags.
Code Quality
Tests live in test/index.test.js and test/browser.test.js, both delegating to a shared test/run-tests.js spec that is exercised against three different backend configurations — the default WASM libheif decoder, a legacy pure-JS libheif decoder, and the browser Canvas encoder — so the same behavioral contract is checked across all supported paths. Error handling is minimal but explicit: convert() throws naming the valid output formats when given an unsupported one, and the browser encoder rejects its promise if canvas.toBlob() returns no blob. There’s no TypeScript or JSDoc typing. ESLint is configured, and CI (GitHub Actions) runs the full test suite across five Node versions plus an npm pack --dry-run check before every publish; there is no visible code-coverage tooling.
What Makes It Unique
The package’s differentiator is scope discipline rather than novel technique: HEIC/HEIF decoding is delegated entirely to the companion heic-decode package, while this library owns only the encode side, and it ships two parallel encoder backends behind an identical convert() interface — a pure-JavaScript encoder for Node portability and a native browser Canvas encoder for bundle-size efficiency — selected purely by import path. It also supports lazy multi-image conversion via convert.all(), so only images a caller actually requests pay the decode/encode cost, which is useful for multi-image HEIC containers like Live Photos.
Used by 6 apps in this directory
Activepieces
Automation · AI Assistants
Open-source AI automation platform that converts 280+ workflow integrations into MCP servers for LLMs, with no-code builders and TypeScript extensibility.
Formbricks
Forms Surveys · Marketing · Analytics
Open-source experience management platform for in-app, website, email, and link surveys — privacy-first and fully self-hostable.
Ghost
CMS · Blogging
Open source headless Node.js CMS for professional publishing, paid memberships, and newsletters with a fully owned audience.
Kener
Monitoring · Devops
Stunning, self-hosted status pages with real-time uptime monitoring, incident management, and multi-channel notifications in a single Docker container.
Midday
Invoicing Finance · Productivity
All-in-one AI-powered business operations platform for freelancers and solo entrepreneurs to manage invoicing, time tracking, banking, and financial intelligence.
Trieve
AI Development · Search · Developer Tools
All-in-one self-hostable platform for hybrid search, RAG, recommendations, and analytics built on Rust and Qdrant.