Skip to content

PureJsImage v0.8.0

Choose a tag to compare

@a-r-d a-r-d released this 10 Aug 03:13
· 296 commits to main since this release

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-wasm competitor 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/heic entry, removed it from allCodecs and
    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_OPERATION instead of silently discarding
    animation; callers can explicitly request the supported first image with open(input, { frame: 0 }).

  • Baseline JPEG restart recovery now defaults to tolerant decoding for malformed real-world files;
    pass open(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 trailing IEND data,
    full-range cICP, and ICC v4 RGB mAB color conversion at parity without silently falling back.
    The same corpus-driven work completed those compatibility fixes for the TypeScript reference.

  • Removed ambient Buffer references 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.