feat(jxl)!: migrate JXL to gamut-jxl; drop jxl-oxide, zune-jpegxl, and the libjxl glue - #48
Merged
Merged
Conversation
…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.
This was referenced Jul 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #25.
Stacked on #47; merge order #42 → #44 → #45 → #46 → #47 → this.
What is Delivered
Rgb16, grayscale expansion, alpha drop, full-range scaling).probe_jxlmoves to gamut's header-onlyinfoand now reports bit depth where it previously returnedNone. Behaviour deltas: animated / premultiplied-alpha streams are rejected (jxl-oxide rendered frame 0).decode_jxl_partialdropped from the public API per the issue (gamut#256 still open upstream).encodefeature. gamut-jxl-sys vendors libjxl hermetically — no system/vendored split survives, onejxl-encodefeature. OneJxlEncodeConfig(lossless default / distance / effort / use_container / coded_bit_depth) replaces the two old config types;EncodeOptions::JxlZune/JxlLibjxlcollapse toJxl. Quality upgrade: the 16-bit default now encodes true 16-bit lossless where the zune default silently down-packed to 8-bit.iccpsidecar; the now-dead rawshift JXL box muxers are deleted.codecs/jxl_libjxl.rs(439 lines), the build.rs libjxl bindgen/pkg-config slice, depsjxl-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 --workspace— 378/0 (JXL default-feature tests now live behind the collapsed features; composition verified)cargo test -p rawshift-image --features full— 533/0, including new tests: 16-bit lossless exact round-trip through gamut decode, embedded-ICC verification viaJxlDecoder::embedded_icc_profile, EXIF-forces-container, invalid effort/distance rejection--features serde— 360/0; clippy workspace + full-D warnings— 0 + 0jxl-decode,jxl-encode,jxl— all cleanencode_in_memoryexample emits a 64×64 16-bit lossless JXL (408 B) and probes it backjxl-oxide/zune-jpegxlabsent from manifests and lockfile;decode_jxl_partialgone; build.rs jxl slice gone