Decode an array from zarr, handling all encoding modes
Zarr array handle
Array metadata from .zattrs
OptionalexpectedElements: number
Expected total elements (for validation)
OptionalzarrRootLoc: Location<Readable>
Zarr root location for resolving array_ref paths (required for array_ref)
Optionalsignal: AbortSignal | null
Optional abort signal forwarded to every chunk read this decode performs (including a resolved array_ref target's), so a caller tearing down mid-fetch can stop the transfer rather than just discard it
Decoded Float32Array
PrivateinferInfer quantization bounds from encoding name
Some encodings have implicit bounds that don't need to be stored:
Encoding name (e.g., "rgb_uint8", "bounded_scalar_uint16")
Bounds [min, max] or null if not inferrable
PrivatedecodeDecode broadcasted array (uniform values)
Format: Shape (1, k) replicated to (n_elements, k)
Raw data array (shape: (1, k))
Target number of elements to replicate to
Feature dimension (e.g., 3 for RGB, 1 for scalar)
Optional_expectedElements: number
Expected total elements (for validation, currently unused)
PrivatedecodeDecode LUT-encoded array
Format: Indices (uint8/uint16) + lookup table Modes:
Array of indices into the lookup table
Lookup table containing unique values
Feature dimension (ignored for scalar mode)
"row" or "scalar" mode
PrivatedequantizeDequantize integer array to floats
Format: uint8 or uint16 → float with bounds [min, max] Delegates to the TypeScript worker-fallback kernels for bit-exact routing parity.
PrivatedecodeDecode log-space encoded scalar array
Format: log1p(value)/max_log → uint8/uint16 Decoding delegates to the shared decode_log_scalar_u8/u16 kernel.
Used for positive scalars with wide dynamic range (e.g., radii)
PrivatedecodeDecode geometric-log scalar (min/max-anchored, reserved zero level).
Level 0 decodes to exactly 0; levels [1, 2^bits - 1] decode to exp(minLog + (u - 1)/(2^bits - 2) * (maxLog - minLog)) — uniform relative precision across the array's own nonzero range. Matches the worker/WASM kernels bit-exactly; Python's f64 decode differs because the viewer rounds the logarithmic anchors to f32 first.
PrivatedecodeResolve array reference (deduplicated array)
Per spec section 7.6, this method:
Path to the target array (from encoding.target)
Content hash for caching/verification (from encoding.hash)
OptionalexpectedElements: number
Expected total elements (for validation)
OptionalzarrRootLoc: Location<Readable>
Zarr root location for path resolution
Optionalsignal: AbortSignal | nullStaticisHelper: Determine if array is encoded
Checks for any encoding metadata in attrs.encoding structure
StaticgetHelper: Get encoding mode from metadata
Returns a string describing the encoding mode
StaticisHelper: Check if encoding is LUT (lookup table)
LUT encoding is special because the lookup table is stored in metadata, so we can load only a range of indices from zarr and still decode correctly. This enables efficient range-based loading instead of loading the full array.
StaticisHelper: Check if encoding is broadcasted (uniform value)
Broadcasted encoding stores a single value that's replicated to all points. For range loading, we just need the single value - no need to extract ranges.
StaticisHelper: Check if encoding is array reference
Array references point to another array for deduplication. For range loading, we can apply optimized loading to the target array.
StaticisHelper: Check if an encoding name means direct stored values.
StaticisHelper: Check if an encoding name is a known LUT encoding.
StaticisHelper: Check if an encoding name is a known log-scalar encoding.
StaticisHelper: Check if an encoding name is a geometric-log scalar encoding (min/max-anchored true-log with a reserved zero level).
StaticvalidateValidate encoding metadata shape before dispatch.
Private StaticvalidateValidate quantization bounds before dequantization.
StaticisHelper: Check if an encoding name is known by the decoder.
StaticisGeneric per-channel quantization encodings: per-column (per-channel) log
(log_perchannel_u8/u16, non-negative), signed-log
(signed_log_perchannel_u8/u16, signed), linear/fixed-point
(linear_perchannel_u8/u16, identity — COORDINATE positions/centers/vertices),
and TRUE-log (geolog_perchannel_u8/u16, wide-range positive — HDR colors).
They carry per-channel scale arrays (col_lo/col_hi) rather than global
bounds, so they are NOT in isQuantizedEncodingName (the global-scale
dequant path); they have their own 'perchannel' load path in the RangeLoader
which fully decodes them to float32 (see range-loader/perchannel.ts). The
scheme is geometry-agnostic; consumers receive decoded float32.
StaticmakeBuild the per-channel dequantizer for a log_perchannel_* /
signed_log_perchannel_* / linear_perchannel_* / geolog_perchannel_*
array. Mirrors the Python decoders (_decode_*_perchannel):
log: x = expm1(lo[c] + level/levels·(hi[c]-lo[c]))
signed-log: y = lo[c] + level/levels·(hi[c]-lo[c]); x = sign(y)·expm1(|y|)
linear: x = lo[c] + level/levels·(hi[c]-lo[c]) (identity; coordinates)
geolog: x = 0 at level 0, else exp(lo[c] + (level-1)/(levels-1)·rng)
(TRUE-log grid, ln-domain scales; HDR colors — always zero-level)
With zero_level: true (current writer for the log/signed-log pair),
level 0 is a RESERVED ZERO (decodes to exactly 0) and nonzero levels
1..2^bits-1 span the nonzero-anchored [lo, hi] with denominator
2^bits-2 — same layout as geolog_scalar. Arrays without the flag keep
the legacy all-levels mapping above. For any other / float32 / direct
encoding it returns the identity, so a raw value passes through unchanged.
(level, col) => value — level is the raw stored integer (as float).
StaticisHelper: Check if an encoding name is quantized (uint8/uint16 with bounds).
StaticisHelper: Check if encoding is quantized (uint8/uint16 with bounds)
Quantized encodings store data in reduced precision (uint8/uint16) with bounds metadata for dequantization. These can be efficiently range-loaded: load only the needed ranges of quantized data, then dequantize.
Includes:
StaticgetGet quantization metadata for range-based decoding
Extracts the bounds needed to dequantize a subset of quantized data. Returns null if not quantized.
Array metadata from .zattrs
Actual zarr array dtype (e.g., 'uint16', '<u2'). Required because Python stores the quantized dtype on the zarr array, not in attrs.dtype.
Private StaticnormalizeNormalize dtype string to canonical format
Handles all NumPy dtype string variants:
StaticgetGet LUT encoding metadata for range-based decoding
Returns the LUT metadata needed to decode a subset of indices. Returns null if not LUT-encoded.
StaticvalidatedValidate a stored lut_mode: absent defaults to 'row' (the Python
encoder omits it for 1-D arrays), but a present-yet-unknown value throws
— matching the worker decoder (workers/data-worker/decode/lut.ts),
which already rejects it. Previously the main thread silently treated
garbage as row mode.
Decode LUT indices directly (for range-based loading)
This allows decoding a subset of indices without loading the full array. The indices can be loaded from zarr using range slicing, then decoded using the LUT from metadata.
Indices loaded from a range of the zarr array
LUT metadata from getLUTMetadata()
Decoded values (Float32Array)
Dequantize quantized data directly (for range-based loading)
This allows dequantizing a subset of quantized data without loading the full array. The quantized ranges can be loaded from zarr using range slicing, then dequantized using the bounds from metadata.
Quantized data loaded from ranges (uint8/uint16)
Quantization metadata from getQuantizationMetadata()
Dequantized values (Float32Array)
Main array decoder class