PureJsImage v0.8.0
Added
- Extended the isolated Imazen codec-corpus harness and independent baselines across JPEG, PNG,
WebP, TIFF, GIF, and BMP, covering complete decode-to-PNG round trips, structured rejection,
timeouts, crashes, memory failures, upstream categories, and format-specific feature groups. - Added an explicitly imported first-party Rust/WASM PNG accelerator for common non-interlaced
8-bit grayscale, RGB, and RGBA scanline decode and encode, retaining native runtime zlib,
bounded-row memory, scalar fallback, and the TypeScript reference for every ineligible workload. - Added a separate
purejsimage-wasmcompetitor benchmark engine and seven-engine speed, memory,
and quality reports so the explicitly registered JPEG/PNG accelerators can be compared directly
with the unchanged default TypeScript package. - Added an explicit optional first-party Rust/WASM baseline JPEG decoder that fuses entropy decode,
IDCT, chroma upsampling, and RGB conversion while preserving bounded MCU-row output, exact
TypeScript parity, lazy warm reuse, and clean fallback for unsupported or unhelpful workloads. - Added optional first-party scalar and SIMD Rust/WASM baseline JPEG encoders with bounded MCU-row
input, JavaScript-owned sink backpressure, RGB/RGBA/grayscale and 4:2:0/4:2:2/4:4:4 parity, explicit
workload selection, plus an ABI-compatible SIMD JPEG decoder artifact with scalar fallback.
Specialized entropy writes, validated-row input reads, chroma sampling, Huffman lookup, and paired
decoder upsampling reduce pinned warm encoder time by 61.7%-66.0% versus TypeScript and pinned warm
decoder time by 58.4%, while retaining the same output contracts and bounded memory. - Added first-party refinement-based progressive JPEG encoding for grayscale and 4:2:0, 4:2:2,
and 4:4:4 YCbCr output, with compact coefficient limits, per-scan restart markers, independent
pixel validation, browser coverage, and isolated runtime/RSS/size benchmarks. - Added jSquash as an isolated WebAssembly competitor using its pinned JPEG, PNG, WebP, and resize
packages, with documented Node WASM initialization, explicit unsupported classifications,
startup/package-footprint measurements, a codec-matched bundle comparison with exact package
versions, validated workflow results, and regenerated charts. - Added premultiplied-RGBA PSNR against independent exact-area references to quality-enabled
competitor workflows, with quality recorded outside timing and peak-RSS sampling, included in
Markdown and JSON reports, and published as a dedicated comparison chart. - Added a fully client-side browser conversion demo with content-based format detection, optional
transforms, honest timing and memory reporting, and an artifact-only GitHub Pages deployment
that keeps its generated all-codec bundle out of repository history.
Changed
- Moved HEIF/HEIC decode to the explicit
purejsimage/codecs/experimental/heicentry, removed it fromallCodecsand
the default browser demo, and documented that MIT grants no third-party HEVC
patent rights. - Documented when native Sharp is the better performance choice and added measured Lambda sizing
guidance: 256 MiB completed every pinned 12-megapixel workflow, but 1024 MiB cut the JPEG-to-WebP
warm operation from 10.6 seconds to 2.5 seconds while peak use remained about 120 MiB.
Fixed
-
Kept the nested packed-declaration smoke test operational during
npm pack --dry-run, so the
documented release gate validates package contents instead of inheriting npm's outer dry-run mode. -
JPEG decoding now treats sampling factors as one for single-component non-interleaved scans,
tolerantly preserves completed progressive coefficients when a partial scan reaches a DHT, SOS,
or EOI boundary, and decodes AVI1/MJPEG baseline frames that omit standard Huffman tables. Strict
progressive decoding continues to reject partial entropy. -
Recognized 12-bit and arithmetic-coded JPEG inputs now fail with
UNSUPPORTED_OPERATION,
separating deliberate codec boundaries from supported-subset failures in the Imazen conformance
baseline. -
TIFF decoding now defers BigTIFF offset validation until an inline value actually needs an
external offset, recognizes legacy LSB-packed LZW streams with late code-width changes, accepts
legacy tile tables in strip tags, bounds padded final YCbCr LZW strips, reconstructs multi-strip
old-style JPEGs with omitted legacy fields, and decodes one-dimensional Group 3 fax rows without
EOL markers. Recognized 64-bit sample layouts remain structured unsupported boundaries. BMP RLE4
now accepts the single encoded padding pixel used for odd-width scanlines while retaining overrun
rejection. -
Animated GIF pixel decode now fails with
UNSUPPORTED_OPERATIONinstead of silently discarding
animation; callers can explicitly request the supported first image withopen(input, { frame: 0 }). -
Baseline JPEG restart recovery now defaults to tolerant decoding for malformed real-world files;
passopen(input, { tolerantDecoding: false })to require strict restart sequencing. Explicit
Rust/WASM decoding now implements the same bounded recovery instead of being skipped. JPEG and
PNG decode accelerator setup or midstream failures now resume through their TypeScript decoders
without duplicate rows. Focused scalar and SIMD PNG regressions keep trailingIENDdata,
full-rangecICP, and ICC v4 RGBmABcolor conversion at parity without silently falling back.
The same corpus-driven work completed those compatibility fixes for the TypeScript reference. -
Removed ambient
Bufferreferences from the Node entry's published declarations so strict
TypeScript consumers can compile the zero-dependency package without installing@types/node. -
Changed the default resize kernel from bilinear to scale-aware Lanczos 3 so ordinary downscales
no longer discard most source samples and alias heavily; strong downscales now use bounded
streaming box pre-shrink before the final Lanczos pass, format-specialized horizontal kernels,
opaque-RGBA handling, and a fixed retained-row ring instead of a map. Bilinear remains available
as an explicit faster, lower-quality option, and benchmark reports identify cross-kernel
comparisons. On the pinned profiles, the 4× PNG resize fell from 1,253 ms to 530 ms and the
10× 100-megapixel downscale fell from 8,455 ms to 2,408 ms. -
Allowed the browser demo to convert the supported primary image from iPhone-style MPF JPEGs while
warning that auxiliary images and gain maps are not preserved; true animated inputs remain blocked. -
Reduced progressive JPEG output with two-pass, scan-specific optimized Huffman tables; the pinned
quality-80 benchmark moved from 3.29% larger than baseline to 7.26% smaller with identical decoded
PSNR. -
Corrected AV1 quantization-matrix coefficient-axis lookup and adjusted matrix
dimensions for 64-point transforms, with q30-q90 YUV and displayed-RGB gates
against independent libaom, dav1d, Sharp, and Chromium decoders. -
Reduced lossless WebP output for screenshot-style pixels with block-adaptive VP8L predictors,
adaptive color-cache codes, and a deeper bounded match search, while retaining exact independent
libwebp pixel validation and documenting the fixed match-table memory cost. -
Fixed progressive JPEG AC refinement after a zero-run-length symbol so common Sharp/libjpeg
output decodes correctly and can be resized and converted to WebP in Node.js and browsers.