First-party codec suite · zero runtime dependencies

Image codecs and low-memory raster processing in strict TypeScript.

PureJsImage builds portable first-party codecs around one shared image and raster pipeline for Node.js and modern browsers. Checked capability contracts, conformance corpora, bounded execution, and optional acceleration let each codec deepen without replacing the reference engine.

86.7%lower peak RSS vs Jimp157.8 vs 1,188.3 MiB
87.6%lower peak RSS vs image-js157.8 vs 1,276.5 MiB
npm install purejsimage
Runtime examples
Choose a runtime
import { createImageLibrary } from
  'purejsimage/browser'
import { jpegCodec } from
  'purejsimage/codecs/jpeg'

const images = createImageLibrary([jpegCodec])
const image = await images.open(file)

const output = await image
  .autoOrient()
  .resize({ width: 1200 })
  .jpeg({ quality: 80 })
  .toBlob()
import { createImageLibrary } from
  'purejsimage'
import { jpegCodec } from
  'purejsimage/codecs/jpeg'

const images = createImageLibrary([jpegCodec])
const image = await images.open('input.jpg')

await image
  .autoOrient()
  .resize({ width: 1200 })
  .jpeg({ quality: 80 })
  .toFile('output.jpg')
import { createImageLibrary } from 'purejsimage'
import { jpegCodec } from
  'purejsimage/codecs/jpeg'

const images = createImageLibrary([jpegCodec])

export const handler = async (input: Buffer) =>
  (await images.open(input))
    .autoOrient()
    .resize({ width: 1200, withoutEnlargement: true })
    .jpeg({ quality: 80 })
    .toBuffer()
strict TypeScriptimmutable pipelinetyped failures

Opt-in WASM cuts the 100 MP PNG workflow from 2,355 ms to 1,438 ms.

The August 10 profile compares default PureJsImage and its explicitly registered JPEG/PNG WASM accelerators with five other engines on the same pinned inputs and validated outputs. Every engine runs in isolation with its public defaults; quality is measured separately against an independently decoded exact-area reference. Sharp uses native libvips; PureJsImage WASM and jSquash use WebAssembly; default PureJsImage is compiled from strict TypeScript, while Jimp and image-js use JavaScript.

79validated passes
19explicit unsupported results
0invalid outputs or errors
Node.js 24.16 · Linux x64 · Intel i7-10700 · recorded August 2026Methodology · Readable report · JSON

A codec-native resize path without a full-frame bitmap.

The first-party baseline JPEG path demonstrates the larger memory model: it retains one MCU row, pushes crop and resize toward decode, and releases source rows when they can no longer affect the output.

1 MCU rowretained at the decoder boundary
  • 01Decode useful MCU rowsSkip pixels outside the requested region.
  • 02Resize through a row ringReuse a bounded set of typed buffers.
  • 03Encode and releaseAvoid duplicate full-frame boundaries.

One portable reference engine, explicitly registered by capability.

Read the API
01 / MEMORY

Documented memory classes

JPEG MCU rows, PNG scanlines, TIFF strips, and experimental HEIF tiles use bounded paths where implemented. Full-frame fallbacks are identified and benchmarked separately.

02 / SAFETY

Input and allocation validation

Dimensions, allocation budgets, box extents, truncation, and entropy reads are checked before allocation or indexing.

03 / PORTABILITY

Portable reference, optional acceleration

The default codecs require no native addons, WASM, GPU backend, external binaries, or runtime dependencies. Shipped JPEG and PNG WASM accelerators use separate explicit imports; future accelerators follow the same contract.

The acceleration roadmap defines how large jobs may progressively use optional WASM or WebGPU providers without changing the default package or output semantics.

From display TIFFs to native scientific and whole-slide rasters.

Full comparison →

TIFF demonstrates how the same codec architecture serves ordinary conversion and specialized raster workloads. Capability cells follow upstream documentation or source; a separate 106-fixture RGBA comparison reports decode coverage, exact output, scientific rasters, and malformed inputs.

LibraryBrowserBigTIFFTilesRegionScientific rasterOME / WSIDecode coverage
PureJsImagebenchmark snapshot · a1f20da · Strict TypeScriptYesYesYesYesYesYes104/106 decoded57 exact2 oracle failures
GeoTIFF.js3.0.5 · Pure JavaScriptYesPartialYesYesYesNo84/106 decoded32 exact11 unsupported · 7 errors · 2 oracle failures · 2 crashes
UTIF.js (utif2)4.1.0 · Pure JavaScriptYesNoYesNoPartialNo74/106 decoded49 exact28 errors · 2 oracle failures · 2 timeouts · 3 crashes
image-js/tiff7.1.3 · Pure JavaScriptYesNoYesNoYesNo41/106 decoded27 exact51 unsupported · 12 errors · 2 oracle failures
image-js1.7.0 · Pure JavaScriptYesNoYesNoPartialNo39/106 decoded33 exact51 unsupported · 14 errors · 2 oracle failures
Jimp1.6.0 · Pure JavaScriptYesNoYesNoNoNo74/106 decoded49 exact28 errors · 2 oracle failures · 2 timeouts · 3 crashes
Sharp / libvips0.35.3 · Native wrapperNoPartialYesPartialPartialNoNot run

Measured 2026-08-10 with v24.16.0 on linux/x64. Methodology, caveats, versions, and evidence.

Install the package and register the required codecs.

The root API does not load codec implementations automatically.