feat(gamut-cmm): LUT pipelines and per-intent tag selection - #370
Open
justin13888 wants to merge 3 commits into
Open
feat(gamut-cmm): LUT pipelines and per-intent tag selection#370justin13888 wants to merge 3 commits into
justin13888 wants to merge 3 commits into
Conversation
Assembles runnable pipelines from all four LUT tag types, each in the tag's native encoded [0,1] domain with the PCS seam decoded at the end: lut8/lut16 as matrix (3-channel non-identity only - lcms2's rule, not XYZ-gated as the spec's letter suggests; documented divergence) into input tables, CLUT, and output tables; mAB/mBA in their s10.12/s10.13 element orders with optional stages omitted leniently. The classic trap is pinned as policy: lut16 decodes PCSLAB with the v2 encoding even inside a v4 profile - keyed on the tag's true type, never the header version - while lut8 and mAB/mBA use v4. Lab-indexed PCS-to-device CLUTs select multilinear interpolation, matching lcms2's trilinear switch. Intent selection uses lcms2's verbatim tables (absolute maps to the relative tag; a missing intent tag falls back to perceptual, then the matrix shaper, then a typed error). The Lab-PCS RGB shaper refusal lifts via the new XyzToLab/LabToXyz stages, whose eval arms land in this same diff per the wildcard-free growth rule. Part of #328.
…-CMS Stage-order unit pins per tag type and direction, the dedicated lut16-v2-Lab-in-a-v4-profile regression the issue demands (with lut8 pinned to v4 scaling alongside), per-intent distinctness on the CMYK prtr corpus with absolute bit-equal to relative, the perceptual fallback proven equal to lcms2 on identically modified re-serialized bytes, and the trilinear rule proven load-bearing (tetrahedral mode diverges 10x from the lcms2 agreement). Differentials neutralize lcms2's v4 forced-BPC perceptual behaviour via a v2 Lab endpoint and a version-downgraded twin profile - which doubles as proof both sides key the v2 encoding on tag type, not header version; measured bounds documented at each assert. Part of #328.
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 7/9 of the gamut-cmm stack (epic #323), stacked on #369. Turns LUT-based profiles —
lut8,lut16,lutAToB,lutBToA— into runnable pipelines, with per-rendering-intent tag selection:lut16Typedecodes PCSLAB with the v2 encoding even inside a v4 profile — keyed on the tag's true type, never the header version (proven by a version-downgraded twin profile) — while lut8 and mAB/mBA use v4.A2B0/1/2/1,B2A0/1/2/1— absolute maps to the relative tag, pinned bit-equal); missing tag → perceptual tag → matrix shaper → typed error, each transition tested (the fallback is proven equal to lcms2 on identically modified re-serialized bytes).XyzToLab/LabToXyzstages.Validation
mise run mutants-crate gamut-cmm: 634 mutants — 602 caught, 32 unviable, 0 missed, no new exclusions. Coverage 99.13% lines; clippy-D warnings, fmt-check, cargo doc clean.Stack
#321 (#351) → #322 (#358) → #324 (#362) → #325 (#364) → #326 (#368) → #327 (#369) → #328 (this) → #329 → #330.
Closes #328. Part of #323.