The question
After #2292 (09bba400) a dual-PCS profile that carries no colorimetric tag in the
direction being used no longer resolves under the D2B/B2D opt-out: it refuses with
icCmmStatProfileMissingTag where master previously fell back to the spectral tag and
wrote a link.
Is refusing correct, or should the opt-out fall back to BToDx/DToBx when the profile
has no BToAx/AToBx to offer?
I have no strong view and did not decide it in #2292 — the fix there deliberately changed
only which tag is preferred, not what happens when the preferred one is absent. Whichever
way this is ruled I will PR it; I am not filing this to hand it off.
Why it changed
CIccXform::Create now gates the spectral branch on spectralPCS && !pcs
(IccProfLib/IccCmm.cpp:611 input, :759 output), matching the five space-selection
sites in CIccCmm::AddXform (:9093, :9112) and CIccNamedColorCmm::AddXform
(:11718, :11796, :11813). For a dual-PCS profile under the opt-out the spectral
branch is now skipped, the colorimetric block below it runs, and if that finds no tag
either the function falls through to the MatrixTRC / monochrome arms and then returns
NULL.
Before #2292 the opt-out was ignored, so the spectral tag was selected and the chain
resolved. That is the defect #1982 reported — but for a profile with only a spectral tag
in that direction, ignoring the opt-out was also the only thing keeping it working.
The affected shape, and how rare it is
Testing/Calc/CameraModel.xml: Input class, v5.00, RgbData, PCS = XYZData,
Spectral PCS = 0x0021ChannelReflectanceData, tags A2B3 and B2D3 — no B2A3. So
as a destination it can only go through B2D3.
Sweeping all 221 tracked *.xml for a non-empty <PCS> plus a <SpectralPCS> plus a
B2D tag gives exactly three profiles:
| profile |
A2B |
B2A |
D2B |
B2D |
Testing/SpecRef/SixChanCameraRef.xml |
3 |
3 |
3 |
3 |
Testing/hybrid/MultSpectralRGB.xml |
- |
- |
- |
yes |
Testing/Calc/CameraModel.xml |
3 |
- |
- |
3 |
Only CameraModel.xml is missing the reverse colorimetric tag, and it is used only for
XML→ICC conversion, dumping and writer-failure tests (CreateAllProfiles.sh:49,
iccdev-stdobserver-regression-tests.sh:261,275,
iccdev-issue-1148-writer-device-regression.sh:159,161,
iccdev-tool-coverage-baseline.sh:526,573-574, a iccDumpProfile -v only) — never as a
CMM source or destination. Nothing in the
suite covers this, which is why all 220 CTests on #2292's ASAN+UBSAN leg stayed green.
Build Instructions
cmake -S Build/Cmake -B build -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake --build build -j4
Reproduce
build/Tools/IccFromXml/iccFromXml Testing/SpecRef/SixChanInputRef.xml six.icc
build/Tools/IccFromXml/iccFromXml Testing/Calc/CameraModel.xml camodel.icc
# both ends opt out of D2B/B2D (intent code 11 -> icXformLutColor, bUseD2BxB2DxTags=false)
build/Tools/IccApplyToLink/iccApplyToLink link.icc 0 2 1 T 0 1 1 0 six.icc 11 camodel.icc 11
Measured Clang 21.1.3 Release. d1a7d42a is the commit before #2292 and its IccCmm.cpp
is byte-identical to f78e915a.
| chain |
d1a7d42a (before) |
09bba400 (after) |
six 11 → camodel 11 |
exit 0, MPE Element Chain: 1 elements, 6->3 channels |
exit 255, status 6: Missing tag in profile |
six 13 → camodel 13 |
exit 0, 6→3 |
exit 255, status 6 |
six 1 → camodel 1 (opt in) |
exit 0, 6→3 |
exit 0, link written |
The opt-in path is unaffected; only the opt-out changed.
The two candidate rulings
-
Refusing is correct. The caller asked for the colorimetric transform and the profile
does not have one in that direction, so icCmmStatProfileMissingTag is the honest
answer. Arguably ICC.2:2023 §0.1.2 supports this: the two PCS types are independent, so
the absence of a colorimetric reverse transform is a real property of the profile, not
something the CMM should paper over. Nothing to do but note it.
-
Fall back to the spectral tag when there is no colorimetric one. This keeps
CameraModel.xml-shaped profiles working and makes the carve-out tag-level ("use
BToDx on opt-in, or when there is no BToAx") rather than header-level ("use BToDx
on opt-in, or when the profile is spectral-only"). It is a larger change: the
colorimetric block at IccCmm.cpp:803-837 already runs as the fallback after the
spectral block, so a retry would need to be threaded in between that block and the
MatrixTRC / monochrome arms at :839-848, inside a long lifetime-sensitive function.
Related: #1982, #2292.
The question
After #2292 (
09bba400) a dual-PCS profile that carries no colorimetric tag in thedirection being used no longer resolves under the D2B/B2D opt-out: it refuses with
icCmmStatProfileMissingTagwhere master previously fell back to the spectral tag andwrote a link.
Is refusing correct, or should the opt-out fall back to
BToDx/DToBxwhen the profilehas no
BToAx/AToBxto offer?I have no strong view and did not decide it in #2292 — the fix there deliberately changed
only which tag is preferred, not what happens when the preferred one is absent. Whichever
way this is ruled I will PR it; I am not filing this to hand it off.
Why it changed
CIccXform::Createnow gates the spectral branch onspectralPCS && !pcs(
IccProfLib/IccCmm.cpp:611input,:759output), matching the five space-selectionsites in
CIccCmm::AddXform(:9093,:9112) andCIccNamedColorCmm::AddXform(
:11718,:11796,:11813). For a dual-PCS profile under the opt-out the spectralbranch is now skipped, the colorimetric block below it runs, and if that finds no tag
either the function falls through to the
MatrixTRC/ monochrome arms and then returnsNULL.Before #2292 the opt-out was ignored, so the spectral tag was selected and the chain
resolved. That is the defect #1982 reported — but for a profile with only a spectral tag
in that direction, ignoring the opt-out was also the only thing keeping it working.
The affected shape, and how rare it is
Testing/Calc/CameraModel.xml: Input class, v5.00,RgbData,PCS = XYZData,Spectral PCS = 0x0021ChannelReflectanceData, tagsA2B3andB2D3— noB2A3. Soas a destination it can only go through
B2D3.Sweeping all 221 tracked
*.xmlfor a non-empty<PCS>plus a<SpectralPCS>plus aB2Dtag gives exactly three profiles:Testing/SpecRef/SixChanCameraRef.xmlTesting/hybrid/MultSpectralRGB.xmlTesting/Calc/CameraModel.xmlOnly
CameraModel.xmlis missing the reverse colorimetric tag, and it is used only forXML→ICC conversion, dumping and writer-failure tests (
CreateAllProfiles.sh:49,iccdev-stdobserver-regression-tests.sh:261,275,iccdev-issue-1148-writer-device-regression.sh:159,161,iccdev-tool-coverage-baseline.sh:526,573-574, aiccDumpProfile -vonly) — never as aCMM source or destination. Nothing in the
suite covers this, which is why all 220 CTests on #2292's ASAN+UBSAN leg stayed green.
Build Instructions
Reproduce
build/Tools/IccFromXml/iccFromXml Testing/SpecRef/SixChanInputRef.xml six.icc build/Tools/IccFromXml/iccFromXml Testing/Calc/CameraModel.xml camodel.icc # both ends opt out of D2B/B2D (intent code 11 -> icXformLutColor, bUseD2BxB2DxTags=false) build/Tools/IccApplyToLink/iccApplyToLink link.icc 0 2 1 T 0 1 1 0 six.icc 11 camodel.icc 11Measured Clang 21.1.3 Release.
d1a7d42ais the commit before #2292 and itsIccCmm.cppis byte-identical to
f78e915a.d1a7d42a(before)09bba400(after)six 11 → camodel 11MPE Element Chain: 1 elements, 6->3 channelsstatus 6: Missing tag in profilesix 13 → camodel 13six 1 → camodel 1(opt in)The opt-in path is unaffected; only the opt-out changed.
The two candidate rulings
Refusing is correct. The caller asked for the colorimetric transform and the profile
does not have one in that direction, so
icCmmStatProfileMissingTagis the honestanswer. Arguably ICC.2:2023 §0.1.2 supports this: the two PCS types are independent, so
the absence of a colorimetric reverse transform is a real property of the profile, not
something the CMM should paper over. Nothing to do but note it.
Fall back to the spectral tag when there is no colorimetric one. This keeps
CameraModel.xml-shaped profiles working and makes the carve-out tag-level ("useBToDxon opt-in, or when there is noBToAx") rather than header-level ("useBToDxon opt-in, or when the profile is spectral-only"). It is a larger change: the
colorimetric block at
IccCmm.cpp:803-837already runs as the fallback after thespectral block, so a retry would need to be threaded in between that block and the
MatrixTRC/ monochrome arms at:839-848, inside a long lifetime-sensitive function.Related: #1982, #2292.