From d71a97367018c8d661fe245df996373b00ef36f9 Mon Sep 17 00:00:00 2001 From: colourbill-ctrl Date: Fri, 12 Jun 2026 10:24:38 -0700 Subject: [PATCH] Decode icStatusCMM in tool/connect error messages (#1322, #1323) iccApplyToLink reported any CIccCmm::AddXform failure as "Invalid Profile(N)" and the IccConnect stage loop reported "AddXform failed ... (status N)" with a bare number. Both misled triage when the actual failure was icCmmStatBadSpaceLink (2) - a chain-level color space mismatch with a structurally valid profile. - iccApplyToLink: report "Unable to add to transform chain (status N: )" via CIccCmm::GetStatusText, with an extra hint for bad space links; decode the Begin() status too. - IccConnect.cpp: append GetStatusText(stat) to the four AddXform failure messages and three Begin() failure messages. - CIccCmm::GetStatusText: add missing icCmmStatUnsupported case. No behavior change; message text only. Exit codes unchanged. Verified against the #1322/#1323 repro commands and RunTests.sh. Co-Authored-By: Claude Fable 5 --- IccConnect/IccLibConnect/IccConnect.cpp | 35 +++++++++++++++---- IccProfLib/IccCmm.cpp | 6 ++++ .../CmdLine/IccApplyToLink/iccApplyToLink.cpp | 23 ++++++++++-- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/IccConnect/IccLibConnect/IccConnect.cpp b/IccConnect/IccLibConnect/IccConnect.cpp index eda58b154..f4e788af4 100644 --- a/IccConnect/IccLibConnect/IccConnect.cpp +++ b/IccConnect/IccLibConnect/IccConnect.cpp @@ -250,8 +250,16 @@ icStatusCMM CIccConnectCmm::AddXformFromConfig(CIccCmm* pCmm, sErrorMsg = "unable to open ICC profile '" + pCfg->m_iccFile + "'"; } else if (stat != icCmmStatOk) { + // AddXform rejects a profile for chain-level reasons as well as + // profile-level ones (e.g. icCmmStatBadSpaceLink (2) means the profile's + // connecting color space does not match the output space of the previous + // stage - or, for the first stage, the color space of the source data). + // A bare numeric status forced users to look up the icStatusCMM enum to + // triage failures (issue #1323), so decode it with + // CIccCmm::GetStatusText alongside the number. std::ostringstream oss; - oss << "AddXform failed for '" << pCfg->m_iccFile << "' (status " << (int)stat << ")"; + oss << "AddXform failed for '" << pCfg->m_iccFile << "' (status " << (int)stat + << ": " << CIccCmm::GetStatusText(stat) << ")"; sErrorMsg = oss.str(); } return stat; @@ -295,8 +303,12 @@ CIccConnectCmm* CIccConnectCmm::CreateNamed(const CIccCfgProfileSequence& profil icStatusCMM beginStat = pCmm->Begin(); if (beginStat != icCmmStatOk) { + // Decode the status (issue #1323) - Begin() is where the named-color CMM + // finalizes connections between the queued xforms, so failures here are + // chain-compatibility problems rather than per-profile ones. std::ostringstream oss; - oss << "Begin() failed (status " << (int)beginStat << "); profile chain is incompatible"; + oss << "Begin() failed (status " << (int)beginStat << ": " + << CIccCmm::GetStatusText(beginStat) << "); profile chain is incompatible"; sErrorMsg = oss.str(); ReleasePccList(pccList); return nullptr; @@ -394,8 +406,11 @@ CIccConnectCmm* CIccConnectCmm::CreateStandard(const CIccCfgProfileSequence& pro pCfg->m_useV5SubProfile ); if (stat != icCmmStatOk) { + // Same status decoding as AddXformFromConfig (issue #1323): report + // the icStatusCMM name, not just the raw number. std::ostringstream oss; - oss << "AddXform failed for embedded source profile (status " << (int)stat << ")"; + oss << "AddXform failed for embedded source profile (status " << (int)stat + << ": " << CIccCmm::GetStatusText(stat) << ")"; sStageErr = oss.str(); } } @@ -418,7 +433,10 @@ CIccConnectCmm* CIccConnectCmm::CreateStandard(const CIccCfgProfileSequence& pro icStatusCMM beginStat = pCmm->Begin(); if (beginStat != icCmmStatOk) { std::ostringstream oss; - oss << "Begin() failed (status " << (int)beginStat + // Decode the status name (issue #1323) in addition to the raw number and + // the source/destination spaces already reported below. + oss << "Begin() failed (status " << std::dec << (int)beginStat << ": " + << CIccCmm::GetStatusText(beginStat) << "); profile chain is incompatible (srcSpace=0x" << std::hex << (unsigned)pCmm->GetSourceSpace() << " dstSpace=0x" << (unsigned)pCmm->GetDestSpace() << ")"; @@ -500,8 +518,11 @@ CIccConnectCmm* CIccConnectCmm::CreateSearch(const CIccCfgSearchApply& searchApp sStageErr = "unable to open ICC profile '" + pCfg->m_iccFile + "'"; } else if (stat != icCmmStatOk) { + // Same status decoding as AddXformFromConfig (issue #1323): report + // the icStatusCMM name, not just the raw number. std::ostringstream oss; - oss << "AddXform failed for '" << pCfg->m_iccFile << "' (status " << (int)stat << ")"; + oss << "AddXform failed for '" << pCfg->m_iccFile << "' (status " << (int)stat + << ": " << CIccCmm::GetStatusText(stat) << ")"; sStageErr = oss.str(); } @@ -591,7 +612,9 @@ CIccConnectCmm* CIccConnectCmm::CreateSearch(const CIccCfgSearchApply& searchApp icStatusCMM beginStat = pCmm->Begin(); if (beginStat != icCmmStatOk) { std::ostringstream oss; - oss << "Begin() failed (status " << (int)beginStat + // Decode the status name (issue #1323) in addition to the raw number. + oss << "Begin() failed (status " << (int)beginStat << ": " + << CIccCmm::GetStatusText(beginStat) << "); search-profile chain is incompatible"; sErrorMsg = oss.str(); ReleasePccList(pccList); diff --git a/IccProfLib/IccCmm.cpp b/IccProfLib/IccCmm.cpp index 487de42bd..585425bcf 100644 --- a/IccProfLib/IccCmm.cpp +++ b/IccProfLib/IccCmm.cpp @@ -8298,6 +8298,12 @@ const icChar* CIccCmm::GetStatusText(icStatusCMM stat) return "Too many samples used"; case icCmmStatBadMCSLink: return "Invalid MCS link connection"; + // icCmmStatUnsupported was added to icStatusCMM without a matching case + // here (the enum declaration in IccCmm.h asks for GetStatusText to be kept + // in sync). Added while wiring status names into the CLI tool error + // messages for issues #1322/#1323 so every enum value decodes to text. + case icCmmStatUnsupported: + return "Unsupported operation"; default: return "Unknown CMM Status value"; diff --git a/Tools/CmdLine/IccApplyToLink/iccApplyToLink.cpp b/Tools/CmdLine/IccApplyToLink/iccApplyToLink.cpp index b2ca1cc43..3bf85fc7c 100644 --- a/Tools/CmdLine/IccApplyToLink/iccApplyToLink.cpp +++ b/Tools/CmdLine/IccApplyToLink/iccApplyToLink.cpp @@ -799,7 +799,21 @@ int main(int argc, icChar* argv[]) stat = theCmm.AddXform(pXformProfile, nIntent<0 ? icUnknownIntent : (icRenderingIntent)nIntent, nInterp, pPccProfile, (icXformLutType)nType, bUseD2BxB2DxTags, &Hint); if (stat) { - printf("Invalid Profile(%d): %s\n", stat, argv[nCount]); + // AddXform can fail for reasons that have nothing to do with the + // profile itself. In particular icCmmStatBadSpaceLink (2) means the + // profile's source color space does not connect to the output space + // of the previous transform in the chain (CIccCmm alternates the + // input/output direction of successive profiles based on the + // first_transform argument, so the connecting spaces depend on chain + // position and direction, not just the profile). The old message + // here ("Invalid Profile(N)") reported any failure as an invalid + // profile, which misled users when a structurally valid profile was + // simply chained incompatibly - see issue #1322. Decode the status + // with CIccCmm::GetStatusText so the real cause is visible. + printf("Error - Unable to add '%s' to transform chain (status %d: %s)\n", argv[nCount], stat, CIccCmm::GetStatusText(stat)); + if (stat == icCmmStatBadSpaceLink) { + printf("The profile's color spaces do not connect with the previous transform in the chain.\n"); + } return -1; } sigMap.clear(); @@ -809,7 +823,12 @@ int main(int argc, icChar* argv[]) //All profiles have been added to CMM. Tell CMM that we are ready to begin applying colors/pixels if((stat=theCmm.Begin())) { - printf("Error %d - Unable to begin profile application - Possibly invalid or incompatible profiles\n", stat); + // Begin() walks the assembled xform list and connects/optimizes the + // transforms; it is where cross-profile incompatibilities that AddXform + // could not see (PCS conversion setup, connection conditions) surface. + // Decode the status code into text (issue #1322 follow-through) instead + // of printing a bare number. + printf("Error - Unable to begin profile application (status %d: %s) - Possibly invalid or incompatible profiles\n", stat, CIccCmm::GetStatusText(stat)); return -1; }