API reference

Public API and runtime contracts.

Codec registration, immutable image pipelines, labeled scientific datasets, analysis operations and graphs, sources, safety limits, metadata preservation, and typed errors.

Codec pipeline: established npm pathApplication platform: alphaExtensions: experimental

ImageLibrary

Create a frozen library with the codec implementations your application accepts. Registration order is preserved in formats(); duplicate format names are rejected.

Signature
function createImageLibrary(registration: Iterable<ImageCodec> | ImageLibraryConfiguration): ImageLibrary

interface ImageLibrary {
  formats(): readonly string[]
  open(input: ImageInput, options?: ImageOpenOptions): Promise<Image>
}

interface ImageOpenOptions {
  frame?: number
  resolutionLevel?: number
  tolerantDecoding?: boolean
  limits?: ImageLimitOptions
}

formats()

Returns the format names registered in this library.

returns readonly string[]

open(input, options?)

Creates a source, validates optional zero-based frame and resolution-level selections, enforces the input-byte limit, probes registered codecs, and returns a lazy image pipeline. TIFF supports explicit top-level frame selection and resolutionLevel selection, where level 0 is the full-resolution frame and later levels are reduced-resolution SubIFDs ordered from largest to smallest. Codecs reject nonzero selections they do not support. Static GIFs decode without a selection; animated GIF metadata remains available, but pixel output requires an explicit { frame: 0 } to prevent silent animation loss. Baseline JPEG restart recovery defaults to tolerantDecoding: true for compatibility with malformed real-world files. Set { tolerantDecoding: false } to require exact restart sequencing and permit an explicitly registered JPEG decode accelerator.

returns Promise<Image>

Codec imports

EntryNamed export
purejsimage/codecs/jpegjpegCodec
purejsimage/codecs/jpeg2000jpeg2000Codec
purejsimage/codecs/pngpngCodec
purejsimage/codecs/gifgifCodec
purejsimage/codecs/icoicoCodec
purejsimage/codecs/webpwebpCodec
purejsimage/codecs/bmpbmpCodec
purejsimage/codecs/tifftiffCodec
purejsimage/codecs/avifavifCodec
purejsimage/codecs/experimental/heicexperimentalHeicCodec, experimentalHeifCodec
purejsimage/codecs/weballWebCodecs (JPEG, PNG, WebP, AVIF)
purejsimage/codecs/allallCodecs

allWebCodecs is the compact common-web group. TIFF remains a direct import because its broader implementation would substantially increase that bundle. allCodecs contains all 14 stable codecs. Both aggregates intentionally exclude experimental HEIF/HEIC.

Experimental HEIC opt-in

TypeScript
import { createImageLibrary } from 'purejsimage'
import { allCodecs } from 'purejsimage/codecs/all'
import { experimentalHeicCodec } from 'purejsimage/codecs/experimental/heic'

const images = createImageLibrary({
  codecs: [...allCodecs, experimentalHeicCodec],
})
Experimental and opt-in. HEIC commonly contains HEVC/H.265 image data that may be subject to third-party patent rights. PureJsImage's MIT license covers this implementation's copyright and grants no third-party patent rights. Users and distributors are responsible for determining whether their use requires additional licenses, particularly for commercial products, services, or high-volume distribution. The codec is shipped in the package but is never loaded by the root entry, allCodecs, or the default browser demo. See the experimental HEIF/HEIC contract.

purejsimage/hdr provisional

Explicit gain-map HDR inspection, extraction, caller-selected linear rendering, paired geometry, and constrained JPEG or AVIF output. Importing the root package, browser entry, or ordinary JPEG and AVIF codec entries does not load this subsystem. Ordinary JPEG decode continues to return the SDR primary.

TypeScript
import { openGainMapImage } from 'purejsimage/hdr'

const image = await openGainMapImage(input)
try {
  for await (const block of image.render({ displayBoost: 4 })) {
    // Linear rgbf32 or rgbaf32. Values above 1 are retained.
  }

  const jpeg = await image
    .crop({ x: 100, y: 50, width: 1200, height: 800 })
    .resize({ width: 600, height: 400, kernel: 'lanczos3' })
    .jpeg({ metadataMode: 'dual' })
} finally {
  image.close()
}

inspectGainMapImage(input, options?)

Cheap JPEG gain-map probe. Reports valid, absent, unsupported, or invalid without entropy-decoding either child image.

returns Promise<GainMapProbeInspection>

openGainMapImage(input, options?)

Opens a validated Ultra HDR or ISO 21496-1 JPEG or AVIF relationship. ISO metadata wins when matching ISO and Ultra HDR representations are present.

returns Promise<OpenedGainMapImage>

inspection()

Returns immutable normalized metadata, exact ISO rationals where available, dimensions, color semantics, representation selection, and validated JPEG ranges.

returns GainMapImageInspection

extractOriginalBase() and extractOriginalGainMap()

Copies the original validated encoded JPEG range or AV1 item payload without decoding pixels. The names distinguish original bytes from transformed inspection and preview state.

returns Promise<Uint8Array>

previewTransformedComponents(options?)

Returns caller-limited current SDR base and encoded gain-map samples with transformed dimensions and channel counts.

returns Promise<GainMapComponentPreview>

render({ displayBoost })

Applies gain in linear light and emits ordered rgbf32 or rgbaf32 blocks. Base alpha is copied unchanged.

returns AsyncIterable<GainMapRenderedBlock>

autoOrient(), crop(), flipHorizontal(), flipVertical(), rotate(), resize()

Returns a fluent view whose base and encoded gain map receive the same normalized geometry.

returns OpenedGainMapImage

jpeg(options?)

Writes dual, ISO-only, or Ultra-HDR-only compound JPEG output with independent base and map quality. The sRGB primary carries the generated PureJsImage sRGB ICC profile. Adapted Float32 rendering remains block-bounded.

returns Promise<Uint8Array>

avif(options?)

Writes the first constrained ISO gain-map AVIF subset: opaque sRGB SDR base, one-channel map, and no grids or animation.

returns Promise<Uint8Array>

See the gain-map HDR guide and the local browser workbench.

purejsimage/evidence alpha

Creates a caller-owned, opt-in execution evidence session. Summary mode retains bounded counters, merged source ranges, and PureJsImage-managed byte totals. Trace mode adds bounded events, child scopes, dependency IDs, cache activity, and allocation leases. Importing the root package does not create a collector or include the Raster X-Ray interface.

TypeScript
import { createEvidenceSession, explainImage, instrumentImageSource } from 'purejsimage/evidence'

const evidence = createEvidenceSession({ mode: 'trace' })
const source = instrumentImageSource(inputSource, evidence.context)
const image = await images.open(source)
const plan = await explainImage(image.resize({ width: 800 }).png())
const output = await image.resize({ width: 800 }).png().toBuffer({
  evidence: evidence.context,
})
const report = evidence.finalize()

Reports are versioned, immutable, and JSON safe. Source names are excluded by default. Managed bytes cover only allocations explicitly owned and accounted by PureJsImage, not process RSS or total browser memory. See the Raster X-Ray browser inspector and the execution evidence guide.

Application-platform package entries

The application platform is an alpha API introduced in PureJsImage 0.10.0. Provider and trusted-extension APIs are experimental. The ordinary purejsimage codec pipeline remains the established path: these opt-in entries do not change resize().jpeg() behavior or load analysis code into the root entry.

Lifecycle is part of the API. Pass AbortSignal through source reads, planning, and execution. Release every NumericTile and execution result, dispose prepared plans and tile runtimes, and close scientific documents. The library cannot infer when application-held resources are no longer needed.

purejsimage/scientific alpha

Portable labeled-axis datasets, explicit reader registries, document and source identity, RasterBlock reads, and native NumericTile conversion. Concrete formats remain optional through individual reader entries. Use createScientificLibrary(), select a summary from document.datasets, then call openDataset(id). resolveNumericTileSource() uses a compatible direct native source when supplied or the permanent RasterBlock conversion adapter otherwise.

purejsimage/scientific/browser alpha

createScientificFileContext(file, options?) wraps a browser File and explicit companion files without exposing Node paths. For remote data, pass an HTTP Range-backed ImageSource through the portable scientific context. Browsers cannot open arbitrary local path strings.

purejsimage/scientific/node alpha

createScientificPathContext(path, options?) opens the primary file and resolves constrained sibling companions. Filesystem paths and Node resources remain in this adapter and do not enter the portable browser module graph.

Scientific reader entries alpha

Interchange and detector entries: purejsimage/scientific/readers/rpl, purejsimage/scientific/readers/emsa, purejsimage/scientific/readers/nrrd, purejsimage/scientific/readers/meta-image, purejsimage/scientific/readers/nifti, purejsimage/scientific/readers/npy, purejsimage/scientific/readers/blockfile, purejsimage/scientific/readers/mib, and purejsimage/scientific/readers/ebsd-text.

DICOM Part 10 grayscale images are available from purejsimage/scientific/readers/dicom. The first public subset is native uncompressed MONOCHROME1/2 Implicit or Explicit VR Little Endian, Encapsulated Uncompressed Explicit VR Little Endian, RLE Lossless, JPEG Baseline 8-bit, JPEG Lossless Process 14 Selection Value 1, and JPEG 2000 lossless/lossy grayscale, with 8-bit or 16-bit allocation as the transfer syntax permits, signed or unsigned stored values, 12-bit-in-16 normalization, homogeneous multi-frame selection, Pixel Spacing, linear rescale slope/intercept metadata, and Window Center/Width presets. Stored samples are not rescaled, windowed, or inverted. Color, LUT-based presentation, other JPEG Lossless selection values, JPEG-LS, HTJ2K, DICOMweb, and series discovery remain unsupported. The reader is not validated for diagnostic use.

HDF5 dialect readers are available from purejsimage/scientific/readers/ncem-emd and purejsimage/scientific/readers/velox-emd. They identify their internal hierarchy rather than relying on the shared .emd extension.

Import only the formats an application registers: purejsimage/scientific/readers/gsf, purejsimage/scientific/readers/envi, purejsimage/scientific/readers/fits, purejsimage/scientific/readers/mrc, purejsimage/scientific/readers/cbf, purejsimage/scientific/readers/digital-micrograph, purejsimage/scientific/readers/tia-ser, purejsimage/scientific/readers/tia-emi, purejsimage/scientific/readers/tiff, purejsimage/scientific/readers/ome-tiff, purejsimage/scientific/readers/ome-zarr, purejsimage/scientific/readers/aperio-svs, purejsimage/scientific/readers/png, purejsimage/scientific/readers/jpeg, purejsimage/scientific/readers/webp, purejsimage/scientific/readers/bmp, or purejsimage/scientific/readers/jp2. PNG, JPEG, WebP, BMP, and JP2 are low-confidence uint8 codec fallbacks, so specialized scientific readers retain precedence. DigitalMicrograph exposes supported rank-2 through rank-4 scalar and fixture-backed BGRA entries as separate datasets. Ordinary rank-3 arrays use X/Y/Z, while EELS uses X/Y/energy and 4D-STEM uses logical scanX/scanY/kx/ky only when exact Gatan metadata identifies those roles; ambiguous rank-4 arrays remain dimension-0 through dimension-3. Direct reads cover the first physical storage plane: X/Y for images, volumes, and EELS; kx/ky for the verified C-ordered 4D-STEM layout. TIA SER exposes v528 and v544 scalar spectra, spectrum images, and image series with lazy payload reads. The preferred TIA EMI path resolves numbered SER companions, adds bounded acquisition metadata, includes both resources in identity, and applies reciprocal-space interpretation only when EMI mode and SER calibration agree. OME-Zarr 0.4 and 0.5 read directory-like Zarr v2 and v3 stores from a root zarr.json, .zgroup, or .zattrs, or a ZIP archive with that root metadata, map image multiscales, labels, and plate wells onto scientific datasets, and fetch only intersecting regular or sharded chunks, including Blosc 1 LZ4 payloads. Ordinary TIFF instead preserves native signed, floating-point, planar, and N-channel samples, uses labeled page axes for compatible pages, keeps incompatible series separate, and exposes SubIFDs as levels without guessing Z/time or arbitrary-band RGB semantics. Its generic probe remains below OME-TIFF and Aperio. The base scientific entry exports createImageCodecScientificReader({ descriptor, codec, limits }) for deliberate composition without linking concrete codecs into that entry. Selectable frames become separate datasets and codec-declared resolution levels remain within each frame dataset; metadata-only frame counts and decode scaling do not create scientific coordinates. The Aperio entry exports the secure default reader plus createAperioSvsReader({ limits }) for explicit WSI source, dimension, directory, region, decoded-byte, and associated-image ceilings. It exposes a calibrated multiresolution pyramid dataset and separate associated-image datasets without eagerly embedding ICC payload bytes. Applications that deliberately need every first-party format can import purejsimage/scientific/readers/all. These entries export reader values without registering them globally, and the all-readers entry excludes experimental HEIC.

DigitalMicrograph applications that need different admission ceilings can use createDigitalMicrographReader({ limits }) to configure source bytes, dataset count, dimension length, individual dataset bytes, and selected-region bytes.

TIA SER applications can use createTiaSerReader({ limits }) to configure structural metadata, element, source, dataset, selected-region, and source-read ceilings.

TIA EMI applications can use createTiaEmiReader({ limits, ser }) to configure binary-envelope, XML, metadata, companion, dataset, and delegated SER ceilings.

purejsimage/operations alpha

JSON-safe, versioned value-type and operation descriptors, parameter schemas, local registries, provider contracts, semantic support checks, and cost-based provider planning. Executable providers remain separate from descriptors. The strict TypeScript reference provider is permanent; future WASM or WebGPU providers require explicit registration and exact semantic support.

purejsimage/analysis alpha

The intentional application workflow entry: controllers, built-in bundle construction, graph/workspace commands, planning and execution, primary project/ROI/result types, operation IDs, and bounded numeric-raster plans. Initial graph operations include resolution-level selection, crop, resampling, thresholding, Gaussian blur, projection, statistics, histograms, line profiles, and deterministic connected components with lazy uint32 labels and a columnar object table. Stateless tile primitives add parsed band math, normalized difference, linear combination, subtraction, terrain derivatives, regional results, and explicit target-grid resampling or caller-supplied inverse reprojection. See the complete compiled application example.

Raster plans are versioned JSON-safe data. They explicitly record raw or scaled band values, nodata, units, resampling, and coordinate-transform identity and accuracy. Executors expose explicit tile and memory limits and consume only caller-provided bounded NumericTile values; they do not discover transforms, read whole datasets, or create a global cache.

Analysis specialist entries alpha

purejsimage/analysis/results exposes full result schemas, validation, summaries, and memory accounting. purejsimage/analysis/roi exposes geometry, coordinate conversion, masks, and line sampling. purejsimage/analysis/runtime exposes TileRuntime, semantic source/derived identities, tile sources, cache keys, memory estimates, and provider-facing derived tiles. purejsimage/analysis/project exposes canonical project hashes, persistence contracts, explicit migrations, and canonical JSON helpers.

Source cache identity uses complete reader/dataset/resource evidence when available and an explicit session or instance scope otherwise. Derived identity includes source, operation/version, normalized parameters, output, provider/implementation, and generation.

purejsimage/extensions experimental

Composes explicitly supplied trusted bundles into isolated application-owned registries. Reader IDs must begin with the extension ID plus /; value type, operation, provider, and migration IDs must begin with the extension ID plus .. No package-global singleton or hidden auto-registration exists.

Trusted code, not a sandbox. Extension providers execute in the caller's realm and can use the caller's authority. A future Worker or iframe RPC boundary is required before accepting untrusted extension packages.

TIFF documents, rasters, and profiles

purejsimage/tiff exposes the validated TIFF IFD graph independently of the display-image pipeline. openTiffDocument(source, options?) returns a TiffDocument with stable top-level and SubIFD directory objects. Each TiffDirectory exposes its absolute source offset; getDirectoryByOffset(offset) resolves parsed metadata pointers. getTagInfo(tag) reports bounded field/count/byte-length metadata without fetching an external payload; getTag() reads bounded cached values. A directory creates either an ImageDecoder for display pixels or a RasterDecoder for native-precision, arbitrary-channel samples. readBytes(offset, length, { maxBytes }) performs an exact bounded private-metadata read and returns a defensive copy without exposing the underlying ImageSource.

TiffDocumentOptions adds maxSegmentCount (1,048,576), maxSegmentTableBytes (32 MiB), and maxEncodedSegmentBytes (128 MiB). Segment count and the raw-plus-converted table construction peak are admitted before table payload reads. Display and raster requests include the largest intersecting encoded segment with retained decoded segments, output, and predictor scratch under maxDecodedBytes.

Labeled-axis OME-TIFF
import { MemorySource } 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: 'image', source: new MemorySource(bytes) } })
const dataset = await document.openDataset(document.datasets[0].id)
for await (const block of dataset.readPlane({
  displayAxes: ['x', 'y'], fixedIndices: [{ axisId: 'channel', index: 0 }], resolutionLevel: 0,
  x: 0, y: 0, width: 512, height: 512,
})) {
  consume(block)
}

omeTiffReader validates OME dimensions, sample type, labeled axes, channel metadata, physical pixel size, dimension order, and explicit or implicit TiffData mappings before exposing a ScientificDataset. readPlane() preserves native sample types without materializing a source-sized display bitmap.

purejsimage/pathology exports openAperioSvs(), aperioSvsProfile, and the generic WholeSlideImage contract. Aperio levels and label, macro, or thumbnail images decode by requested region. TIFF compression tags 33003 and 33005 use the reusable createJpeg2000CodestreamDecoder(); JPEG 2000 reconstruction remains bounded to the current TIFF tile or strip, though the current codestream decoder retains that segment's complete component state.

Third-party TIFF profile authoring

A separately shipped integration implements TiffProfile<T> using only package exports. Register profiles with createTiffProfileRegistry(). Detection runs every profile in isolation, orders matches by descending integer priority then id, reports detector failures, and rejects equal-priority matches as ambiguous. For an explicitly selected profile, registry.openWith(document, profile) preserves T and returns Promise<T>.

Vendor profile
import { createTiffProfileRegistry } from 'purejsimage/tiff'
import type { TiffProfile } from 'purejsimage/tiff'

export const vendorProfile: TiffProfile<VendorDataset> = {
  id: 'vendor-format',
  priority: 50,
  async detect({ document }) {
    const tag = await document.topLevelDirectories[0]?.getTag(270, {
      maxBytes: 1024 * 1024,
    })
    return tag?.kind === 'ascii' && tag.value.startsWith('Vendor')
  },
  async open({ document }) {
    const pointer = await document.topLevelDirectories[0]?.getTag(65000, {
      maxBytes: 24,
    })
    if (pointer?.kind !== 'numbers') throw new Error('Vendor pointer is missing')
    const directory = document.getDirectoryByOffset(pointer.values[0] ?? -1)
    if (!directory) throw new Error('Vendor IFD is missing')
    const length = pointer.values[2] ?? -1
    const metadata = await document.readBytes(
      pointer.values[1] ?? -1, length, { maxBytes: 1024 * 1024 },
    )
    return openVendorDataset(directory, metadata)
  },
}

const registry = createTiffProfileRegistry([vendorProfile])
const dataset = await registry.openWith(document, vendorProfile)
Public boundary. Profile code must bound every metadata read with getTag(tag, { maxBytes }) or readBytes(offset, length, { maxBytes }), validate metadata-to-IFD mappings before decoding, and retain structured unsupported errors for ambiguous vendor semantics. Tag values are cached, but each caller's limit is checked before cache access; byte-valued tags and raw reads return defensive copies. The checked examples/tiff-profile-leica driver compiles as an external package and imports only purejsimage, purejsimage/tiff, and purejsimage/pathology.

See the dedicated TIFF guide for the complete supported-format list, scientific and whole-slide workflows, output profile, memory model, and current limitations →

Zstandard decompression

The portable purejsimage/compression/zstd subpath exports the reusable first-party decoder used by TIFF Compression=50000. It has no format-specific parameters and does not load native code, WebAssembly, or a runtime dependency.

TypeScript
import { decodeZstd } from 'purejsimage/compression/zstd'

const output = decodeZstd(compressed, {
  expectedOutputBytes: 8192,
  maxOutputBytes: 8192,
  maxWindowBytes: 64 * 1024 * 1024,
})

maxOutputBytes and maxWindowBytes default to 64 MiB. Supplying expectedOutputBytes preallocates the exact bounded output and rejects a different decoded size. Dictionary-dependent frames fail with UNSUPPORTED_OPERATION.

Optional WASM acceleration

JPEG, PNG, and WebP provide first-party WebAssembly accelerators as explicit package entries. The root, browser, and codec imports never load them automatically. Register a provider through ImageLibraryConfiguration; ineligible or unavailable work continues through the corresponding TypeScript codec.

Node.js
import { createImageLibrary } from 'purejsimage'
import { wasmJpegAccelerator } from 'purejsimage/accelerators/wasm/jpeg'
import { wasmPngAccelerator } from 'purejsimage/accelerators/wasm/png'
import { wasmWebpAccelerator } from 'purejsimage/accelerators/wasm/webp'
import { allCodecs } from 'purejsimage/codecs/all'

const images = createImageLibrary({
  codecs: allCodecs,
  accelerators: [wasmJpegAccelerator, wasmPngAccelerator, wasmWebpAccelerator],
})

Browser applications use createImageLibrary from purejsimage/browser. The accelerator import paths stay the same and resolve to browser-safe loaders.

Configuration

The ready-made providers use defaults chosen to avoid paying module and copy overhead on small images. Use the factory exports when an application needs different thresholds or input limits.

TypeScript
interface WasmJpegAcceleratorOptions {
  minimumPixels?: number
  minimumEncodePixels?: number
  maximumInputBytes?: number
  maximumEncoderRowBytes?: number
}

interface WasmPngAcceleratorOptions {
  minimumPixels?: number
  minimumEncodePixels?: number
  maximumRowBytes?: number
}

interface WasmWebpAcceleratorOptions {
  minimumPixels?: number
  minimumEncodePixels?: number
  maximumPixels?: number
}

function createWasmJpegAccelerator(options?: WasmJpegAcceleratorOptions): ImageCodecAccelerator
function createWasmPngAccelerator(options?: WasmPngAcceleratorOptions): ImageCodecAccelerator
function createWasmWebpAccelerator(options?: WasmWebpAcceleratorOptions): ImageCodecAccelerator

JPEG and PNG pixel thresholds default to 65,536. WebP defaults to 16,384 pixels and accepts at most 64 million pixels. JPEG accepts at most 32 MiB of compressed input and a 16 MiB encoder row by default; PNG accepts at most a 16 MiB row. Every supplied value must be a positive integer.

Eligible workflows

ProviderAccelerated workTypeScript fallback examples
JPEGCommon full-image baseline YCbCr decode and baseline gray8, rgb8, or rgba8 encodeProgressive output, crop or scaled decode, ICC-transformed decode, metadata-preserving output, small images, and inputs beyond configured limits
PNGFull-image, non-interlaced 8-bit grayscale, RGB, or RGBA decode without tRNS; adaptive-filter gray8, rgb8, or rgba8 encodePalette, grayscale-alpha, sub-byte, 16-bit, tRNS, Adam7, APNG frames, crop, compression level 0, small images, and rows beyond configured limits
WebPVP8 YUV row conversion, VP8L predictor and color reconstruction, lossless transform encoding, and lossy rgba8 or gray8 to YUV420 conversionRIFF parsing, VP8 and VP8L entropy coding, VP8 prediction and transforms, measured-faster paired-row rgb8 conversion, animation, small images, and images beyond configured limits
Runtime behavior. Modules load lazily and are reused. SIMD is preferred when the runtime validates it, with scalar WASM and then TypeScript as fallbacks. Node retains native zlib; browsers retain platform compression streams. Codec parsing, metadata, limits, CRC validation, sources, and sinks remain in JavaScript, and pixel processing remains bounded by rows or blocks.

Image

Every transform returns a new immutable Image sharing the same input context. No pixel work occurs until an output method is called.

metadata()

Reads source metadata and applies planned transforms to width, height, format, alpha, and orientation fields without executing the pixel pipeline.

returns Promise<ImageMetadata>

autoOrient()

Applies EXIF orientations 1–8 when present. Orientations that reorder rows use bounded-memory temporary tile storage.

returns Image

keepExif()

Opts into retaining source EXIF in a compatible output. EXIF is stripped by default; pixel reorientation normalizes a retained orientation tag to 1.

returns Image

keepIcc()

Opts into retaining a compatible source ICC profile instead of converting tagged samples and stripping the profile.

returns Image

crop(options)

Crops to an integer rectangle. x and y may be zero; width and height must be positive. Out-of-bounds crops fail.

returns Image

resize(options)

Resizes by one dimension or two. Supports contain, cover, fill, inside, and outside fits. Lanczos 3 is the default; nearest and bilinear sampling are available for explicit lower-cost resizing.

returns Image

window(options)

Maps numeric grayscale samples to gray8 through an explicit center and width, overriding the source's normal display range for this pipeline.

returns Image

lut(options)

Applies a 256-entry lookup table. gray8 input may produce gray8, rgb8, or rgba8; rgba8 input uses independent interleaved channel tables and remains rgba8.

returns Image

rotate(degrees, options?)

Rotates clockwise by any finite number of degrees. Quarter turns are exact; other angles use bilinear sampling and expand the canvas.

returns Image

flip()

Mirrors pixels vertically, from top to bottom.

returns Image

flop()

Mirrors pixels horizontally, from left to right.

returns Image

jpeg(options?)

Appends JPEG output. Quality is 1–100; background accepts transparent, #RRGGBB, or #RRGGBBAA; chroma subsampling is 420, 422, or 444.

returns Image

png(options?)

Appends 8-bit PNG output. Node supports compression levels 0–9; browser CompressionStream output currently supports the default level 6.

returns Image

webp(options?)

Appends static lossy or lossless WebP output. Lossy quality is 1–100. Lossless WebP suits graphics and screenshots; prefer lossy WebP for photographs, or compare with PNG when exact lossless output is required.

returns Image

bmp(options?)

Appends BMP output. The alpha option selects 32-bit RGBA or 24-bit RGB output.

returns Image

hdr(options?)

Appends Radiance RGBE output. Native float RGB remains HDR; display pixels are converted through the normal numeric path. Optional exposure and gamma values are written as header metadata.

returns Image

qoi(options?)

Appends lossless QOI output with explicit RGB or RGBA channels and sRGB or linear colorspace metadata.

returns Image

pbm(), pgm(), ppm(), pam(), pfm()

Append a specific Netpbm variant. Integer encoders support documented ASCII, binary, and 8-bit or 16-bit choices. PFM supports native float32 grayscale or RGB with explicit endianness and scale.

returns Image

tga(options?)

Appends 24-bit RGB or 32-bit RGBA TGA output with optional lossless RLE.

returns Image

tiff(options?)

Appends canonical Classic TIFF output: little-endian, chunky 8-bit RGB or RGBA, independently Deflate-compressed strips, and horizontal prediction. Node supports compression levels 0–9; browser CompressionStream output supports level 6.

returns Image

encode(format, options?)

Generic equivalent to the format-specific encoder methods for jpeg, png, webp, bmp, hdr, qoi, netpbm, tga, and tiff. Use the Netpbm format option to select PBM, PGM, PPM, PAM, or PFM.

returns Image

toBuffer(options?)

Executes the pipeline and collects encoded chunks into Node.js bytes. The runtime value remains a Buffer, exposed through the portable Uint8Array public type so consumers do not need Node ambient declarations.

returns Promise<Uint8Array>

toUint8Array(options?)

Executes and returns portable encoded bytes. Available in Node and browsers.

returns Promise<Uint8Array>

toBlob(options?)

Executes and returns a Blob with the registered output codec MIME type. Intended for browser previews, uploads, and downloads.

returns Promise<Blob>

toSink(sink, options?)

Executes into a custom ImageSink for streaming or application-owned output.

returns Promise<void>

toFile(path, options?)

Node-only file output. If encoding fails or is cancelled, the partial output file is removed.

returns Promise<void>
Progressive output. Set progressive: true to emit a refinement-based progressive JPEG. This retains compact quantized coefficient planes until all scans are written; baseline output remains the bounded-row default.

Operation options

CropOptions

TypeScript
interface CropOptions {
  x: number
  y: number
  width: number
  height: number
}

ResizeOptions

TypeScript
type ResizeFit = 'contain' | 'cover' | 'fill' | 'inside' | 'outside'
type ResizeKernel = 'nearest' | 'bilinear' | 'lanczos3'
type Background = 'transparent' | `#${string}`

type ResizeOptions = {
  width?: number
  height?: number
  fit?: ResizeFit
  position?: 'center'
  background?: Background
  withoutEnlargement?: boolean
  kernel?: ResizeKernel
} // width or height is required
OptionDefaultNotes
fitcover with two dimensionsFit, position, and background require both width and height.
positioncenterCurrently center only; valid with contain.
backgroundtransparentValid with contain. Accepts six- or eight-digit hex.
kernellanczos3Lanczos 3 minimizes downscale aliasing. Bilinear is faster but lower quality; nearest preserves hard pixel edges.
withoutEnlargementfalseCaps the scale at 1 where the fit permits it.

WindowOptions and LutOptions

TypeScript
interface WindowOptions {
  center: number
  width: number
}

interface LutOptions {
  table: Uint8Array // 256 × output channel count, interleaved
  format: 'gray8' | 'rgb8' | 'rgba8'
}

Windowing precedes geometric transforms and converts native numeric grayscale blocks directly to gray8. A grayscale LUT treats each table entry as an output color. An RGBA LUT maps each input channel through the corresponding interleaved channel table.

RotateOptions

TypeScript
interface RotateOptions {
  background?: Background // transparent by default
}

Positive degrees rotate clockwise. Arbitrary angles expand to the smallest integer canvas that contains the result and use the requested six- or eight-digit hex background, or transparency by default.

Encoder options

TypeScript
interface JpegEncodeOptions {
  quality?: number                // 1–100
  progressive?: boolean          // refinement-based output; false by default
  background?: Background
  chromaSubsampling?: '420' | '422' | '444'
  restartInterval?: number       // 0–65535; 0 disables restart markers
}

interface PngEncodeOptions { compressionLevel?: number } // 0–9
interface WebpEncodeOptions { lossless?: boolean; quality?: number }
interface BmpEncodeOptions { alpha?: boolean }
interface HdrEncodeOptions { exposure?: number; gamma?: number }
interface QoiEncodeOptions {
  channels?: 3 | 4
  colorspace?: 'srgb' | 'linear'
}
interface NetpbmEncodeOptions {
  format?: 'pbm' | 'pgm' | 'ppm' | 'pam' | 'pfm'
  ascii?: boolean
  bitDepth?: 8 | 16
  endian?: 'little' | 'big'
  scale?: number
}
interface TgaEncodeOptions { alpha?: boolean; rle?: boolean }
interface TiffEncodeOptions {
  compression?: 'deflate'
  predictor?: 'horizontal'
  layout?: 'strips'
  compressionLevel?: number       // 0–9; browser supports 6
}

EXIF and ICC preservation

Encoders strip EXIF and ICC metadata unless the pipeline calls keepExif() or keepIcc(). The two choices are independent and apply when the pipeline executes.

FormatRead for preservationWrite on output
JPEGEXIF and RGB ICCEXIF and RGB ICC
PNGEXIF and compatible ICCEXIF and compatible ICC
WebPEXIF and RGB ICCEXIF and RGB ICC
HEIF / HEIC (experimental)EXIF and RGB ICCNot implemented
TIFFCompatible ICC onlyCompatible ICC only
Other formatsNot implementedNot implemented

With keepIcc(), tagged samples remain in their source color space and the original profile is embedded in the output, avoiding a double conversion. The profile must match the output pixel model. With keepExif(), autoOrient(), rotate(), flip(), and flop() normalize a retained EXIF orientation to 1 because the pixels have already moved.

Explicit capability boundary. Asking for preservation across an unsupported source or output combination throws an ImageError instead of silently dropping requested metadata.

ImageMetadata

TypeScript
interface ImageMetadata {
  width: number
  height: number
  format: string
  mimeType: string
  hasAlpha: boolean
  orientation?: number
  colorSpace?: string
  colorProfile?:
    | { kind: 'icc'; description?: string }
    | {
        kind: 'nclx'
        primaries: number
        transferCharacteristics: number
        matrixCoefficients: number
        fullRange: boolean
      }
  bitDepth?: number
  chromaSubsampling?: '400' | '411' | '420' | '422' | '440' | '444'
  codecProfile?: number
  frames?: number
}

Optional fields depend on what the container and registered codec can determine safely. HEIF and AVIF expose validated ICC descriptions when present or the numeric nclx primaries, transfer characteristics, matrix coefficients, and range. Animated formats may report frame counts even when the current pixel decoder handles only a still subset.

Scientific raster API

Import display mapping, volume operations, statistics, spectral helpers, and the reader registry from purejsimage/scientific. Import concrete formats from their purejsimage/scientific/readers/* entries. Explicit registries return labeled-axis ScientificDataset values and native RasterBlock samples instead of registering photographic ImageCodec entries.

createScientificLibrary({ readers })

Creates an immutable local reader registry. open(context) returns a ScientificDocument; each summary has a stable ID, labeled descriptor, and structured source identity.

returns ScientificLibrary

dataset.readSeries(request)

Reads bounded native one-dimensional spectra or profiles from their single true axis. The descriptor uses planeReads: { kind: 'none' } and advertises exact seriesReads axes; emitted ScientificSeriesBlock values are tightly packed canonical big-endian segments with explicit start, length, format, data, and optional release ownership. normalizeScientificSeriesReadRequest() validates selections before I/O, while readScientificSeriesFromPlane() is the explicit bounded row/column fallback for existing plane readers.

returns AsyncIterable<ScientificSeriesBlock>

encodeGsf(options)

Exported by purejsimage/scientific/readers/gsf; writes a deterministic GSF header, aligned padding, metadata, and exact little-endian float32 payload.

returns Uint8Array

gsfReader, enviReader, fitsReader, mrcReader, cbfReader, tiffReader, omeTiffReader

Explicit first-party readers from individual package entries. ENVI identities include both header and binary resources; ordinary TIFF preserves native series/pages/levels; FITS and OME-TIFF use stable per-dataset IDs.

ScientificReader values

dataset.descriptor.spatialReference

Optional typed raster georeferencing. Ordinary GeoTIFF exposes CRS authority/code and citation when known, a six-parameter pixel-to-model affine, an inverse when invertible, model bounds, pixel-is-area/point semantics, scalar or component nodata, and bounded JSON-safe GeoTIFF evidence. SubIFD levels expose their corresponding spatial reference. Apply [a,b,c,d,e,f] as modelX = a*x + b*y + c and modelY = d*x + e*y + f; readPlane({ x, y, width, height }) remains in raster pixel coordinates.

TypeScript
const spatial = dataset.descriptor.spatialReference
if (spatial?.pixelToModel) {
  const [a, b, c, d, e, f] = spatial.pixelToModel
  console.log(a * x + b * y + c, d * x + e * y + f, spatial.crs)
}
ScientificSpatialReference | undefined

inspectCog(document)

Exported by purejsimage/tiff. Performs bounded structural inspection without decoding pixels and reports TIFF/BigTIFF, byte order, IFD and SubIFD paths, overview dimensions, tile geometry and offsets, compression audit status, band/sample layout, and likely COG issues. It is a diagnostic rather than formal standards certification.

TypeScript
const document = await openTiffDocument(source)
const report = await inspectCog(document)
console.log(report.likelyCog, report.directories, report.issues)
Promise<CogInspection>

createScientificPathContext(path)

Node-only helper from purejsimage/scientific/node that creates a source and constrained companion resolver.

returns Promise<ScientificOpenContext>

sliceScientificVolume(dataset, options)

Returns a lazy cross-section over caller-selected labeled display axes without materializing the source volume.

returns ScientificDataset

projectScientificVolume(dataset, options)

Returns a lazy labeled-axis minimum, maximum, or mean projection. It keeps only bounded output-row accumulators and uses float64 accumulation for means.

returns ScientificDataset

measureScientificPlane(dataset, options)

Resolves an explicit, dataset min/max, or bounded approximate percentile range. The result includes the range, finite sample count, sampled value count, ROI, and channel. Dataset and percentile modes scan the selected source plane once; explicit mode does not.

returns Promise<ScientificPlaneMeasurement>

measureScientificPlane(dataset, { statistics: ... })

Optionally computes minimum, maximum, mean, population standard deviation, finite and invalid counts, bounded sampled percentiles, and a bounded histogram. Statistics ignore NaN, infinity, and the dataset no-data sentinel.

returns Promise<ScientificPlaneMeasurement>

renderScientificPlane(dataset, options)

Selects a supported ordered pair from descriptor.capabilities.planeReads, fixes every remaining axis explicitly, and maps native samples to bounded RGB blocks. Dataset and percentile ranges scan before the returned pixel iterator reads the plane again. Reuse a measured explicit range to avoid that repeat scan when palette, transfer, or relief changes.

returns Promise<ScientificRenderedPlane>

nearestSpectralChannel() and renderSpectralBand()

Select the nearest metadata wavelength and expose both the requested and actual channel center before producing display pixels.

renderSpectralComposite()

Maps requested red, green, and blue wavelengths to actual channels and returns bounded false-color RGB blocks.

integrateSpectralRange() and bandRatio()

Produce native float64 derived raster datasets without an RGBA intermediate. Invalid, no-data, and zero-denominator results remain NaN.

Quantitative/display boundary. Range selection, display transfers, palettes, relief, and false color affect only emitted display pixels. Linear, log, sqrt, and asinh are applied after the selected range maps to a normalized interval. Relief is display hillshading in sample coordinates and does not use physical X/Y spacing. These operations do not rewrite source samples or metadata.

Scientific Raster Explorer · ENVI guide · GSF guide · FITS guide · MRC guide · CBF guide · Volume operations

Inputs & sources

TypeScript
type BrowserImageInput = ArrayBuffer | Blob | ImageSource | Uint8Array
type NodeImageInput = BrowserImageInput | string

interface ImageSource {
  readonly size: number
  read(offset: number, length: number, options?: { signal?: AbortSignal }): Promise<Uint8Array>
}

MemorySource

Zero-copy reads over an ArrayBuffer or Uint8Array.

BlobSource

Range reads through Blob.slice().

FileSource

Node-only. Use await FileSource.open(path) to build a file-backed source explicitly.

HttpRangeSource

Optional bounded HTTP range reads with request and byte statistics. Import from purejsimage/sources/http-range. Use openSignal for the probe, lifetimeSignal for the source, and a per-read signal for one consumer. A single consumer abort does not cancel a shared block fetch still needed by others.

For an in-range read, custom read() implementations must return exactly min(length, size - offset) bytes as a Uint8Array, or reject when the backing read fails. Returned bytes may be reused or invalidated when the next read begins. Short, oversized, detached, and rejected reads surface as ImageError results. Public open, metadata, decode, raster, whole-slide, source-read, and terminal output options accept an optional AbortSignal; cancellation aborts the active sink and is rethrown as AbortError.

Safety limits

Pass a partial limits object to open(). Every provided value must be a positive safe integer.

LimitDefaultEnforcement
maxWidth100,000Declared and transformed width
maxHeight100,000Declared and transformed height
maxPixels268,435,456Width × height using overflow-safe arithmetic
maxInputBytes134,217,728 (128 MiB)Before source contents are read
maxFrames1,000Declared frame count
maxDecodedBytes1,073,741,824 (1 GiB)Worst-case dimensions and streaming expansion
Configure application limits. The defaults are general guardrails, not a recommendation that every deployment accept 100,000-pixel dimensions or 128 MiB inputs.

ImageError

TypeScript
type ImageErrorCode =
  | 'INVALID_INPUT'
  | 'LIMIT_EXCEEDED'
  | 'TRUNCATED_INPUT'
  | 'UNSUPPORTED_FORMAT'
  | 'UNSUPPORTED_OPERATION'
CodeMeaning
INVALID_INPUTMalformed image structure, invalid options, dimensions, or source contract.
LIMIT_EXCEEDEDA configured input, dimension, frame, decoded-byte, or temporary-storage budget was exceeded.
TRUNCATED_INPUTThe source ended before the codec could read required bytes or pixels.
UNSUPPORTED_FORMATThe format is unknown or its codec was not registered.
UNSUPPORTED_OPERATIONThe format is recognized, but the requested coding feature, decode subset, or encoder is not implemented.

Advanced contracts

The Node root and browser entry export the primitives used to author custom codecs, accelerators, and sinks: ImageCodec, ImageCodecAccelerator, ImageLibraryConfiguration, ImageDecoder, ImageEncoder, CodecRegistry, ImageSink, Uint8ArraySink, PixelBlock, PixelFormat, and BufferPool. Node additionally exports BufferSink, FileSink, and FileSource.

These interfaces support custom codecs and sinks. A decoder yields ordered pixel blocks; an encoder consumes them and writes encoded chunks to a sink. Implementations must preserve the release callback and source-buffer lifetime contracts.

View public exports on GitHub →