Skip to content

feat(jxl)!: migrate JXL to gamut-jxl; drop jxl-oxide, zune-jpegxl, and the libjxl glue - #48

Merged
justin13888 merged 2 commits into
masterfrom
25-migrate-jxl-gamut
Jul 19, 2026
Merged

feat(jxl)!: migrate JXL to gamut-jxl; drop jxl-oxide, zune-jpegxl, and the libjxl glue#48
justin13888 merged 2 commits into
masterfrom
25-migrate-jxl-gamut

Conversation

@justin13888

Copy link
Copy Markdown
Collaborator

Closes #25.

Stacked on #47; merge order #42#44#45#46#47 → this.

What is Delivered

  • Decode on gamut-jxl (pure Rust) replacing jxl-oxide — same output contract (Rgb16, grayscale expansion, alpha drop, full-range scaling). probe_jxl moves to gamut's header-only info and now reports bit depth where it previously returned None. Behaviour deltas: animated / premultiplied-alpha streams are rejected (jxl-oxide rendered frame 0).
  • decode_jxl_partial dropped from the public API per the issue (gamut#256 still open upstream).
  • Encode collapses both old backends (zune-jpegxl + in-repo libjxl bindgen glue) onto gamut-jxl's encode feature. gamut-jxl-sys vendors libjxl hermetically — no system/vendored split survives, one jxl-encode feature. One JxlEncodeConfig (lossless default / distance / effort / use_container / coded_bit_depth) replaces the two old config types; EncodeOptions::JxlZune/JxlLibjxl collapse to Jxl. Quality upgrade: the 16-bit default now encodes true 16-bit lossless where the zune default silently down-packed to 8-bit.
  • Metadata through the encoder: EXIF forces the container form; ICC rides the codestream colour metadata (spec-correct) instead of an iccp sidecar; the now-dead rawshift JXL box muxers are deleted.
  • Deleted: codecs/jxl_libjxl.rs (439 lines), the build.rs libjxl bindgen/pkg-config slice, deps jxl-oxide/zune-jpegxl/jpegxl-src (direct — it remains in the lockfile solely as gamut-jxl-sys's own pinned build-dep), four backend features, EncodeError::Jxl.

Verification Done

Run independently after implementation (cmake + g++ present, vendored libjxl built — encode fully exercised, no caveats):

  • cargo test --workspace378/0 (JXL default-feature tests now live behind the collapsed features; composition verified)
  • cargo test -p rawshift-image --features full533/0, including new tests: 16-bit lossless exact round-trip through gamut decode, embedded-ICC verification via JxlDecoder::embedded_icc_profile, EXIF-forces-container, invalid effort/distance rejection
  • --features serde360/0; clippy workspace + full -D warnings0 + 0
  • Standalone builds: jxl-decode, jxl-encode, jxl — all clean
  • End-to-end: encode_in_memory example emits a 64×64 16-bit lossless JXL (408 B) and probes it back
  • Greps: jxl-oxide/zune-jpegxl absent from manifests and lockfile; decode_jxl_partial gone; build.rs jxl slice gone

…d the libjxl glue

JXL decode moves from jxl-oxide to gamut-jxl's pure-Rust decoder
(ImageBuf<Rgb16>; grayscale expansion, alpha dropping, and full-range 16-bit
scaling match the old output contract). probe_jxl now uses gamut-jxl's
header-only info and gains a bit_depth report it previously lacked.
Behaviour deltas: animated and premultiplied-alpha streams are rejected
where jxl-oxide rendered frame 0.

decode_jxl_partial is removed from the public API until truncated-stream
decode lands upstream (visualcommons/gamut#256).

JXL encode collapses both old backends (zune-jpegxl and the in-repo libjxl
bindgen glue) onto gamut-jxl's encode feature; gamut-jxl-sys owns the libjxl
linking and always vendors hermetically, so rawshift's vendored/system
feature split disappears. One JxlEncodeConfig replaces
ZuneJxlEncodeConfig/LibjxlEncodeConfig, exposing exactly gamut's options:
lossless (default), distance, effort, use_container, coded_bit_depth.
EncodeOptions::JxlZune/JxlLibjxl collapse to Jxl; codec id jxl/gamut. The
16-bit default now encodes true 16-bit lossless where the old zune default
down-packed to 8-bit. Metadata embeds through the encoder (EXIF forces the
container form; ICC rides the codestream colour metadata, spec-correct,
instead of an iccp sidecar box).

Deleted: codecs/jxl_libjxl.rs, the build.rs libjxl bindgen/pkg-config slice,
deps jxl-oxide/zune-jpegxl/jpegxl-src (direct), features
jxl-decode-jxl-oxide/jxl-encode-zune/jxl-encode-libjxl(-vendored), the
EncodeError::Jxl variant, and the now-dead JXL container muxers in
metadata/ (gamut-jxl owns box writing). jpegxl-src remains in the lockfile
only as gamut-jxl-sys's own pinned build-dependency.

BREAKING CHANGE: decode_jxl_partial removed; JXL config/option/variant names
changed; default JXL encode output is now 16-bit lossless.
… all-features run

The JXL migration removed the libjxl vendored/system feature split (gamut-jxl-sys
always vendors hermetically), but the all-features CI invocation still passed the
deleted feature, which Cargo rejects as unknown. Comment updated to describe the
gamut-jxl-sys build path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate JXL to gamut-jxl

1 participant