Expand description
JPEG XL (JXL) codec — decoder-side header parsing.
JPEG XL is ISO/IEC 18181 (final specification 2022). It supersedes classic JPEG with a modal design that separates a “VarDCT” path (variable-size DCT + LF/HF subbands, quality-competitive with AVIF and modern JPEG) from a “Modular” path (grid-of-pixels predictor + MA-tree range coder, strong at lossless + non-photo material).
This crate currently ships:
- Container + signature detection for both JXL wrappings:
raw codestream (
FF 0A) and ISOBMFF-wrapped (00 00 00 0C 4A 58 4C 20 0D 0A 87 0A), including extraction of the codestream fromjxlc/jxlpboxes. - An LSB-first
bitreader::BitReadermatching the reference bit packing used by the codestream. - Parsing of the codestream preamble:
metadata::SizeHeaderand themetadata::ImageMetadatafields up tonum_extra_channels(bit depth, orientation, preview/animation flags). Fuller ColorEncoding + ToneMapping decoding is deferred. - Modular sub-bitstream pixel decode (per the 2019 committee draft,
Annexes C.9 + D.7), made of:
abrac::Abrac— the bit-level adaptive range coder (D.7);begabrac::Begabrac— bounded-Exp-Golomb integer coder over a known signed range (D.7.1);matree::MaTree— the meta-adaptive decision tree that picks a per-context BEGABRAC for each pixel (D.7.2 / D.7.3);predictors— the five named pixel predictors (Zero, Average, Gradient, Left, Top) from C.9.3.1;modular— the channel header parser plus the per-pixel property + predictor + entropy decode loop.
The integrated registered decoder is not yet wired: the registered
make_decoder reports Error::Unsupported because the surrounding
codestream framing (FrameHeader + TOC + frame-byte alignment) is not
yet wired to the per-channel path. Programs that only need
probe-level information (dimensions, bit depth) should call
probe directly; programs that want to drive the per-channel
Modular decode end-to-end should instantiate
modular::decode_single_channel against a hand-built fixture
(unit tests in modular show the expected wire format).
Follow-up work (tracked for the eventual landing PR):
- GlobalModular wiring (C.4.8) so the FDIS path can actually drive the Modular sub-bitstream end-to-end.
- Squeeze inverse transform (I.3) for multi-resolution Modular images.
- VarDCT-path decoder (variable-size DCT + LF/HF, Chroma-from-Luma, Gaborish smoothing, EPF) — out of scope for this round.
- MABrotli / MAANS entropy coders (the 2019 committee draft’s
entropy_coder∈ {1, 2}); only MABEGABRAC (entropy_coder == 0) is implemented today.
§FDIS 18181-1:2021 layer
In addition to the committee-draft pipeline above, the FDIS layer is being built up additively across rounds:
- Round 1:
ans— FDIS Annex D entropy decoder (prefix codes, ANS, distribution clustering, hybrid integer coding). - Round 2:
extensions— A.5 Extensions;metadata_fdis— full A.6 ImageMetadata refresh including ColorEncoding, ToneMapping, ExtraChannelInfo, AnimationHeader, OpsinInverseMatrix, PreviewHeader;frame_header— C.2 FrameHeader bundle including Passes, BlendingInfo, RestorationFilter;toc— C.3 TOC with Lehmer-code permutation decoder driven by the round-1 ANS layer;ans::cluster::read_general_clustering— D.3.5 general path. - Round 3 (planned): GlobalModular wiring + cjxl fixture decode.
§Round-1 (2024-spec) status (this commit)
make_decoder returns a live decoder ([JxlDecoder]) that handles
the simplest end-to-end Modular bitstreams:
- Raw codestream OR ISOBMFF wrapping.
- Grey (1 plane) OR RGB (3 planes), 8 bits per sample (integer).
- Single-group, single-pass frame (
num_groups == 1 && num_passes == 1). nb_transformsarbitrary at the parse level (TransformInfo bundles per H.7 are decoded for any nb_transforms > 0); inverse application of Palette / Squeeze defers to round 2 with a cleanError::Unsupportedexit point. RCT (no channel-list change) passes through the layout step.- Multi-leaf MA tree evaluated end-to-end (decision-node
property[k] > valuetraversal per H.4.1). use_global_treeis honoured.- No Patches / Splines / NoiseParameters — those are LfGlobal features round 2 will land alongside the VarDCT path.
- No ICC profile (Annex E.4).
- Predictor 6 (Annex H.5 Self-correcting) only resolved at the (0, 0) origin; full WP defers to round 2.
The acceptance fixture for round 1 is pixel-1x1.jxl (1×1 RGB
lossless, 22 B): decodes to R=255 G=0 B=0 matching its
expected.png.
Anything outside this envelope returns
Error::Unsupported at the
relevant gate point. Wider coverage (VarDCT, Squeeze inverse,
Palette inverse, ICC, full WP predictor 6) lands in round 2+.
§Round-6 (2024-spec) additions
- Annex E.4 ICC profile decode (
icc): the 7-state-equivalent entropy-coded ICC byte stream (41 pre-clustered distributions +IccContext(i, b1, b2)41-context function) is decoded into the final ICC profile bytes per E.4.3 (header), E.4.4 (tag list) and E.4.5 (main content). Whenmetadata.colour_encoding.want_icc == truethe bit-position is now correctly advanced past the ICC stream rather than failing withError::Unsupportedoutright; the decoded bytes are validated for the “acsp” magic at offset 36 but are not yet propagated tooxideav_core::VideoFrame(which has no ICC slot in 0.1.x). - G.2 LfGroup / G.4 PassGroup type scaffolding (
lf_group,pass_group): typed bundles + per-group rectangle geometry +(minshift, maxshift)computation per pass. Per-LfGroup and per-PassGroup decode itself is not yet wired (round-7 follow-up gated on the GlobalModularnb_meta_channels-aware refactor — seelf_groupcrate-level docs). - Multi-LfGroup / multi-group / multi-pass / VarDCT frames fail with precise round-7-targeting error messages instead of the round-3 generic “TOC with N entries” rejection.
§Round-7 (2024-spec) additions
Four-piece refactor coordinating the GlobalModular partial-decode path with per-PassGroup decode + post-PassGroup transforms (Annex G.1.3 last paragraph + G.4.2):
- Partial GlobalModular —
global_modular::GlobalModular::readstops decoding at any non-meta channel exceedinggroup_dim(G.1.3 last paragraph). Such channels are zero-filled placeholders inimage.channelsuntil per-PassGroup decode fills them. stream_indexthreading —modular_fdis::decode_channels_at_streamtakes the stream index from Table H.4:0for GlobalModular,1 + 3*num_lf_groups + 17 + num_groups * pass_idx + group_idxfor ModularGroup. Threaded throughget_propertiesso the MA tree’sproperty[1] > valuedecisions select the correct per-section leaf.- TOC layout + empty entries —
toc::Toc::readnow accepts zero-size entries (e.g. an empty LfGroup or PassGroup section is legal when no channel matches that section’s filter). Thedecode_codestreamconsumer addresses sections by their TOC offsets (computed from the entry running sum), with permutation already handled in the round-2 TOC reader. - Post-PassGroup transforms —
global_modular::apply_inverse_transformsis invoked AFTER all PassGroups complete (G.4.2 last paragraph), not insideGlobalModular::read, so the inverse transform sees the fully-assembled image rather than a half-decoded one.
Per-PassGroup decode is in
pass_group::decode_modular_group_into; the
(minshift, maxshift) computation in pass_group::compute_pass_shift_range
models an implicit n=num_ds final-resolution entry that the
printed spec text omits but whose absence would make single-pass
frames decode no modular data (documented SPECGAP).
Round-7 SPECGAP — cjxl 0.11.1 emits multi-group lossless modular
fixtures where the per-cluster ANS distribution’s alphabet_size
exceeds 1 << log_alphabet_size (specifically: alphabet_size=33
against table_size=32 when log_alphabet_size = 5 + u(2) = 5). The
2024 spec text in C.2.5 is silent on the cap (the introductory
paragraph describes D as a 1 << log_alphabet_size-element array
but the listing’s alphabet_size-iterating loop can exceed it).
§Round-8 (2024-spec) additions
Two themes:
-
C.2.5 SPECGAP partial resolution (
ans::distribution):ans::distribution::read_distributionnow returns(D, log_eff)wherelog_effis the effective log_alphabet_size for downstream alias-table sizing. Round 8 picks “interpretation C”: iterate the logcounts loop formin(alphabet_size, table_size)entries, treating the bitstream’s signalledalphabet_size > table_sizeas a soft cap (the encoder advertises a wider alphabet but only serialisestable_sizeper-symbol entries). Empirically validated by parsing the LfGlobal section oftests/fixtures/synth_320_grey/synth_320.jxlcleanly past the round-7 SPECGAP error. Interpretations A (grow D to accommodate alphabet_size) and B (drop writes at i >= table_size, accumulate total_count only over stored entries) were both tried and rejected — seeans::distributioncrate docs for the comparison. The synth_320 fixture is still NOT decoded end-to-end: a separate post-LfGlobal blocker appears (cjxl emits a 0-byte PassGroup[0][0] slot which contradicts the spec’s “all groups carry data per pass” rule); that is round-9+ work. -
VarDCT scaffold (
vardct): the FrameHeader’sencoding == kVarDCTpath is now structurally recognised rather than rejected with a genericError::Unsupported. The module exposesvardct::recognise_vardct_codestreamwhich validates the round-8 envelope (single LF group, single pass, no extra channels, Grey or RGB colour space) and returns avardct::VarDctScaffoldgeometry record. The IDCT-II primitive for the 8x8 block size (vardct::idct1d_8+vardct::idct2d_8x8) is also wired with unit tests. End- to-end VarDCT pixel decode (LF subband, HF subband, dequant, inverse transform dispatch across block sizes 8x8 / 8x16 / 16x8 / 16x16 / 32x32 / 64x64 / DCT4 / IDENTITY / AFV, Chroma-from-Luma, Gaborish smoothing, EPF) is round-9+ work.
§Round-9 (2024-spec) additions
Three concurrent fixes that together unblock the synth_320 fixture (multi-group lossless grey, 320×320, num_groups=9):
-
§F.3.1 HfGlobal slot is unconditional — the 2024 spec bullets list
HfGlobalfor every TOC, with NOTE 1 calling out that the slot is 0-byte forencoding == kModular. Round 8’snum_toc_entries/toc::Toc::readgated HfGlobal onencoding == kVarDCT, off-by-oning every PassGroup index in multi-group kModular frames. Also:HfPass[num_passes]is part of theHfGlobalsection per Annex G.3 Table G.4 — round 8 had incorrectly counted it as separate TOC entries. With both off- by-ones fixed, synth_320’s TOC reads as 12 entries[33, 0, 0, 9, 20, 7, 20, 9, 24, 7, 23, 7](slot 2 is the 0- byte HfGlobal, not PG[0][0]). -
§F.3 first-paragraph zero-padding — “When decoding a section, no more bits are read from the codestream than 8 times the byte size indicated in the TOC; if fewer bits are read, then the remaining bits of the section all have the value zero.” Round 8’s
bitreader::BitReadererrored on EOF for section sub-readers, breaking PassGroup ANS decodes whose modular sub-bitstreams consumed fewer real bits than the TOC-stated section size. Round 9 addsbitreader::BitReader::new_sectionwhich returns 0 for any read past the end of the section data; the legacybitreader::BitReader::newpreserves strict EOF for whole- codestream parsing. -
Per-PassGroup transforms (Annex H.6 inside G.4.2) — observed in cjxl 0.11.1’s synth_320 edge groups: the encoder emits a per-group Palette transform (
begin_c=0, num_c=1, nb_colours=191) for the 64-pixel-wide column-2 / row-2 groups.pass_group::decode_modular_group_intonow applies the transform layout adjustment to the per-group channel descs, decodes against the adjusted descs, and applies the inverse transforms LOCALLY before copying samples back into the parent image.global_modular::apply_transforms_to_channel_layoutis nowpubso the per-group reuse path doesn’t duplicate the table.
Round-9 status — synth_320 reaches end-of-frame without
erroring and ~21k of 102400 pixels match the expected
(y + x) & 0xFF gradient (the first 6 rows across the first two
group columns); the remaining pixels drift mid-decode in the
smaller edge groups. Full pixel-correctness is round-10 work
(suspected residual: ANS state nuance specific to F.3 zero-
padded tail OR per-group WP bookkeeping). All five small
lossless fixtures still pixel-correct vs round 4’s
expected.png.
§Round-10 (2024-spec) additions
Two themes:
-
C.1 + C.3.3
lz_dist_ctxspec-conformance fix — [modular_fdis::decode_uint_in] anddecode_uint_in_with_distpreviously passed the per-symbol leaf context for both the literal token AND the LZ77 distance token, which contradicts the spec’s “the LZ77 distance token is read usingD[clusters[lz_dist_ctx]]” withlz_dist_ctx = num_dist(the dedicated extra context the codestream reserves wheneverlz77.enabled). When LZ77 fires, that bug would distort every copy. Fixed: derivelz_dist_ctx = cluster_map.len() - 1from the post-prelude state of theEntropyStreamand thread it toHybridUintState::decode’sctx_lzargument. No-op for fixtures whose symbol stream haslz77.enabled = false(synth_320 included). -
synth_320 edge-group drift bisect — instrumented per- decode tracing pinpoints the first mismatch at PG[0][0] decode #3087 (frame coords y=24, x=14). State 0x9CA780 alias-maps to symbol 30 (cluster 0’s low-prob
D[30] = 1entry), forcing an ANS refill plus extra bits that over-consume 21 bits beyond the 9-byte slot. Bisect ruled out: per-PassGroup transform layout (PG[0][0] carries no transforms; only edge groups do); LZ77 path (off in the symbol stream); per-channel WP state reset (PG[0][0] is the first group); cluster_map /dist_multiplierderivation (matches H.3). Round-11+ work will need a finer state-by- state diff against djxl--debug(deferred to an Auditor round) since the implementer wall bars djxl source / the reference-decoder-trace doc.
Round-10 status — synth_320 still decodes ~21k of 102400 pixels matching the gradient (first 24 rows of PG[0][0] and PG[0][1] are pixel-correct; drift begins at y=24, x=14). All five small lossless fixtures still pixel-correct.
§Round-11 (2024-spec) additions
Three pieces wire LF subband decode (Annex G.2.2 / I.2):
-
LfGlobal VarDCT bundles (
lf_global):lf_global::Quantizer(FDIS C.4.3 —global_scale+quant_lf) drives LF dequant per Listing C.1.lf_global::LfChannelCorrelation(C.4.4) carries the CfL factors used by Annex G to reconstruct X/B from dY (defaultcolour_factor=84,base_correlation_x=0.0,base_correlation_b=1.0).lf_global::HfBlockContext(C.8.4) implements only theu(1)==1default-table fast path in round 11; the per-LF-threshold / qf-threshold / clustering- map branch returnsError::Unsupported. With these bundles wired,LfGlobal::readadvances correctly past the VarDCT-only region of the LfGlobal slot rather than rejecting outright. -
GlobalModular zero-channel acceptance (
global_modular):GlobalModular::readpreviously rejected any frame wherederive_channel_descsreturned 0 channels (the common VarDCT-without-extras case). Round 11 accepts the empty case: the inner ModularHeader (use_global_tree,WPHeader,nb_transforms) is still consumed, but the MA-tree and per- cluster distribution decode are skipped per FDIS C.9.1 last sentence (“In the trivial case where N is zero, the decoder takes no action.”). -
LfGroup + LfCoefficients (
lf_group):lf_group::LfCoefficients::readreadsextra_precision = u(2)per FDIS C.5.3, builds the per-LfGroup channel layout (3 LF channels ofceil(group_w/8) × ceil(group_h/8)samples, optionally further right-shifted byframe_header.jpeg_upsamplingon chroma planes), then drives a Modular sub-bitstream withstream_index = 1 + lf_group_indexper Table H.4.lf_group::LfGroup::readcomposes ModularLfGroup (G.2.3 — round-11 only handles the empty-channel-list case for now) with LfCoefficients. HfMetadata (G.2.4) is round-12+ work.
Acceptance fixture: hand-built minimal VarDCT bitstream — no cjxl
dependency, encoded directly from spec listings — covering an
8×8 frame with 1×1 LF coefficient channels, MA tree of one
Zero-predictor leaf, and prefix-code symbol stream with
alphabet_size=1 (so every decoded LF coefficient is 0). The
fixture parses through LfGlobal::read → LfGroup::read →
LfCoefficients::read end-to-end. Test:
lf_group::tests::round11_lfgroup_minimal_vardct_one_block_parses.
All five small lossless fixtures stay pixel-correct (see
tests/round11_lf_subband.rs).
§Round-13 (2024-spec) additions
Three pieces tighten the VarDCT pipeline so round-12’s unit-tested F.1 / F.2 work actually runs on real codestreams:
-
DctSelect / HfMul derivation from BlockInfo (
dct_select): walks each column of the per-LfGroup BlockInfo channel decoded in round 12, looks up the transform type in Table C.16, and places the varblock at the next-empty 8×8 cell of the LfGroup’s block grid (raster order). HfMul is computed as1 + mul. The 27-entry transform-type table is committed verbatim with per-entry(block_cols, block_rows)from the FDIS spec. -
HfGlobal C.6 default-fast-path (
hf_global): reads theu(1)dequant-default flag and thenum_hf_presets - 1 = u(ceil(log2(num_groups)))field. The non-default-encoding branch (per-matrixencoding_mode = u(3)+ Listing C.7ReadDctParams()) returnsError::Unsupporteduntil round 14+ wires the full table. -
VarDCT pipeline wiring ([
decode_vardct_round13]): the top-leveldecode_one_frameno longer rejects VarDCT codestreams at the round-8 scaffold gate. Instead, fornum_lf_groups == 1 && num_passes == 1, it now drives: LfGlobal → LfGroup (LfCoefficients + HfMetadata) → DctSelect derivation → HfGlobal → F.1 LF dequantisation → F.2 adaptive smoothing (when not skipped). The round-13 pipeline returnsError::Unsupportedwith a “round 14+: HF subband decode + IDCT not yet wired” message AFTER all round-12 work has run on the real input.
Round-13 status — five small lossless Modular fixtures stay
pixel-correct; both VarDCT fixtures (vardct_256x256_d1.jxl and
vardct_256x256_d3.jxl, copied from docs/image/jpegxl/fixtures/)
reach the round-13 pipeline (no longer hit the round-8 scaffold
gate).
Round-14 candidates (in dependency order):
- HfBlockContext non-default-table branch (per-LF thresholds + qf
thresholds + clustering map), required for any cjxl-encoded VarDCT
fixture that doesn’t take the
u(1)=1default-table fast path. - HfGlobal C.6.2 dequant-matrix encoding modes (Listing C.7) +
Listing C.10
GetDCTQuantWeightsfor per-DctSelect dequant matrices. - HfPass C.7.1 coefficient orders (
used_orders13-bit mask,DecodePermutation) + C.7.2 histograms (495 × num_hf_presets × nb_block_ctx clustered distributions). - PassGroup HF coefficients C.8.3: per-block
hfp = u(ceil(log2(num_hf_presets)))+ clustered ANS coeff decode + F.3 HF dequantisation (Listing F.2 + per-channel scale + per-DctSelect dequant matrix multiply). - Inverse DCT dispatch across block sizes (8×8 IDCT wired round 8; 8×16 / 16×8 / 16×16 / 32×32 / 64×64 / DCT4 / DCT4×8 / DCT8×4 / IDENTITY / AFV remain).
- Listing I.5 LLF-from-downsampled-LF composition (the bridge from
F.2-smoothed LF samples to varblock LF coefficients) — pure-math
step landed round 121 as
llf_from_lf(FDIS Listings I.15 + I.16). Still pending: per-LfGroup wiring that drives the per-varblock invocation from thepass_group_hfcoefficient buffer. - Chroma-from-Luma (Annex G), Gaborish (Annex J?), EPF.
§Round-16 (2024-spec) additions
lf_group::HfMetadata::read now wires nested transforms (FDIS
§C.5.4 + §C.9.4): the four-channel HfMetadata sub-bitstream parses
nb_transforms + TransformInfo[] exactly like the GlobalModular
section, applies the transform-rewritten channel layout via
global_modular::apply_transforms_to_channel_layout before the
inner per-channel decode, then walks
global_modular::apply_inverse_transforms in reverse bitstream
order to recover the four-channel base layout
[XFromY, BFromY, BlockInfo, Sharpness].
Round-15 left the d1 fixture stuck on the round-12 deferral inside
HfMetadata::read (nb_transforms > 0 errored with “transforms
inside HF metadata sub-bitstream not yet supported”). With round 16
the parse succeeds; the d1 fixture surfaces a strictly-later
blocker — its HfMetadata Squeeze step references channels beyond
the four-channel baseline (begin_c=39 on step 0), tripping the
apply_transforms_to_channel_layout channel-count invariant.
That’s the round-17 candidate (suspected upstream bit-position
drift in LfGlobal or LfCoefficients).
HfMetadata::read and LfGroup::read now both take a
&ImageMetadataFdis argument so the inverse Palette transform can
read bit_depth.bits_per_sample for delta-palette prediction.
§Round-26 (2024-spec) — Annex L colour transforms
Parent-dispatch “r11”. New xyb module transcribes FDIS §L.2.2
inverse XYB → linear RGB and §L.3 inverse YCbCr → RGB verbatim
from the ISO/IEC 18181-1:2024 PDF. Three public entry points:
xyb::inverse_xyb_to_rgb, xyb::inverse_ycbcr_to_rgb, and
the convenience composite xyb::modular_xyb_to_linear_rgb
(§L.2.2 preamble + inverse XYB in one call).
Wired into [decode_codestream] modular output stage: when
metadata.xyb_encoded == true and colour_encoding.colour_space
is Rgb, the per-channel pass-through is replaced with
[build_rgb_planes_from_xyb]; symmetric branch for
frame_header.do_ycbcr == true. Pre-round-26 pass-through path
preserved for xyb_encoded == false && do_ycbcr == false modular
frames so the five small lossless fixtures stay pixel-correct.
Round-26 SPECGAP: §L.2.2 NOTE describes the output as
linear-domain RGB but doesn’t prescribe a gamma encoding step
before display. xyb::linear_rgb_to_u8 emits linear bytes
(clamp + scale by 255 + round); callers that need sRGB-encoded
bytes apply the sRGB transfer function downstream.
§Round-27 (2024-spec) — IDCT dispatch
Parent-dispatch “r12” item (5). New idct module wires the
spec-conformant 1-D inverse DCT for power-of-two sizes
s ∈ {1, 2, 4, 8, 16, 32, 64, 128, 256} (FDIS Annex I.2.1) and
the 2-D inverse DCT (Annex I.2.2 Listing I.4) for rectangular
R × C blocks. Three public entry points: idct::idct_1d,
idct::idct_2d (taking coefficients in spec (short × long)
row-major natural-ordering layout per Annex I.2.4 and returning
(R × C) row-major samples), and idct::idct_for_transform
which dispatches on a dct_select::TransformType to the 2-D
IDCT for the 18 plain-DCT block sizes in Table C.16.
The 9 non-DCT transforms (Hornuss, DCT2x2, DCT4x4, DCT4x8,
DCT8x4, AFV0..AFV3) — Listings I.7..I.13 — return
Err(Unsupported) from idct::idct_for_transform and are
deferred to round 28+ alongside HF coefficient decode + F.3
dequantisation. The legacy vardct::idct1d_8 /
vardct::idct2d_8x8 (round-8 scaffold, scaled-orthonormal
IDCT) are retained for backward compatibility but are NOT
spec-conformant; new HF-decode wiring will call through
idct::idct_for_transform exclusively.
Re-exports§
pub use container::detect;pub use container::extract_codestream;pub use container::Signature;pub use metadata::parse_headers;pub use metadata::BitDepth;pub use metadata::Headers;pub use metadata::ImageMetadata;pub use metadata::SizeHeader;
Modules§
- abrac
- Adaptive binary range coder (ABRAC), per ISO/IEC 18181-1 committee draft (2019-08-05) Annex D.7. ABRAC is the binary building block from which the MABEGABRAC context model used by the Modular sub-bitstream is constructed.
- afv
- AFV (Asymmetric “FREE”) variable-block helpers — ISO/IEC FDIS 18181-1:2021 Annex I.2.2 Listings I.5 and I.6.
- ans
- ANS entropy coder + companion lookup tables for the FDIS-2021 revision of JPEG XL (ISO/IEC FDIS 18181-1:2021, Annex D).
- begabrac
- Bounded-Exp-Golomb ABRAC (BEGABRAC), per ISO/IEC 18181-1 committee draft (2019-08-05) Annex D.7.1.
- bitreader
- LSB-first bit reader used by the JPEG XL codestream.
- block_
context_ resolver - Per-LfGroup
BlockContext()resolver — ISO/IEC FDIS 18181-1:2021 §C.8.3 + §I.2.2 (was Listing C.13 + Listing C.15). - block_
dequant - Per-block VarDCT decode walk — chains the §C.8.3 decoded quantised-coefficient block through Annex F.3 HF dequantisation and the Annex I.2 inverse DCT to produce a block of spatial residual samples.
- chroma_
from_ luma - Chroma-from-Luma (CfL) — ISO/IEC FDIS 18181-1:2021 Annex G (“Chroma from luma”, page 73) and ISO/IEC 18181-1:2024 §I.2.6.
- coeff_
order - Natural ordering of the DCT coefficients — ISO/IEC FDIS 18181-1:2021 §I.2.4 + Table I.1.
- container
- JPEG XL container detection.
- dct_
quant_ weights GetDCTQuantWeights+ per-DctSelectdequantization-matrix materialisation — ISO/IEC 18181-1:2024 §I.2.4 / §I.2.5 + Table I.4- dct_
select DctSelect/HfMulderivation fromBlockInfo— ISO/IEC 18181-1:2024 Annex C.5.4 prose + Table C.16.- epf
- Edge-preserving restoration filter — ISO/IEC FDIS 18181-1:2021 Annex J.3 (“Edge-preserving filter”, pages 85–87).
- extensions
Extensionsbundle — FDIS 18181-1 §A.5 (Table A.14).- frame_
header FrameHeaderbundle — FDIS 18181-1 §C.2 (Table C.2).- gaborish
- Gabor-like restoration filter — ISO/IEC FDIS 18181-1:2021 Annex J.2 (“Gabor-like transform”, page 85).
- global_
modular GlobalModularbundle — FDIS 18181-1 §C.4.8.- hf_
coeff_ histogram_ size HfCoefficientHistogramSize— typed sizing primitive for the §C.7.2 HF coefficient histogram block.- hf_
coefficient_ histograms HfCoefficientHistograms— ISO/IEC FDIS 18181-1:2021 §C.7.2 HF coefficient histograms read.- hf_
dequant - HF coefficient dequantisation — ISO/IEC FDIS 18181-1:2021 Annex F.3 (page 72 of the FDIS PDF) and ISO/IEC 18181-1:2024 Annex F.3.
- hf_
global HfGlobalbundle — ISO/IEC 18181-1:2024 Annex I.2.4 + I.2.6.- hf_pass
HfPassbundle — ISO/IEC FDIS 18181-1:2021 §C.7.- icc
- ICC profile decoder — ISO/IEC 18181-1:2024 Annex E.4.
- idct
- Inverse DCT dispatch — ISO/IEC 18181-1:2024 Annex I.7 + I.9.
- lf_
dequant - LF dequantization + adaptive LF smoothing — ISO/IEC 18181-1:2024 Annex F.1 (Listing F.1) and Annex F.2 (the prose immediately following Listing F.1).
- lf_
global LfGlobalbundle — FDIS 18181-1 §C.4 (Table C.10).- lf_
group LfGroupbundle — ISO/IEC 18181-1:2024 Annex G.2 (= 2021 FDIS C.5).- llf_
from_ lf - LLF coefficients from downsampled image — ISO/IEC FDIS 18181-1:2021 Annex I.2.5 (Listings I.15 + I.16) and ISO/IEC 18181-1:2024 Annex I.2.5.
- matree
- Meta-Adaptive Bounded-Exp-Golomb ABRAC (MABEGABRAC) decision tree, per ISO/IEC 18181-1 committee draft (2019-08-05) Annex D.7.2 and D.7.3.
- metadata
- JPEG XL codestream header parsing.
- metadata_
fdis ImageMetadata(full FDIS A.6 form),ColourEncoding(A.4),ToneMapping(A.6 Table A.18),ExtraChannelInfo(A.9),AnimationHeader(A.7),OpsinInverseMatrix(A.8), and theSizeHeaderre-decoded against the FDIS published in 2021.- modular
- Modular sub-bitstream channel decoding (per ISO/IEC 18181-1 committee draft, 2019-08-05, Annex C.9).
- modular_
fdis - Modular image sub-bitstream — ISO/IEC 18181-1:2024 Annex H.
- multi_
pass_ decode - Per-LfGroup multi-pass varblock decode driver —
ISO/IEC FDIS 18181-1:2021 §C.8.3 + Table C.6
Passes. - multi_
pass_ hf_ header - Per-LfGroup multi-pass driver with per-pass HF-header
hfpreads — ISO/IEC FDIS 18181-1:2021 §C.8.3 first paragraph. - multi_
pass_ hf_ histogram_ decoder - Per-pass HF histogram decode context — ISO/IEC FDIS 18181-1:2021
§C.7.2 (entropy histograms) + §C.8.3 (per-pass
histogram_offsetrouting) bridge. - non_
zeros_ grid - Per-pass / per-channel
NonZeros(x, y)grid bookkeeping — ISO/IEC FDIS 18181-1:2021 §C.8.3 + Listing C.13 + Listing C.14. - pass_
group PassGroupbundle — ISO/IEC 18181-1:2024 Annex G.4.- pass_
group_ hf PassGroupHF coefficients — ISO/IEC FDIS 18181-1:2021 §C.8.3 + §C.8.4 supporting machinery.- per_
channel_ non_ zeros - Per-channel
NonZeros(x, y)grid container — ISO/IEC FDIS 18181-1:2021 §C.8.3 + Listing C.13 prelude. - per_
pass_ non_ zeros - Per-pass
NonZeros(x, y)grid container — ISO/IEC FDIS 18181-1:2021 §C.8.3 + Listing C.13. - predictors
- Modular sub-bitstream pixel predictors, per ISO/IEC 18181-1 committee draft (2019-08-05) Annex C.9.3.1.
- residual_
plane - Per-LfGroup VarDCT residual-plane assembly — places each varblock’s
R × Cspatial residual block (the output of the Annex F.3 dequant + Annex I.2.3 inverse-DCT stage) into a single-channel spatial plane at the varblock’s pixel origin. - toc
TOC(Table of Contents) — FDIS 18181-1 §C.3.- varblock_
walk - Per-LfGroup varblock-walk driver — ISO/IEC FDIS 18181-1:2021 §C.5.4 (DctSelect placement prose) + §C.8.3 (per-pass per-channel varblock decode loop).
- vardct
- VarDCT decode path — ISO/IEC 18181-1:2024 Annex I.
- xyb
- Annex L colour transforms — ISO/IEC 18181-1:2024.
Structs§
- Headers
Fdis - FDIS-side
Headersreturned byprobe_fdis. Mirrors the committee-draftHeadersbut uses the FDIS bundle types.
Constants§
- CODEC_
ID_ STR - Public codec id string. Matches the aggregator feature name
jpegxl.
Functions§
- decode_
one_ frame - Decode the entire JXL packet (raw codestream OR ISOBMFF-wrapped) and
return the first frame as a
VideoFrame. Round-3 envelope. - make_
encoder - Encoder slot, always rejected. Exposed for completeness so callers
that wire an
Encoderfactory by codec id get a cleanUnsupportederror instead ofCodecNotFound. - probe
- Inspect a JXL file (raw codestream or ISOBMFF-wrapped) and return the
signature type + parsed
SizeHeader+ImageMetadatapreamble. - probe_
fdis - FDIS-side probe: parse SizeHeader + full A.6 ImageMetadata. Falls back to the committee-draft probe if the FDIS path errors (so that container detection still works on edge cases the committee-draft path tolerates).
- register
- Unified entry point: install the JPEG XL codec into a
RuntimeContext. - register_
codecs - Register the JPEG XL decoder stub into the supplied
CodecRegistry. The encoder slot is intentionally left unregistered: the crate is decoder-side only and currently retired-pending-cleanroom (see crate-level docs).