Skip to content

Latest commit

 

History

418 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PureJsImage 3-by-3 brand mark

PureJsImage

Zero-runtime-dependency image processing in strict TypeScript

Portable image codecs · native scientific rasters · optional explicit WASM acceleration

npm version CI status Zero runtime dependencies MIT license

Documentation · Image demo · Scientific explorer · Whole-slide demo · OME-Zarr demo · PureJsImage Lab

Sometimes the wrong tool for the job is the right one 😉

Why I started building PureJsImage

Whole-slide viewer showing a 131,472 × 51,113 pathology slide from a 1.98 GiB Aperio SVS file after fetching 11.4 MiB, 0.562% of the source, for the displayed viewport

Measured HTTP Range session from the live browser viewer: only the visible pyramid tiles were read.

What PureJsImage is best at

  • Low peak memory usage - bounded rows, scanlines, strips, and tiles avoid source-sized RGBA working sets where formats permit it.
  • Portable across Node.js and modern browsers - strict TypeScript runs without native addons or system executables.
  • Zero dependencies - the published package has no runtime dependency tree. You can also easily tree-shake our exports.
  • Native scientific raster processing - direct-range reads and native-precision data avoid forcing scientific samples through RGBA.
  • Benchmarks that check correctness - ordinary codec and scientific-reader suites measure speed, peak RSS, output validity, source I/O, and package footprint.
  • Optional WASM accelerators - explicit JPEG, PNG, and WebP accelerator imports never load or activate automatically.
  • HUGE tested compatibility matrix - we used the Imazen image corpus to cover a huge range of real files. PureJsImage can open more format variations than nearly any other JS image library we compared.
  • Benchmaxxed performance - we painstakingly hillclimbed performance metrics vs other JS image libraries. Most of the hot loops have been unrolled. We are still slower than Sharp but mostly faster than anything else that is pure JS.

PureJsImage provides portable image codecs and low-memory raster workflows for Node.js and modern browsers. The permanent reference engine is strict TypeScript with no runtime dependency tree, native addon, system executable, or implicit WebAssembly download. Optional JPEG, PNG, and WebP WASM accelerators use separate imports and explicit registration.

Low memory is a primary product requirement. PureJsImage exists to avoid the source-sized RGBA working sets that make common JavaScript image pipelines expensive or unsafe in constrained environments such as AWS Lambda. Codecs push crops and resize toward decode, retain bounded rows or tiles where their structure permits it, and label full-frame fallbacks explicitly.

Current package surface

PureJsImage 0.17.0 is a zero-runtime-dependency strict TypeScript image-processing package for Node.js and modern browsers. The default path uses portable TypeScript implementations; optional JPEG, PNG, and WebP WASM accelerators require explicit registration.

14 stable ordinary codecs: JPEG, PNG, WebP, BMP, TIFF, GIF, ICO, JPEG 2000 / JP2, AVIF, JPEG XL, Radiance HDR / RGBE, QOI, Netpbm and PFM, TGA / TARGA.

Experimental: HEIF / HEIC (experimental) remains a separate explicit import, is excluded from allCodecs, and carries the documented HEVC/H.265 patent notice.

33 scientific readers: Common raster and whole-slide (9); Electron microscopy (7); AFM, SPM, and surface metrology (5); Medical and volume interchange (5); Spectroscopy and detector interchange (6); Raw numeric interchange (1). Direct-range readers request selected source spans, and specialized scientific readers retain native numeric precision instead of forcing data through RGBA.

Current measured surface Minified JS gzip Brotli
Core API 63.6 KiB 20.0 KiB 17.6 KiB
Common web codecs 613.9 KiB 226.7 KiB 189.8 KiB
All stable codecs 876.9 KiB 308.6 KiB 254.0 KiB
Scientific platform 163.5 KiB 47.1 KiB 40.0 KiB
All scientific readers 1233.9 KiB 357.0 KiB 284.8 KiB
Geo raster platform 136.9 KiB 37.1 KiB 31.7 KiB
All Geo readers 612.5 KiB 185.5 KiB 150.2 KiB

The extracted npm package is 6.4 MiB with 1 production package. This is unpacked size, not the compressed npm tarball.

Install

npm install purejsimage

PureJsImage requires Node.js 22 or newer. Browser applications import the core API from purejsimage/browser. Public APIs are pre-1.0 and may still receive breaking refinements.

Ordinary image pipeline

Register only the codecs an application needs:

import { createImageLibrary } from "purejsimage";
import { jpegCodec } from "purejsimage/codecs/jpeg";
import { pngCodec } from "purejsimage/codecs/png";

const images = createImageLibrary({ codecs: [jpegCodec, pngCodec] });
const image = await images.open("input.jpg");

await image
  .autoOrient()
  .resize({ width: 1200, withoutEnlargement: true })
  .jpeg({ quality: 80, background: "#ffffff" })
  .toFile("output.jpg");

Node orientation and rotation use lazy chunked memory by default. They do not open temporary files. This default is portable and was 20–28% faster than file storage across the measured orientation and arbitrary-rotation cases.

Applications can opt into temporary files when reducing Node process RSS matters more than runtime or filesystem portability:

const images = createImageLibrary([jpegCodec, pngCodec], { temporaryFiles: true });

The opt-in path stores about one padded decoded frame under os.tmpdir(). In the measured 4000x3000 RGBA orientation case, file storage reduced peak process RSS from 147.69 MiB to 90.90 MiB and increased median runtime from 654.72 ms to 820.48 ms. A tmpfs still consumes host memory even though its pages are outside process RSS. PureJsImage probes file creation, writing, reading, and truncation before consuming image rows. Failed setup or later file writes, including ENOSPC, move the spool to chunked memory and preserve output. An error that prevents recovery of bytes already written to the file is reported as a structured ImageError.

Use purejsimage/browser with File, Blob, Uint8Array, or an explicit ImageSource in a browser. For the common web formats, register the prebuilt JPEG, PNG, WebP, and AVIF group:

import { createImageLibrary } from "purejsimage";
import { allWebCodecs } from "purejsimage/codecs/web";

const webImages = createImageLibrary(allWebCodecs);

TIFF remains an explicit purejsimage/codecs/tiff import because including it would substantially increase the web-focused bundle. Use purejsimage/codecs/all only when the complete stable codec aggregate is appropriate.

Scientific datasets

Scientific readers preserve labeled axes, calibration, native sample types, and the ability to read only the parts you need. Numeric data becomes display pixels only when an application explicitly chooses a range, palette, slice, or projection.

Scientific explorer rendering native ENVI hyperspectral samples in the local browser with band selection and percentile display-range controls

The explorer maps native samples to display pixels in the tab. It does not write an RGB conversion of the cube.

import { FileSource } from "purejsimage";
import { createScientificLibrary } from "purejsimage/scientific";
import { omeTiffReader } from "purejsimage/scientific/readers/ome-tiff";

const science = createScientificLibrary({ readers: [omeTiffReader] });
const document = await science.open({
  primary: {
    id: "input",
    name: "input.ome.tif",
    source: await FileSource.open("input.ome.tif"),
  },
});
const dataset = await document.openDataset(document.datasets[0].id);

Ordinary GeoTIFFs opened through tiffReader expose a typed dataset.descriptor.spatialReference with CRS identity/citation, pixel-to-model affine, inverse when invertible, model bounds, pixel interpretation, nodata, and JSON-safe GeoTIFF evidence. readPlane() regions remain raster pixel coordinates.

For Cloud Optimized GeoTIFF workflows, inspectCog() reports container, IFD/SubIFD, tile, overview, compression, and sample layout plus likely structural issues. The checked COG compatibility matrix distinguishes display-only compression from native scientific-raster support and includes the simulated-range viewport benchmark.

GeoTIFF and GeoZarr are also available as lazy GeoRasterDataset readers under purejsimage/geo/readers. The GeoZarr reader supports v2 and v3 metadata, regular chunks, supported v3 shards, multiscales, HTTP stores, local directories, and ZIP stores without adding another Zarr decoder. Band, time, vertical, ensemble, and custom dimensions remain selectable axes. World-file TIFF, JPEG, and PNG images, georeferenced ENVI, Esri ASCII Grid, and SRTM HGT use the same geo contract while retaining each format's honest region-read limits. Classic NetCDF CDF-1 and CDF-2 files with regular rectilinear CF coordinates are available through purejsimage/geo/readers/netcdf. Time and vertical dimensions remain selectable. CDF-5, HDF5-backed NetCDF4, irregular coordinate lookup, and curvilinear grids are reported explicitly.

Geographic raster compatibility

Format Local Remote Region Multiscale Reprojection Write
GeoTIFF Tested Tested Tested Tested Tested Out of scope
COG behavior Tested Tested Tested Tested Tested Out of scope
GeoZarr Tested Tested Tested Tested Tested Out of scope
Image plus world file Tested Tested Fixture-limited Unavailable Tested Out of scope
ENVI Tested Fixture-limited Tested Unavailable Tested Out of scope
Esri ASCII Grid Tested Fixture-limited Fixture-limited Unavailable Fixture-limited Out of scope
SRTM HGT Tested Fixture-limited Tested Unavailable Tested Out of scope
Classic NetCDF / CF Tested Tested Tested Unavailable Fixture-limited Out of scope

“Fixture-limited” is implemented behavior with a narrow current corpus. “Metadata only” does not claim the related pixel operation. See the complete generated geo evidence table and the machine-readable manifest.

Direct-range readers can request only the source spans needed for metadata, a native-precision region, a spectrum, a volume plane, or a whole-slide tile. This includes workflows across DM3 and DM4, TIA SER and EMI, NCEM and Velox EMD, NIfTI, NRRD, MRC, OME-TIFF, Aperio SVS, AFM and surface metrology, and 4D-STEM data.

The live Scientific Raster Explorer currently wires only its smaller demo set. It does not claim to open every package reader. Applications and PureJsImage Lab can register the explicit reader exports they need.

Scientific format reference → · Scientific API reference → · Scientific application guide → · OME-Zarr reader and validation policy → · OME-Zarr public compatibility evidence → · Geo raster architecture → · GeoZarr reader → · Contained geo formats → · Classic NetCDF and CF grids → · Native numeric tile contract → · Bounded raster analysis →

Supported Formats

Stable ordinary codecs

Format Read Write
JPEG Yes Yes
PNG Yes Yes
WebP Yes Yes
BMP Yes Yes
TIFF Yes Yes
GIF Static / explicit frame 0 No
ICO Yes No
JPEG 2000 / JP2 Yes No
AVIF Yes Limited
JPEG XL Limited No
Radiance HDR / RGBE Yes Yes
QOI Yes Yes
Netpbm and PFM Yes Yes
TGA / TARGA Yes Yes

Experimental codecs

Format Read Write
HEIF / HEIC (experimental) Experimental No

“Limited” means PureJsImage supports a useful subset and clearly rejects files outside it. “Experimental” means the codec is excluded from allCodecs and requires an explicit direct import and registration.

See the exact codec support matrix →

Detailed codec compatibility roadmaps: JPEG, PNG, WebP, BMP, TIFF, GIF, ICO, JPEG 2000 / JP2, AVIF, JPEG XL, Radiance HDR / RGBE, QOI, Netpbm and PFM, TGA / TARGA, and HEIF / HEIC (experimental).

Scientific reader package surface

The package currently exposes 33 scientific readers through explicit purejsimage/scientific/readers/* exports. This family summary is generated from the scientific reader inventory in capabilities/manifest.json, the package exports, and src/scientific/readers/all.ts.

Reader family Count Representative formats
Common raster and whole-slide 9 PNG, JPEG, WebP, BMP, JPEG 2000 / JP2, TIFF, OME-TIFF, OME-Zarr, Aperio SVS
Electron microscopy 7 Gatan DigitalMicrograph, FEI/Thermo TIA SER, FEI/Thermo TIA EMI, NCEM EMD 0.2, FEI/Thermo Velox EMD, NanoMegas ASTAR blockfile, Quantum Detectors Merlin MIB
AFM, SPM, and surface metrology 5 Gwyddion Simple Field, Nanonis SXM, Igor Binary Wave v5, Digital Surf SUR/PRO, X3P surface exchange
Medical and volume interchange 5 MRC/CCP4, NRRD, MetaImage MHD/MHA, NIfTI-1/2, DICOM Part 10 Image
Spectroscopy and detector interchange 6 ENVI, FITS, CBF/imgCIF, Lispix RPL/RAW, EMSA/MAS spectrum, ANG/CTF orientation map
Raw numeric interchange 1 NumPy NPY

The complete per-reader imports and support boundaries remain on the scientific format reference, the API reference, and the machine-readable capability manifest.

The live browser explorer currently wires the smaller demo set: Gwyddion Simple Field (purejsimage/scientific/readers/gsf), ENVI (purejsimage/scientific/readers/envi), FITS (purejsimage/scientific/readers/fits), MRC/CCP4 (purejsimage/scientific/readers/mrc), CBF/imgCIF (purejsimage/scientific/readers/cbf). The explorer does not claim to open every reader in the package surface; applications can register any explicit reader export.

The raster APIs preserve native numeric data instead of forcing every source through RGB. The full reader surface includes scientific images and volumes, spectroscopy and instrument data, microscopy and whole-slide data, surface and metrology formats, and ordinary image adapters.

Experimental HEIF/HEIC is available only from purejsimage/codecs/experimental/heic. It remains excluded from allCodecs because HEIC commonly carries HEVC/H.265 content that may be subject to third-party patent rights. The project’s MIT license grants no third-party patent rights; users and distributors must evaluate their own licensing obligations.

Current benchmark snapshots

Web codec benchmarks (2026-08-24): 122 validated passes, 25 explicit unsupported rows, and no invalid outputs or errors across JPEG, PNG, WebP, TIFF, and AVIF workflows. On the 24-megapixel northstar photo pipeline, the TypeScript path used 84.7% less absolute peak RSS than Jimp (181.8 MiB versus 1189.1 MiB).

Scientific readers (2026-08-17): 43 correctness and startup workflows passed across 31 readers in that snapshot. The separate medium/large scaling profile validated 13 representative workloads; 6 met the under-10% CV publication threshold and the remaining rows stay visible as noisy. Results report first usable block, selected-operation time, absolute peak RSS, source requests and bytes, overfetch, import/initialization, and emitted-block correctness without collapsing formats into one winner score.

Ordinary and scientific reports use separately fingerprinted harnesses. No cross-section speed or memory ratio is claimed.

Web codec benchmark speed chart. Lower wall time is better. The chart includes validated shared JPEG, PNG, WebP, TIFF, and AVIF workloads. Sharp is native libvips and is not presented as pure JavaScript.

Median wall time from the current validated web codec benchmark snapshot.

Web codec benchmark peak RSS chart. Lower peak RSS is better. The chart includes validated shared JPEG, PNG, WebP, TIFF, and AVIF workloads. Sharp is native libvips and is not presented as pure JavaScript.

Absolute process peak RSS from the current validated web codec benchmark snapshot.

Web codec benchmarks · Scientific methodology and report · Benchmark harness · Generated result index

Historical AWS Lambda measurements remain useful for memory-tier and CPU-allocation context, but are kept separate from current local benchmark headlines. See the performance page for dates, architecture, and exact artifacts.

Bundle size and npm package size

Generated for purejsimage 0.17.0. The README keeps only the major entry points; the complete per-codec, per-reader, competitor, gzip, Brotli, installed-package, and WASM measurements are on the performance page and in the machine-readable artifact.

Surface Import Minified JS gzip Brotli
Core API purejsimage 63.6 KiB 20.0 KiB 17.6 KiB
Core + common web codecs purejsimage/codecs/web 613.9 KiB 226.7 KiB 189.8 KiB
Core + all stable codecs purejsimage/codecs/all 876.9 KiB 308.6 KiB 254.0 KiB
Core + scientific platform purejsimage/scientific 163.5 KiB 47.1 KiB 40.0 KiB
Scientific readers: all purejsimage/scientific/readers/all 1233.9 KiB 357.0 KiB 284.8 KiB

The extracted npm package is 6.4 MiB and has 1 production package. The eight optional JPEG, PNG, and WebP accelerator assets total 175.7 KiB raw WASM and are loaded only through explicit accelerator imports.

Complete size and footprint tables → · Machine-readable package metrics

Evidence and methodology

Historical TIFF conformance comparison

The checked 2026-08-13 snapshot compared documented TIFF capabilities separately from independent RGBA output. PureJsImage decoded 104/106 comparable display cases; 57 were exact and 47 had pixel differences. “Oracle unavailable” means the independent Sharp/ImageMagick path could not produce ground truth, not that an engine failed. Current performance headlines come from the newer generated benchmark index above.

Full grouped capability matrix, methods, sources, and per-library results

Why PureJsImage?

  • Low-memory execution is the main goal: avoid source-sized bitmaps and duplicate full-frame buffers wherever codec structure permits bounded rows, tiles, regions, or coefficient storage.
  • Strict TypeScript codecs remain the portable production and fallback path.
  • Zero runtime dependencies simplify browser, serverless, edge, air-gapped, and restricted builds.
  • Bounded rows, tiles, regions, and source reads are used where the format permits them.
  • Unsupported syntax fails explicitly instead of producing plausible corruption.
  • Validation, quality oracles, peak RSS, source I/O, and package footprint remain part of the benchmark contract.

If native libvips is deployable and throughput is the primary constraint, use Sharp. PureJsImage is aimed at workflows where portable source, browser parity, explicit dependency boundaries, native scientific data, or lower-memory JavaScript execution matter.

Citation

DOI

Use the metadata in CITATION.cff to cite PureJsImage. The file records the current software release, author, source repository, npm package, license, and project keywords in Citation File Format 1.2.0. The DOI for release 0.16.0 is 10.5281/zenodo.22071815. Use 10.5281/zenodo.22071814 to cite the project across all versions.

Development

npm install
npm run check

Read CONTRIBUTING.md, the architecture, and the roadmap before larger changes.

Special thanks

Thanks to Imazen for the real-world image corpus used in compatibility and (especially) TIFF validation.

Thanks to PgRust for inspiring me to do this work.

About

Low-memory, zero-dependency image codecs and processing in pure TypeScript for Node.js, browsers, and serverless runtimes. Bounded decode/resize pipelines plus deep TIFF, scientific raster, GeoTIFF, OME-TIFF, and whole-slide support.

Topics

Resources

Contributing

Security policy

Stars

61 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages