Skip to content

Commit 5517ddc

Browse files
Sync iccviz engine: GamutVolume, RoundTripDE, neutral-axis inking (InternationalColorConsortium#1711)
Bring the data-first visualization engine under Tools/CmdLine/IccProfilePlot/ (IccVizModel, landed in InternationalColorConsortium#1517) up to date with three feature-additive changes, plus the caller updates they require. No refactor of the enumerate/render surface; no change to IccProfLib or to the Mini{PDF,SVG,TIFF} writers. Engine (IccVizModel.hpp/.cpp, IccVizMath.hpp): - GamutVolume(): gamut volume in dE*ab^3 via boundary voxelisation + flood-fill through the AToB transform; scalar GamutVolumeResult with a `degenerate` flag so a collapsed sampling is distinguishable from a genuinely tiny gamut. - RoundTripDE(): B2A->A2B round-trip accuracy (mean/p90/max/std dE*ab) seeded from in-gamut device-cube samples; scalar RoundTripResult. - Kind::NeutralAxisInking: device colorant along the neutral axis from a PCS->device (BToA) table, enumerated per BToA tag. InkReversalL retired (enum value reserved). Plus GamutVolume accuracy work (IccProfLib CIELAB reuse) and CLUT-raster / new-metric hardening against malformed input. Breaking API (internal only): Enumerate(pIcc, Order) loses its Order argument. Enumerate(pIcc) now returns one canonical order (chromaticity, then per-tag A2B0/1/2, B2A0/1/2, gamut, then named/colorant). Only in-tree caller updated. iccProfileVisualize.cpp: - Drop the Order argument at the Enumerate call site. - Render Kind::NeutralAxisInking into the PDF report (was engine-enumerated but silently skipped): CreateNeutralAxesXobject (L*/%-ink axes frame) + renderNeutralAxisGraph (one polyline per colorant along L* 100->0, distinct CMYK stroke, channel-name legend) + the processLuts switch case. One page per PCS->device table. The engine sources are algorithmically identical to the upstream copy; the only deltas are the restored ICC license header on IccVizModel.cpp and an ASCII punctuation sweep (matching the InternationalColorConsortium#1517 strict-build convention), which changes five graph-title string literals from an em-dash to a hyphen. All translation units build clean under -Wall -Wextra. The old "byte-identical vs original iccProfileVisualize" PDF baseline is intentionally superseded by the canonical page order and the chromaticity page for device/CMYK profiles; a pinned-output regression + CTests for the two new scalar metrics follow as a separate in-repo PR per the maintainer-owned CTest policy. Refs InternationalColorConsortium#1711. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 3c65614 commit 5517ddc

4 files changed

Lines changed: 1044 additions & 174 deletions

File tree

Tools/CmdLine/IccProfilePlot/IccVizMath.hpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@
6262
*/
6363

6464
/**
65-
* IccVizMath - small shared colour-math helpers for the visualization model.
65+
* IccVizMath - small shared colour-math helpers for the visualization model.
6666
*
6767
* The pure scalar conversions the visualizations need: XYZ->xy chromaticity
6868
* projection and the Kang et al. planckian-locus approximation.
6969
*
70-
* They live in one header so the math - especially approxPlanck()'s polynomial
71-
* constants - has a single source. The functions are header-only (inline) and
70+
* They live in one header so the math - especially approxPlanck()'s polynomial
71+
* constants - has a single source. The functions are header-only (inline) and
7272
* depend only on the ICC scalar types, so the header carries no link dependency.
7373
*/
7474

@@ -85,7 +85,9 @@ struct XY {
8585
float y = 0.0f;
8686
};
8787

88-
// 16-bit ICC XYZ (s15Fixed16 stored as integer/65535) -> CIE xy chromaticity.
88+
// xyFromICCXYZ - project a 16-bit ICC XYZ (s15Fixed16 stored as integer/65535) to
89+
// CIE xy chromaticity. Separate from the float version because the integer source
90+
// can't be NaN/Inf, so it skips those checks; a near-zero sum returns (0,0).
8991
inline XY xyFromICCXYZ(const icXYZNumber* xyz) {
9092
// integers, so don't have to test for NaN or Inf
9193
float X = xyz->X / 65535.0f;
@@ -96,7 +98,9 @@ inline XY xyFromICCXYZ(const icXYZNumber* xyz) {
9698
return XY{X / sum, Y / sum};
9799
}
98100

99-
// Float XYZ -> CIE xy chromaticity.
101+
// xyFromXYZFloat - project a floating-point XYZ triple to CIE xy chromaticity; the
102+
// float twin of xyFromICCXYZ for values that come from a transform rather than a
103+
// stored tag. A near-zero (or non-positive) sum returns (0,0) to avoid dividing by ~0.
100104
inline XY xyFromXYZFloat(const icFloatNumber* xyz) {
101105
float X = xyz[0];
102106
float Y = xyz[1];
@@ -106,7 +110,10 @@ inline XY xyFromXYZFloat(const icFloatNumber* xyz) {
106110
return XY{X / sum, Y / sum};
107111
}
108112

109-
// Planckian (blackbody) locus approximation in CIE xy.
113+
// approxPlanck - approximate the planckian (blackbody) locus in CIE xy for a colour
114+
// temperature `t` (Kelvin), used to draw the reference curve on the chromaticity
115+
// chart. Uses the Kang et al. piecewise polynomial fit rather than integrating the
116+
// Planck radiator, which is fast, table-free and accurate enough for a plotted guide.
110117
// https://en.wikipedia.org/wiki/Planckian_locus
111118
// Bongsoon Kang; Ohak Moon; Changhee Hong; Honam Lee; Bonghwan Cho;
112119
// Youngsun Kim (December 2002). "Design of Advanced Color Temperature Control

0 commit comments

Comments
 (0)