Hoyt's FORK of DemoIccMAX 2.1.17.hoyt
Documentation for Hoyt's FORK of DemoIccMAX
Loading...
Searching...
No Matches
IccPrmg.cpp
Go to the documentation of this file.
1/** @file
2File: IccPRMG.cpp
3
4Contains: Implementation of CIccPRMG class
5
6Version: V1
7
8Copyright: (c) see ICC Software License
9*/
10
11/*
12* The ICC Software License, Version 0.2
13*
14*
15* Copyright (c) 2005 The International Color Consortium. All rights
16* reserved.
17*
18* Redistribution and use in source and binary forms, with or without
19* modification, are permitted provided that the following conditions
20* are met:
21*
22* 1. Redistributions of source code must retain the above copyright
23* notice, this list of conditions and the following disclaimer.
24*
25* 2. Redistributions in binary form must reproduce the above copyright
26* notice, this list of conditions and the following disclaimer in
27* the documentation and/or other materials provided with the
28* distribution.
29*
30* 3. In the absence of prior written permission, the names "ICC" and "The
31* International Color Consortium" must not be used to imply that the
32* ICC organization endorses or promotes products derived from this
33* software.
34*
35*
36* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39* DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
40* ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47* SUCH DAMAGE.
48* ====================================================================
49*
50* This software consists of voluntary contributions made by many
51* individuals on behalf of the The International Color Consortium.
52*
53*
54* Membership in the ICC is encouraged when this software is used for
55* commercial purposes.
56*
57*
58* For more information on The International Color Consortium, please
59* see <http://www.color.org/>.
60*
61*
62*/
63
64#include "IccPrmg.h"
65#include "IccUtil.h"
66
67#ifdef USEREFICCMAXNAMESPACE
68namespace refIccMAX {
69#endif
70
71/**********************************************************************
72 * The following table is from the PRMG specification.
73 *
74 * The first dimension corresponds to hue values going from 0 to 360
75 * degrees in ten degree intervals (with 360 duplicating 0 for
76 * interpolation purposes.
77 *
78 * The second dimension corresponds to increasing lightness values. The
79 * first entry is for 3.5 L*, succeeding entries are for L* values
80 * increasing by 5 L* from 5 to 100. L* values below 3.5 or above 100
81 * are considered to be out of gamut.
82 */
83static icFloatNumber icPRMG_Chroma[37][20] = {
84 {0, 11, 26, 39, 52, 64, 74, 83, 91, 92, 91, 87, 82, 75, 67, 57, 47, 37, 25, 13},
85 {0, 10, 24, 38, 50, 62, 73, 82, 90, 92, 91, 87, 82, 75, 67, 58, 48, 37, 26, 13},
86 {0, 10, 23, 37, 50, 62, 73, 84, 93, 94, 94, 90, 85, 78, 70, 60, 50, 39, 27, 14},
87 {0, 9, 22, 35, 48, 61, 74, 86, 98, 100, 101, 96, 90, 83, 75, 65, 54, 42, 30, 15},
88 {0, 8, 21, 34, 47, 60, 73, 83, 93, 97, 101, 99, 97, 90, 83, 73, 61, 47, 34, 17},
89 {0, 8, 20, 32, 43, 55, 66, 77, 88, 95, 99, 101, 100, 98, 92, 85, 72, 56, 40, 20},
90 {0, 7, 17, 27, 37, 47, 57, 67, 76, 84, 91, 96, 100, 102, 103, 98, 90, 72, 51, 26},
91 {0, 6, 16, 25, 34, 43, 52, 60, 68, 76, 83, 90, 96, 100, 104, 107, 109, 100, 74, 37},
92 {0, 6, 15, 23, 32, 40, 48, 57, 64, 71, 78, 85, 91, 97, 103, 107, 110, 113, 110, 70},
93 {0, 6, 14, 22, 30, 39, 47, 55, 62, 68, 75, 82, 88, 95, 101, 106, 112, 117, 120, 123},
94 {0, 6, 14, 22, 30, 38, 46, 54, 61, 68, 74, 81, 88, 94, 100, 106, 109, 112, 112, 92},
95 {0, 6, 14, 22, 31, 39, 47, 55, 63, 69, 76, 83, 89, 96, 100, 103, 106, 107, 102, 75},
96 {0, 6, 15, 24, 32, 41, 49, 58, 66, 73, 80, 87, 93, 98, 101, 102, 99, 91, 73, 50},
97 {0, 6, 16, 25, 35, 44, 54, 63, 72, 80, 87, 93, 97, 101, 99, 94, 86, 73, 56, 34},
98 {0, 7, 18, 28, 38, 48, 57, 67, 77, 86, 95, 98, 101, 97, 93, 85, 75, 61, 44, 26},
99 {0, 7, 19, 30, 40, 51, 62, 72, 83, 92, 97, 99, 96, 91, 85, 76, 66, 52, 37, 22},
100 {0, 7, 20, 32, 44, 56, 68, 80, 92, 96, 99, 97, 92, 87, 79, 70, 59, 46, 33, 19},
101 {0, 8, 20, 32, 43, 53, 64, 75, 85, 91, 96, 93, 89, 82, 75, 65, 55, 42, 30, 17},
102 {0, 8, 20, 31, 41, 52, 62, 72, 81, 87, 92, 90, 86, 79, 71, 61, 52, 40, 28, 15},
103 {0, 8, 20, 30, 40, 50, 60, 68, 76, 82, 87, 85, 82, 76, 69, 60, 50, 39, 27, 14},
104 {0, 8, 20, 30, 38, 47, 56, 63, 70, 76, 82, 81, 77, 72, 66, 58, 49, 38, 27, 14},
105 {0, 8, 20, 29, 37, 46, 53, 60, 66, 73, 79, 80, 75, 70, 64, 57, 49, 38, 27, 14},
106 {0, 8, 20, 29, 37, 45, 52, 59, 65, 71, 76, 75, 72, 68, 63, 56, 48, 38, 27, 14},
107 {0, 9, 20, 29, 38, 46, 53, 59, 65, 70, 75, 73, 71, 66, 61, 54, 46, 36, 26, 13},
108 {0, 10, 22, 31, 40, 48, 55, 61, 67, 71, 74, 70, 66, 61, 56, 49, 41, 32, 23, 12},
109 {0, 11, 24, 34, 43, 51, 59, 65, 70, 73, 71, 68, 63, 58, 52, 45, 38, 30, 21, 11},
110 {0, 14, 27, 38, 48, 57, 64, 69, 73, 73, 70, 66, 61, 56, 50, 43, 35, 28, 20, 10},
111 {0, 17, 32, 45, 55, 65, 70, 75, 75, 73, 70, 66, 61, 55, 49, 42, 34, 27, 19, 10},
112 {0, 21, 42, 55, 68, 75, 81, 80, 79, 76, 72, 67, 61, 55, 49, 41, 34, 26, 18, 9},
113 {0, 26, 52, 68, 83, 86, 89, 87, 84, 80, 75, 69, 63, 57, 50, 42, 35, 27, 18, 10},
114 {0, 25, 69, 82, 95, 94, 93, 91, 88, 85, 79, 73, 66, 59, 52, 44, 36, 28, 19, 10},
115 {0, 21, 51, 74, 91, 97, 100, 98, 95, 90, 84, 77, 70, 63, 55, 47, 39, 30, 20, 10},
116 {0, 18, 41, 62, 79, 91, 102, 101, 98, 95, 89, 83, 76, 68, 60, 51, 42, 32, 22, 11},
117 {0, 16, 35, 53, 71, 82, 91, 100, 104, 102, 98, 91, 84, 76, 67, 57, 47, 36, 24, 12},
118 {0, 14, 31, 46, 61, 73, 83, 92, 101, 103, 99, 95, 89, 80, 71, 61, 50, 38, 26, 13},
119 {0, 12, 28, 42, 55, 68, 77, 86, 94, 96, 93, 90, 85, 77, 68, 58, 48, 37, 25, 13},
120 {0, 11, 26, 39, 52, 64, 74, 83, 91, 92, 91, 87, 82, 75, 67, 57, 47, 37, 25, 13},
121};
122
123static int icClamp(int val, int minVal, int maxVal)
124{
125 if (val < minVal)
126 return minVal;
127 else if (val > maxVal)
128 return maxVal;
129 return val;
130}
131
133{
134 m_nTotal = m_nDE1 = m_nDE2 = m_nDE3 = m_nDE5 = m_nDE10 = 0;
135 m_bPrmgImplied = false;
136}
137
139{
140 if (L < 3.5 || L > 100.0)
141 return -1;
142
143 int nHIndex, nLIndex;
144 icFloatNumber dHFraction, dLFraction;
145
146 // Normalize h to the range [0, 360)
147 while (h < 0.0)
148 h += 360.0;
149 while (h >= 360.0)
150 h -= 360.0;
151
152 nHIndex = (int)(h / 10.0);
153 dHFraction = (h - nHIndex * 10.0f) / 10.0f;
154
155 if (L < 5) {
156 nLIndex = 0;
157 dLFraction = (L - 3.5f) / (5.0f - 3.5f);
158 } else if (L == 100.0) {
159 nLIndex = 19; // Assuming 19 is a safe index, adapt if necessary
160 dLFraction = 1.0;
161 } else {
162 nLIndex = (int)((L - 5.0) / 5.0) + 1;
163 dLFraction = (L - nLIndex * 5.0f) / 5.0f;
164 }
165
166 // Determine the bounds of the icPRMG_Chroma array (replace with actual bounds)
167 const int maxHIndex = sizeof(icPRMG_Chroma) / sizeof(icPRMG_Chroma[0]) - 1;
168 const int maxLIndex = sizeof(icPRMG_Chroma[0]) / sizeof(icPRMG_Chroma[0][0]) - 1;
169
170 // Clamp indices to prevent out-of-bounds access
171 nHIndex = icClamp(nHIndex, 0, maxHIndex - 1);
172 nLIndex = icClamp(nLIndex, 0, maxLIndex - 1);
173
174 icFloatNumber dInvLFraction = 1.0f - dLFraction;
175
176 // Interpolate chroma values safely
177 icFloatNumber ch1 = icPRMG_Chroma[nHIndex][nLIndex] * dInvLFraction
178 + icPRMG_Chroma[nHIndex][nLIndex+1] * dLFraction;
179 icFloatNumber ch2 = icPRMG_Chroma[nHIndex+1][nLIndex] * dInvLFraction
180 + icPRMG_Chroma[nHIndex+1][nLIndex+1] * dLFraction;
181
182 return ch1 * (1.0f - dHFraction) + ch2 * dHFraction;
183}
184
186{
187 icFloatNumber dChroma = GetChroma(L, h);
188
189 if (dChroma<0.0 || c>dChroma)
190 return false;
191
192 return true;
193}
194
196{
197 icFloatNumber Lch[3];
198
199 icLab2Lch(Lch, Lab);
200 return InGamut(Lch[0], Lch[1], Lch[2]);
201}
202
203icStatusCMM CIccPRMG::EvaluateProfile(CIccProfile *pProfile, icRenderingIntent nIntent/* =icUnknownIntent */,
204 icXformInterp nInterp/* =icInterpLinear */, bool buseMpeTags/* =true */)
205{
206 if (!pProfile)
207 {
209 }
210
211 if (pProfile->m_Header.deviceClass!=icSigInputClass &&
212 pProfile->m_Header.deviceClass!=icSigDisplayClass &&
213 pProfile->m_Header.deviceClass!=icSigOutputClass &&
214 pProfile->m_Header.deviceClass!=icSigColorSpaceClass)
215 {
217 }
218
219 m_bPrmgImplied = false;
220 if (nIntent==icPerceptual || nIntent==icSaturation) {
222 CIccTag *pSigTag = pProfile->FindTag(rigSig);
223
224 if (pSigTag && pSigTag->GetType()==icSigSignatureType) {
225 CIccTagSignature *pSig = (CIccTagSignature*)pSigTag;
226
228 m_bPrmgImplied = true;
229 }
230 }
231
232 CIccCmm Lab2Dev2Lab(icSigLabData, icSigLabData, false);
233
234 icStatusCMM result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, NULL, icXformLutColorimetric, buseMpeTags);
235 if (result != icCmmStatOk) {
236 return result;
237 }
238
239 result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, NULL, icXformLutColorimetric, buseMpeTags);
240 if (result != icCmmStatOk) {
241 return result;
242 }
243
244 result = Lab2Dev2Lab.Begin();
245 if (result != icCmmStatOk) {
246 return result;
247 }
248 icFloatNumber pcs[3], Lab1[3], Lab2[3], dE;
249
250 m_nTotal = m_nDE1 = m_nDE2 = m_nDE3 = m_nDE5 = m_nDE10 = 0;
251
252 for (pcs[0]=0.0; pcs[0]<=1.0; pcs[0] += (icFloatNumber)0.01) {
253 for (pcs[1]=0.0; pcs[1]<=1.0; pcs[1] += (icFloatNumber)0.01) {
254 for (pcs[2]=0.0; pcs[2]<=1.0; pcs[2] += (icFloatNumber)0.01) {
255 memcpy(Lab1, pcs, 3*sizeof(icFloatNumber));
256 icLabFromPcs(Lab1);
257 if (InGamut(Lab1)) {
258 Lab2Dev2Lab.Apply(Lab2, pcs);
259 icLabFromPcs(Lab2);
260
261 dE = icDeltaE(Lab1, Lab2);
262 m_nTotal++;
263
264 if (dE<=1.0) {
265 m_nDE1++;
266 m_nDE2++;
267 m_nDE3++;
268 m_nDE5++;
269 m_nDE10++;
270 }
271 else if (dE<=2.0) {
272 m_nDE2++;
273 m_nDE3++;
274 m_nDE5++;
275 m_nDE10++;
276 }
277 else if (dE<=3.0) {
278 m_nDE3++;
279 m_nDE5++;
280 m_nDE10++;
281 }
282 else if (dE<=5.0) {
283 m_nDE5++;
284 m_nDE10++;
285 }
286 else if (dE<=10.0) {
287 m_nDE10++;
288 }
289 }
290 }
291 }
292 }
293
294 return icCmmStatOk;
295}
296
297icStatusCMM CIccPRMG::EvaluateProfile(const icChar *szProfilePath, icRenderingIntent nIntent/* =icUnknownIntent */,
298 icXformInterp nInterp/* =icInterpLinear */, bool buseMpeTags/* =true */)
299{
300 CIccProfile *pProfile = ReadIccProfile(szProfilePath);
301
302 if (!pProfile)
304
305 icStatusCMM result = EvaluateProfile(pProfile, nIntent, nInterp, buseMpeTags);
306
307 delete pProfile;
308
309 return result;
310}
311
312
313#ifdef USEREFICCMAXNAMESPACE
314}
315#endif
@ icXformLutColorimetric
Definition IccCmm.h:135
icXformInterp
CMM Interpolation types.
Definition IccCmm.h:113
icStatusCMM
CMM return status values.
Definition IccCmm.h:90
@ icCmmStatInvalidProfile
Definition IccCmm.h:95
@ icCmmStatCantOpenProfile
Definition IccCmm.h:93
@ icCmmStatOk
Definition IccCmm.h:92
float icFloatNumber
All floating point operations/variables in IccProfLib use the icFloatNumber data type.
Definition IccDefs.h:100
char icChar
Definition IccDefs.h:109
static icFloatNumber icPRMG_Chroma[37][20]
Definition IccPrmg.cpp:83
static int icClamp(int val, int minVal, int maxVal)
Definition IccPrmg.cpp:123
File: IccPrmg.h.
CIccProfile * ReadIccProfile(const icChar *szFilename, bool bUseSubProfile)
Name: ReadIccProfile.
void icLabFromPcs(icFloatNumber *Lab)
Floating point encoding of Lab in PCS is in range 0.0 to 1.0.
Definition IccUtil.cpp:919
icFloatNumber icDeltaE(const icFloatNumber *lab1, const icFloatNumber *lab2)
Definition IccUtil.cpp:527
void icLab2Lch(icFloatNumber *Lch, icFloatNumber *Lab)
Definition IccUtil.cpp:881
File: IccUtil.h.
unsigned int icUInt32Number
icFloatNumber GetChroma(icFloatNumber L, icFloatNumber h)
Definition IccPrmg.cpp:138
bool InGamut(icFloatNumber *Lab)
Definition IccPrmg.cpp:195
icStatusCMM EvaluateProfile(CIccProfile *pProfile, icRenderingIntent nIntent=((icRenderingIntent) 0x3f3f3f3f), icXformInterp nInterp=icInterpLinear, bool buseMpeTags=true)
Definition IccPrmg.cpp:203
Class: CIccTag.
virtual icTagTypeSignature GetType() const
Function: GetType()
Class: CIccTagSignature.
icUInt32Number GetValue() const
@ icSigDisplayClass
@ icSigOutputClass
@ icSigInputClass
@ icSigColorSpaceClass
@ icSigLabData
@ icSigSignatureType
@ icSigPerceptualReferenceMediumGamut
icTagSignature
public tags and sizes
@ icSigPerceptualRenderingIntentGamutTag
icRenderingIntent
Rendering Intents, used in the profile header.
@ icPerceptual
@ icSaturation