feat(lcms2-oracle): transform, ΔE, and black-point bindings plus synthesizer corpus - #358
Open
justin13888 wants to merge 3 commits into
Open
feat(lcms2-oracle): transform, ΔE, and black-point bindings plus synthesizer corpus#358justin13888 wants to merge 3 commits into
justin13888 wants to merge 3 commits into
Conversation
Extends the dev-only Little-CMS oracle beyond profile synthesis and inspection so colour transforms can be differentially validated: - RAII Transform over cmsHTRANSFORM (pair, multiprofile, proofing) with f64/u16/u8 apply paths; TYPE_* pixel-format codes rebuilt as documented const fns (bindgen cannot expand the *_SH macro forms) and cmsFLAGS_* transcribed with lcms2.h line citations, both pinned by tests; INTENT_* re-exported from the generated bindings. - Public ToneCurve (gamma/parametric/tabulated, eval, reverse) and cmsXYZ2Lab/cmsLab2XYZ, dE76/CIEDE2000, and the v2/v4 Lab and XYZ encoders; black-point detection; quiet log handler; alarm codes. - New synthesizers for the CMM engine test corpus: scnr camera profiles (matrix-shaper + LUT), v4 and v2 CMYK prtr with distinct per-intent A2B/B2A tables, Display P3 with the true piecewise sRGB TRC (parametric type 4), v2 matrix-shaper with and without chad, and a v4 shaper with a real (non-D50) wtpt for absolute-intent tests; existing synthesizers move to synth.rs with re-exports. build.rs is byte-identical: the existing cms.* allowlists already generate every binding used here. Part of #322.
Differential suite over the new oracle bindings: CIEDE2000 agrees with cmsCIE2000DeltaE to 1e-12 across 632 seeded pairs including hue-wrap, one-chroma-zero, and achromatic edges (weighted variant included); XYZ<->Lab matches cmsXYZ2Lab/cmsLab2XYZ to 1e-12 under an explicit D50 white, with the ~3e-6 rounded-literal white divergence measured and bounded separately; the v2/v4 16-bit Lab and PCSXYZ encoders match lcms2 exactly over dense sweeps and every clamp boundary, skipping only inputs inside lcms2's documented fast-floor ambiguity window. Part of #322.
Every profile the new lcms2-oracle synthesizers emit (scnr matrix and LUT camera profiles, v4/v2 CMYK prtr, Display P3 with the piecewise sRGB TRC, v2 shapers with and without chad, the non-D50-wtpt shaper) parses without error and round-trips; the v2 prtr's A2B0 decodes as lut16 and the v4 prtr's as lutAToB, pinning the version-dependent tag serialization the CMM's per-intent selection relies on. Part of #322.
This was referenced Aug 15, 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.
Summary
PR 2/9 of the gamut-cmm stack (epic #323), stacked on #351. Extends
tooling/lcms2-oracleso colour transforms — not just profiles — can be differentially validated against Little-CMS:TransformovercmsHTRANSFORM(profile pair, multiprofile, proofing) with f64/u16/u8 apply paths; black-point detection; quiet log handler; alarm codes; publicToneCurve(gamma/parametric/tabulated, eval, reverse);cmsXYZ2Lab/cmsLab2XYZ, ΔE76/CIEDE2000, and the v2/v4 Lab + XYZ encoders.TYPE_*/cmsFLAGS_*constants rebuilt in Rust — bindgen cannot expand the function-like*_SH()macro forms, so a documentedconst fnreplicates the packing (pinned against the verified numeric values) and the flags are transcribed withlcms2.hline citations.build.rsis byte-identical (issue acceptance criterion).scnrcamera profiles (matrix-shaper + LUT), v4 and v2 CMYKprtrwith six distinct per-intent A2B/B2A tables, Display P3 with the true piecewise sRGB TRC (parametric type 4), v2 matrix-shaper with/withoutchad, and a v4 shaper with a real non-D50wtpt(absolute-intent test vehicle —cmsCreateRGBProfilealways writeswtpt = D50+chad, which would make those tests vacuous).gamut-colorΔE₀₀ agrees withcmsCIE2000DeltaEto ≤1e-12 over 632 seeded pairs (hue-wrap/achromatic edges included); XYZ↔Lab ≤1e-12 under explicit D50; encoders match lcms2 exactly over dense sweeps + every clamp boundary (lcms2's fast-floor ambiguity window documented and skipped).gamut-iccparses and round-trips every new synthesizer profile and pins the v2→lut16/ v4→lutAToBtag serialization.Validation
cargo test -p gamut-color -p gamut-icc --all-features+ oracle's own tests: all green (15 oracle, 6 new gamut-color, 2 new gamut-icc tests).-D warnings,mise run fmt-checkclean;git diff --stat tooling/lcms2-oracle/build.rsempty.Stack
#321 (#351) → #322 (this) → #324 → #325 → #326 → #327 → #328 → #329 → #330.
Closes #322. Part of #323.