Skip to content

PureJsImage v0.12.0

Choose a tag to compare

@a-r-d a-r-d released this 19 Aug 00:29
· 49 commits to main since this release

PureJsImage 0.12.0

Added

  • Added a deterministic Cloud Optimized GeoTIFF compatibility corpus, checked compression matrix,
    public bounded inspectCog() structural report, explicit compression ID/name errors, and a
    simulated-HTTP-range viewport benchmark that asserts overview selection and reports requests,
    bytes fetched, cache hits, first decoded tile-block latency, and decoded pixels.

  • Added typed GeoTIFF spatial references to ordinary TIFF scientific dataset descriptors and
    SubIFD levels, including CRS authority/code and citation, six-parameter pixel-to-model affine,
    invertible inverse, model bounds, pixel-is-area/point semantics, scalar or component GDAL nodata,
    and JSON-safe source metadata. Region reads remain in raster pixel coordinates, and malformed
    optional georeferencing does not block native TIFF pixels.

  • Expanded the official common-web (web-codecs) suite with JPEG→AVIF, JPEG→lossy WebP, AVIF
    crop+resize, the Lambda JPEG thumbnail, progressive JPEG resize, and lossless WebP alpha decode.
    The published speed and memory SVG charts include those jobs, and the README now shows both
    charts.

  • Added the explicit purejsimage/scientific/readers/ome-zarr reader for OME-NGFF 0.4 and 0.5
    image multiscales on first-party Zarr v2 and v3 directory stores. Selected planes fetch only
    intersecting regular or sharding_indexed chunks through the existing companion resolver; bytes,
    gzip, zlib, zstd, crc32c, transpose, shuffle, and Blosc 1 (LZ4/zlib/zstd/memcpy) are implemented;
    missing chunks become fill values. Sibling and root NGFF labels become separate datasets with
    image-label colors; plate wells become one dataset per field. A ZIP archive with root-level
    zarr.json or .zgroup opens as a single-file store without companions. Partial last chunks,
    sharded inner endian, Blosc split streams, and the C-Blosc compressor enumeration are handled.
    A pinned IDR 6001240 coarsest-plane slice cross-checks NGFF 0.4 Blosc/LZ4 against 0.5 sharded
    Blosc/zstd. The reader also accepts omitted v3 chunk_key_encoding, exact integer and hex
    fill_values, F-order padded last chunks, numeric OMERO colors, UTF-8 BOM metadata, and
    big-endian shard indexes, and rejects overlapping shard payloads. any-axis-pair planes are
    packed into destination row order. Zarr v2 fill_value: null decodes present chunks and fails
    on absent ones instead of inventing zeros; a present zero-byte chunk is malformed; missing
    shard inners use only the uint64 all-ones sentinel pair. Directory dataset identity includes
    defining metadata plus a session store id; ZIP identity stays the archive source. Chunk lookup
    uses a bounded LRU so maxOpenSources is not a lifetime visit limit. Clipped last chunks no
    longer fail when the nominal chunk exceeds the decode budget; empty optional .zattrs, trailing
    dataset slashes, bare one-byte NumPy dtypes, numcodecs.* codec ids, and case-insensitive
    NaN/Infinity fills are accepted. bioformats2raw 0/, 1/, … series roots and a single nested
    ZIP store prefix are supported; ambiguous multi-root ZIPs stay rejected. Series discovery also
    works without a root .zattrs file, bioformats2raw.layout may be a numeric string, and
    seriesCount counts series groups rather than every collected dataset. ZIP stores named
    *.zarr / *.ome.zarr probe as OME-Zarr, macOS __MACOSX/ sidecars no longer make a unique
    nested root look ambiguous, a root labels list does not hide bioformats2raw series, and extra
    integer series beyond maxDatasets raise LIMIT_EXCEEDED. ZIP probes use name-plus-magic
    evidence and do not open the archive. Generic Zarr v2 groups are not detected without NGFF
    attributes. Zarr storage fill is recorded as zarrFill rather than noDataValue; v3 rejects
    null and non-numeric integer fills; shard-index codecs must declare endian; nonempty
    storage_transformers are unsupported; NGFF axes must be time, then channel or custom, then
    2–3 spatial axes; OMERO colors must be six hex digits or 0–0xffffff; and the chunk cache is
    bounded by maxCachedChunkBytes. Pinned IDR slices now include 6001240 sibling labels, an
    IDR0010 0.5 plate well, an IDR0001 0.4 plate field, and an IDR0101 translation image. BloscLZ,
    Snappy, bitshuffle, tables, RFC-9 zip-comment/jsonFirst requirements, nonempty storage
    transformers, repeated transpose codecs, and writers remain explicit unsupported operations.
    ZIP members are limited before decompression; sharded plane reads resolve each shard once;
    bioformats2raw.layout must be 3; and directory calibration cites the resolved metadata
    resource id. Plane-session caches stay bounded and layer over the persistent chunk LRU;
    a source larger than maxCachedChunkBytes is held at most as one transient shard.

Changed

  • Speed up first-party AVIF decode after the retained inverse-transform skip: decode equiprobable
    bits without a throwaway CDF, skip zero-coefficient dequant, upsample interior 4:2:0 chroma
    without edge clips, renormalize the arithmetic coder with integer shifts, clamp YUV bytes with
    integer rounding, hoist SGR prefix-row bases, and inline the common 8-bit 4:2:0 convert. Local
    avif-fox-resize-jpeg fell from 589 ms to 500 ms (−15%) with an exact output hash; neighbor
    avif-fox-full-png improved 11%. The Imazen AVIF survey stayed 36/36 decoded with maximum RGB
    error 2; post-filter, color, high-bit, tile, q-matrix, and common-photo oracles were unchanged.
  • Speed up first-party AVIF inverse transforms by reusing residual scratch and skipping 1D
    transforms on all-zero rows and columns. Local avif-fox-resize-jpeg fell from 621 ms to 589 ms
    (−5%) with an exact output hash. The Imazen AVIF survey stayed 36/36 decoded with maximum RGB
    error 2; post-filter, high-bit, tile, q-matrix, and common-photo oracles were unchanged.
  • Speed up first-party AVIF loop restoration by specializing the 8-bit SGR box filter, restoring
    8-bit SGR/Wiener as unit-width tiles in 8-row bands, and applying interior Wiener 7-tap filters
    directly from the CDEF plane. Local avif-fox-resize-jpeg fell from 838 ms to 623 ms (−25%) with
    an exact output hash; neighbor avif-fox-full-png improved 18%. High-bit restoration stays on
    4-wide 4-row tiles so Int32 prefix squares do not overflow. The Imazen AVIF survey stayed 36/36
    decoded with maximum RGB error 2.
  • Fuse 8-bit AC Huffman prefix decoding into scaled JPEG block decode. Local jpeg-resize-1200
    fell from 543 ms to 511 ms (−7%) with an exact bitstream hash; neighbor jpeg-crop-resize
    improved 3.9% and northstar-photo-pipeline improved 3.4%. Imazen JPEG stayed 39 pass / 2
    unsupported / 167 rejected-safely / 46 accepted.
  • Speed up JPEG resize-to-encode pipelines by unrolling the scale-2 4×4 IDCT, skipping vertical
    chroma bilinear on 4:2:2 (chroma already has full vertical resolution), and unrolling the encoder
    DCT. Local jpeg-resize-1200 fell from 715 ms to 543 ms (−24%) with an exact bitstream hash;
    neighbor jpeg-crop-resize improved 18%. Imazen JPEG stayed 39 pass / 2 unsupported / 167
    rejected-safely / 46 accepted.
  • Speed up scaled JPEG decode by skipping unused AC store after the last zigzag the reduced IDCT
    reads, fusing leftover Huffman bit skips, unrolling the scale-4 2×2 IDCT, stopping restart
    indexing once the crop target is passed, and inlining leftover-AC skip on the entropy reader.
    Official northstar-photo-pipeline fell from 1181 ms to 802 ms (−32%) on top of the previous
    scaled-IDCT work, with an exact bitstream hash. Neighbor jpeg-crop-resize improved 13.5%;
    jpeg-resize-1200 kept its exact hash. Imazen JPEG stayed 39 pass / 2 unsupported / 167
    rejected-safely / 46 accepted.
  • Speed up large JPEG crop-then-resize pipelines by snapping unaligned decoder crops to a
    containing scale-aligned box so scaled IDCT can run. Official northstar-photo-pipeline fell
    from 2857 ms to 1181 ms (−59%). Pixel samples stayed inside the documented ±8 tolerance; the
    lossy JPEG bitstream changed as expected. Aligned neighbors kept exact hashes. Imazen JPEG
    stayed 39 pass / 2 unsupported / 167 rejected-safely / 46 accepted.
  • Speed up JPEG-to-PNG conversion by recycling decoder row buffers after encode, specializing
    adaptive PNG filter scoring for RGB8, and skipping bilinear luma interpolation when luma is
    already full resolution. Official jpeg-to-png fell from 552 ms to 444 ms (−20%) with a 6.5%
    peak-RSS drop on the recycle path; neighbor jpeg-resize-1200 improved 4.5%. Output hashes and
    the Imazen JPEG/PNG corpora were unchanged.
  • Fail full official web-codecs and competitors benchmark runs when any matched pass/pass wall
    median is more than 10% slower than the published headline snapshot. Single-workflow hillclimb
    runs are not gated.
  • Publish web-codec and competitor benchmark charts as SVG instead of rasterizing them to PNG.
  • Speed up first-party AVIF decode after the retained restoration gather/prefix work: hoist SGR
    prefixes, unroll Wiener and SGR blend, copy interior CDEF windows, reuse inverse-transform
    scratch buffers, specialize 4:2:0 chroma upsample, and specialize 8-bit Wiener rounding. Official
    avif-fox-resize-jpeg fell from 1452 ms to 803 ms (−45%) and avif-fox-full-png from 1573 ms to
    987 ms (−37%) on the 2026-08-17 web-codec snapshot, with unchanged output hashes.
  • Speed up first-party lossless WebP encoding by replacing the shifting LZ77 candidate table with a
    ring buffer, recording match tokens once for histogram and bitstream emission, and scoring color
    cache sizes in a single scan. Isolated 1200x480 effort-4 encode of transparent-logo-1200x480
    fell from 166 ms to 100 ms with an unchanged bitstream.
  • Speed up first-party lossy WebP encoding by adding the DC predictor during reconstruction instead
    of prefilling each 4x4, and by finalizing RGB8 chroma in the 2x2 write. Isolated 1200x900
    quality-80 encode of the tundra frame fell from about 44 ms to 32 ms with an unchanged bitstream.