File: | IccProfLib/IccCmm.cpp |
Warning: | line 1937, column 5 Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /** @file | ||||
2 | File: IccCmm.cpp | ||||
3 | |||||
4 | Contains: Implementation of the CIccCmm class. | ||||
5 | |||||
6 | Version: V1 | ||||
7 | |||||
8 | Copyright: � see ICC Software License | ||||
9 | */ | ||||
10 | |||||
11 | /* | ||||
12 | * The ICC Software License, Version 0.2 | ||||
13 | * | ||||
14 | * | ||||
15 | * Copyright (c) 2003-2012 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 | ////////////////////////////////////////////////////////////////////// | ||||
65 | // HISTORY: | ||||
66 | // | ||||
67 | // -Initial implementation by Max Derhak 5-15-2003 | ||||
68 | // -Added support for Monochrome ICC profile apply by Rohit Patil 12-03-2008 | ||||
69 | // -Integrated changes for PCS adjustment by George Pawle 12-09-2008 | ||||
70 | // | ||||
71 | ////////////////////////////////////////////////////////////////////// | ||||
72 | |||||
73 | #ifdef WIN32 | ||||
74 | #pragma warning( disable: 4786) //disable warning in <list.h> | ||||
75 | #endif | ||||
76 | |||||
77 | #include "IccXformFactory.h" | ||||
78 | #include "IccTag.h" | ||||
79 | #include "IccMpeBasic.h" | ||||
80 | #include "IccArrayBasic.h" | ||||
81 | #include "IccStructBasic.h" | ||||
82 | #include "IccIO.h" | ||||
83 | #include "IccApplyBPC.h" | ||||
84 | #include "IccSparseMatrix.h" | ||||
85 | #include "IccEncoding.h" | ||||
86 | #include "IccMatrixMath.h" | ||||
87 | |||||
88 | #ifdef USEREFICCMAXNAMESPACE | ||||
89 | namespace refIccMAX { | ||||
90 | #endif | ||||
91 | |||||
92 | //// | ||||
93 | // Useful Macros | ||||
94 | //// | ||||
95 | |||||
96 | static __inlineinline bool IsSpaceSpectralPCS(icUInt32Number sig) | ||||
97 | { | ||||
98 | sig = icGetColorSpaceType(sig)((icColorSpaceSignature)(((icUInt32Number)sig)&0xffff0000 )); | ||||
99 | |||||
100 | return sig==icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData) || | ||||
101 | sig==icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData) || | ||||
102 | sig==icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData) || | ||||
103 | sig==icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData) || | ||||
104 | sig==icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData); | ||||
105 | } | ||||
106 | |||||
107 | #define IsSpaceColorimetricPCS(x)((x)==icSigXYZData || (x)==icSigLabData) ((x)==icSigXYZPcsDataicSigXYZData || (x)==icSigLabPcsDataicSigLabData) | ||||
108 | #define IsSpaceNChannel(x)(((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000) )==icSigNChannelData) (icGetColorSpaceType(x)((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000))==icSigNChannelData) | ||||
109 | #define IsSpacePCS(x)(((x)==icSigXYZData || (x)==icSigLabData) || IsSpaceSpectralPCS (x)) (IsSpaceColorimetricPCS(x)((x)==icSigXYZData || (x)==icSigLabData) || IsSpaceSpectralPCS(x)) | ||||
110 | #define IsSpaceMCS(x)(((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000) )==icSigSrcMCSChannelData) (icGetColorSpaceType(x)((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000))==icSigSrcMCSChannelData) | ||||
111 | #define IsSpaceCMYK(x)((x)==icSigCmykData || (x)==icSig4colorData) ((x)==icSigCmykData || (x)==icSig4colorData) | ||||
112 | |||||
113 | #define IsNChannelCompat(x, y)(((((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000 ))==icSigNChannelData) && (((icUInt32Number)x)&0x0000ffff )==icGetSpaceSamples(y)) || ((((icColorSpaceSignature)(((icUInt32Number )y)&0xffff0000))==icSigNChannelData) && (((icUInt32Number )y)&0x0000ffff)==icGetSpaceSamples(x))) ((IsSpaceNChannel(x)(((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000) )==icSigNChannelData) && icNumColorSpaceChannels(x)(((icUInt32Number)x)&0x0000ffff)==icGetSpaceSamples(y)) || (IsSpaceNChannel(y)(((icColorSpaceSignature)(((icUInt32Number)y)&0xffff0000) )==icSigNChannelData) && icNumColorSpaceChannels(y)(((icUInt32Number)y)&0x0000ffff)==icGetSpaceSamples(x))) | ||||
114 | |||||
115 | #define IsCompatSpace(x, y)((x)==(y) || ((((x)==icSigXYZData || (x)==icSigLabData) || IsSpaceSpectralPCS (x)) && (((y)==icSigXYZData || (y)==icSigLabData) || IsSpaceSpectralPCS (y))) || ((((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000 ))==icSigSrcMCSChannelData) && (((icColorSpaceSignature )(((icUInt32Number)y)&0xffff0000))==icSigSrcMCSChannelData )) ) ((x)==(y) || (IsSpacePCS(x)(((x)==icSigXYZData || (x)==icSigLabData) || IsSpaceSpectralPCS (x)) && IsSpacePCS(y)(((y)==icSigXYZData || (y)==icSigLabData) || IsSpaceSpectralPCS (y))) || (IsSpaceMCS(x)(((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000) )==icSigSrcMCSChannelData) && IsSpaceMCS(y)(((icColorSpaceSignature)(((icUInt32Number)y)&0xffff0000) )==icSigSrcMCSChannelData))/* || (IsSpaceCMYK(x) && IsSpaceCMYK(y))*/) | ||||
116 | |||||
117 | |||||
118 | #define ICCPCSSTEPDUMPFMT" %.8f" ICCMTXSTEPDUMPFMT" %.8f" | ||||
119 | |||||
120 | |||||
121 | ////////////////////////////////////////////////////////////////////// | ||||
122 | // Construction/Destruction | ||||
123 | ////////////////////////////////////////////////////////////////////// | ||||
124 | |||||
125 | /** | ||||
126 | ************************************************************************** | ||||
127 | * Class CIccPCS Constructor | ||||
128 | * | ||||
129 | * Purpose: | ||||
130 | * This is a class constructor. | ||||
131 | * | ||||
132 | ************************************************************************** | ||||
133 | */ | ||||
134 | CIccPCS::CIccPCS() | ||||
135 | { | ||||
136 | m_bIsV2Lab = false; | ||||
137 | m_Space = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | ||||
138 | m_bLastPcsXform = false; | ||||
139 | } | ||||
140 | |||||
141 | /** | ||||
142 | ************************************************************************** | ||||
143 | * Name: CIccPCS::Reset | ||||
144 | * | ||||
145 | * Purpose: | ||||
146 | * This is called with the initial color space and a bool | ||||
147 | * argument which is true if the PCS is version 2. | ||||
148 | * | ||||
149 | * Args: | ||||
150 | * Startpsace = Starting Colorspace | ||||
151 | * bUseLegacyPCS = legacy PCS flag | ||||
152 | ************************************************************************** | ||||
153 | */ | ||||
154 | void CIccPCS::Reset(icColorSpaceSignature StartSpace, bool bUseLegacyPCS) | ||||
155 | { | ||||
156 | m_bIsV2Lab = IsSpacePCS(StartSpace)(((StartSpace)==icSigXYZData || (StartSpace)==icSigLabData) || IsSpaceSpectralPCS(StartSpace)) && bUseLegacyPCS; | ||||
157 | m_Space = StartSpace; | ||||
158 | } | ||||
159 | |||||
160 | /** | ||||
161 | ************************************************************************** | ||||
162 | * Name: CIccPCS::Check | ||||
163 | * | ||||
164 | * Purpose: | ||||
165 | * This is called before the apply of each profile's xform to adjust the PCS | ||||
166 | * to the xform's needed PCS. | ||||
167 | * | ||||
168 | * Args: | ||||
169 | * SrcPixel = source pixel data (this may need adjusting), | ||||
170 | * pXform = the xform that who's Apply function will shortly be called | ||||
171 | * | ||||
172 | * Return: | ||||
173 | * SrcPixel or ptr to adjusted pixel data (we dont want to modify the source data). | ||||
174 | ************************************************************************** | ||||
175 | */ | ||||
176 | const icFloatNumber *CIccPCS::Check(const icFloatNumber *SrcPixel, const CIccXform *pXform) | ||||
177 | { | ||||
178 | icColorSpaceSignature NextSpace = pXform->GetSrcSpace(); | ||||
179 | bool bIsV2 = pXform->UseLegacyPCS(); | ||||
180 | bool bIsNextV2Lab = bIsV2 && (NextSpace == icSigLabData); | ||||
181 | const icFloatNumber *rv; | ||||
182 | bool bNoClip = pXform->NoClipPCS(); | ||||
183 | |||||
184 | if (m_bLastPcsXform) { | ||||
185 | rv = SrcPixel; | ||||
186 | } | ||||
187 | else if (m_bIsV2Lab && !bIsNextV2Lab) { | ||||
188 | Lab2ToLab4(m_Convert, SrcPixel, bNoClip); | ||||
189 | if (NextSpace==icSigXYZData) { | ||||
190 | LabToXyz(m_Convert, m_Convert, bNoClip); | ||||
191 | } | ||||
192 | rv = m_Convert; | ||||
193 | } | ||||
194 | else if (!m_bIsV2Lab && bIsNextV2Lab) { | ||||
195 | if (m_Space==icSigXYZData) { | ||||
196 | XyzToLab(m_Convert, SrcPixel, bNoClip); | ||||
197 | SrcPixel = m_Convert; | ||||
198 | } | ||||
199 | Lab4ToLab2(m_Convert, SrcPixel); | ||||
200 | rv = m_Convert; | ||||
201 | } | ||||
202 | else if (m_Space==NextSpace) { | ||||
203 | rv = SrcPixel; | ||||
204 | } | ||||
205 | else if (m_Space==icSigXYZData && NextSpace==icSigLabData) { | ||||
206 | XyzToLab(m_Convert, SrcPixel, bNoClip); | ||||
207 | rv = m_Convert; | ||||
208 | } | ||||
209 | else if (m_Space==icSigLabData && NextSpace==icSigXYZData) { | ||||
210 | LabToXyz(m_Convert, SrcPixel, bNoClip); | ||||
211 | rv = m_Convert; | ||||
212 | } | ||||
213 | else { | ||||
214 | rv = SrcPixel; | ||||
215 | } | ||||
216 | |||||
217 | m_Space = pXform->GetDstSpace(); | ||||
218 | m_bIsV2Lab = bIsV2 && (m_Space == icSigLabData); | ||||
219 | m_bLastPcsXform = (pXform->GetXformType()==icXformTypePCS); | ||||
220 | |||||
221 | return rv; | ||||
222 | } | ||||
223 | |||||
224 | /** | ||||
225 | ************************************************************************** | ||||
226 | * Name: CIccPCS::CheckLast | ||||
227 | * | ||||
228 | * Purpose: | ||||
229 | * Called after all xforms are applied to adjust PCS to final space if needed | ||||
230 | * Note: space will always be V4. | ||||
231 | * | ||||
232 | * Args: | ||||
233 | * Pixel = Pixel data, | ||||
234 | * DestSpace = destination color space | ||||
235 | * bNoClip = indicates whether PCS should be clipped | ||||
236 | ************************************************************************** | ||||
237 | */ | ||||
238 | void CIccPCS::CheckLast(icFloatNumber *Pixel, icColorSpaceSignature DestSpace, bool bNoClip) | ||||
239 | { | ||||
240 | if (m_bIsV2Lab) { | ||||
241 | Lab2ToLab4(Pixel, Pixel, bNoClip); | ||||
242 | if (DestSpace==icSigXYZData) { | ||||
243 | LabToXyz(Pixel, Pixel, bNoClip); | ||||
244 | } | ||||
245 | } | ||||
246 | else if (m_Space==DestSpace) { | ||||
247 | return; | ||||
248 | } | ||||
249 | else if (m_Space==icSigXYZData) { | ||||
250 | XyzToLab(Pixel, Pixel, bNoClip); | ||||
251 | } | ||||
252 | else if (m_Space==icSigLabData) { | ||||
253 | LabToXyz(Pixel, Pixel, bNoClip); | ||||
254 | } | ||||
255 | } | ||||
256 | |||||
257 | /** | ||||
258 | ************************************************************************** | ||||
259 | * Name: CIccPCS::UnitClip | ||||
260 | * | ||||
261 | * Purpose: | ||||
262 | * Convert a double to an icUInt16Number with clipping | ||||
263 | ************************************************************************** | ||||
264 | */ | ||||
265 | icFloatNumber CIccPCS::UnitClip(icFloatNumber v) | ||||
266 | { | ||||
267 | if (v<0) | ||||
268 | v = 0; | ||||
269 | if (v>1.0) | ||||
270 | v = 1.0; | ||||
271 | |||||
272 | return v; | ||||
273 | } | ||||
274 | |||||
275 | /** | ||||
276 | ************************************************************************** | ||||
277 | * Name: CIccPCS::NegClip | ||||
278 | * | ||||
279 | * Purpose: | ||||
280 | * Convert a double to an icUInt16Number with clipping of negative numbers | ||||
281 | ************************************************************************** | ||||
282 | */ | ||||
283 | icFloatNumber CIccPCS::NegClip(icFloatNumber v) | ||||
284 | { | ||||
285 | if (v<0) | ||||
286 | v=0; | ||||
287 | |||||
288 | return v; | ||||
289 | } | ||||
290 | |||||
291 | /** | ||||
292 | ************************************************************************** | ||||
293 | * Name: CIccPCS::LabToXyz | ||||
294 | * | ||||
295 | * Purpose: | ||||
296 | * Convert Lab to XYZ | ||||
297 | ************************************************************************** | ||||
298 | */ | ||||
299 | void CIccPCS::LabToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | ||||
300 | { | ||||
301 | icFloatNumber Lab[3]; | ||||
302 | |||||
303 | memcpy(&Lab,Src,sizeof(Lab)); | ||||
304 | |||||
305 | icLabFromPcs(Lab); | ||||
306 | |||||
307 | icLabtoXYZ(Lab); | ||||
308 | |||||
309 | icXyzToPcs(Lab); | ||||
310 | |||||
311 | if (!bNoClip) { | ||||
312 | Dst[0] = UnitClip(Lab[0]); | ||||
313 | Dst[1] = UnitClip(Lab[1]); | ||||
314 | Dst[2] = UnitClip(Lab[2]); | ||||
315 | } | ||||
316 | else { | ||||
317 | Dst[0] = Lab[0]; | ||||
318 | Dst[1] = Lab[1]; | ||||
319 | Dst[2] = Lab[2]; | ||||
320 | } | ||||
321 | } | ||||
322 | |||||
323 | |||||
324 | /** | ||||
325 | ************************************************************************** | ||||
326 | * Name: CIccPCS::XyzToLab | ||||
327 | * | ||||
328 | * Purpose: | ||||
329 | * Convert XYZ to Lab | ||||
330 | ************************************************************************** | ||||
331 | */ | ||||
332 | void CIccPCS::XyzToLab(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | ||||
333 | { | ||||
334 | icFloatNumber XYZ[3]; | ||||
335 | |||||
336 | |||||
337 | if (!bNoClip) { | ||||
338 | XYZ[0] = UnitClip(Src[0]); | ||||
339 | XYZ[1] = UnitClip(Src[1]); | ||||
340 | XYZ[2] = UnitClip(Src[2]); | ||||
341 | } | ||||
342 | else { | ||||
343 | XYZ[0] = Src[0]; | ||||
344 | XYZ[1] = Src[1]; | ||||
345 | XYZ[2] = Src[2]; | ||||
346 | } | ||||
347 | |||||
348 | icXyzFromPcs(XYZ); | ||||
349 | |||||
350 | icXYZtoLab(XYZ); | ||||
351 | |||||
352 | icLabToPcs(XYZ); | ||||
353 | |||||
354 | if (!bNoClip) { | ||||
355 | Dst[0] = UnitClip(XYZ[0]); | ||||
356 | Dst[1] = UnitClip(XYZ[1]); | ||||
357 | Dst[2] = UnitClip(XYZ[2]); | ||||
358 | } | ||||
359 | else { | ||||
360 | Dst[0] = XYZ[0]; | ||||
361 | Dst[1] = XYZ[1]; | ||||
362 | Dst[2] = XYZ[2]; | ||||
363 | } | ||||
364 | } | ||||
365 | |||||
366 | |||||
367 | /** | ||||
368 | ************************************************************************** | ||||
369 | * Name: CIccPCS::Lab2ToXyz | ||||
370 | * | ||||
371 | * Purpose: | ||||
372 | * Convert version 2 Lab to XYZ | ||||
373 | ************************************************************************** | ||||
374 | */ | ||||
375 | void CIccPCS::Lab2ToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | ||||
376 | { | ||||
377 | Lab2ToLab4(Dst, Src, bNoClip); | ||||
378 | LabToXyz(Dst, Dst, bNoClip); | ||||
379 | } | ||||
380 | |||||
381 | |||||
382 | /** | ||||
383 | ************************************************************************** | ||||
384 | * Name: CIccPCS::XyzToLab2 | ||||
385 | * | ||||
386 | * Purpose: | ||||
387 | * Convert XYZ to version 2 Lab | ||||
388 | ************************************************************************** | ||||
389 | */ | ||||
390 | void CIccPCS::XyzToLab2(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | ||||
391 | { | ||||
392 | XyzToLab(Dst, Src, bNoClip); | ||||
393 | Lab4ToLab2(Dst, Dst); | ||||
394 | } | ||||
395 | |||||
396 | |||||
397 | /** | ||||
398 | ************************************************************************** | ||||
399 | * Name: CIccPCS::Lab2ToLab4 | ||||
400 | * | ||||
401 | * Purpose: | ||||
402 | * Convert version 2 Lab to version 4 Lab | ||||
403 | ************************************************************************** | ||||
404 | */ | ||||
405 | void CIccPCS::Lab2ToLab4(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | ||||
406 | { | ||||
407 | if (bNoClip) { | ||||
408 | Dst[0] = (icFloatNumber)(Src[0] * 65535.0f / 65280.0f); | ||||
409 | Dst[1] = (icFloatNumber)(Src[1] * 65535.0f / 65280.0f); | ||||
410 | Dst[2] = (icFloatNumber)(Src[2] * 65535.0f / 65280.0f); | ||||
411 | } | ||||
412 | else { | ||||
413 | Dst[0] = UnitClip((icFloatNumber)(Src[0] * 65535.0f / 65280.0f)); | ||||
414 | Dst[1] = UnitClip((icFloatNumber)(Src[1] * 65535.0f / 65280.0f)); | ||||
415 | Dst[2] = UnitClip((icFloatNumber)(Src[2] * 65535.0f / 65280.0f)); | ||||
416 | } | ||||
417 | } | ||||
418 | |||||
419 | /** | ||||
420 | ************************************************************************** | ||||
421 | * Name: CIccPCS::Lab4ToLab2 | ||||
422 | * | ||||
423 | * Purpose: | ||||
424 | * Convert version 4 Lab to version 2 Lab | ||||
425 | ************************************************************************** | ||||
426 | */ | ||||
427 | void CIccPCS::Lab4ToLab2(icFloatNumber *Dst, const icFloatNumber *Src) | ||||
428 | { | ||||
429 | Dst[0] = (icFloatNumber)(Src[0] * 65280.0f / 65535.0f); | ||||
430 | Dst[1] = (icFloatNumber)(Src[1] * 65280.0f / 65535.0f); | ||||
431 | Dst[2] = (icFloatNumber)(Src[2] * 65280.0f / 65535.0f); | ||||
432 | } | ||||
433 | |||||
434 | /** | ||||
435 | ************************************************************************** | ||||
436 | * Name: CIccCreateXformHintManager::CIccCreateXformHintManager | ||||
437 | * | ||||
438 | * Purpose: | ||||
439 | * Destructor | ||||
440 | ************************************************************************** | ||||
441 | */ | ||||
442 | CIccCreateXformHintManager::~CIccCreateXformHintManager() | ||||
443 | { | ||||
444 | if (m_pList) { | ||||
445 | IIccCreateXformHintList::iterator i; | ||||
446 | |||||
447 | for (i=m_pList->begin(); i!=m_pList->end(); i++) { | ||||
448 | if (i->ptr) | ||||
449 | delete i->ptr; | ||||
450 | } | ||||
451 | |||||
452 | delete m_pList; | ||||
453 | } | ||||
454 | } | ||||
455 | |||||
456 | /** | ||||
457 | ************************************************************************** | ||||
458 | * Name: CIccCreateXformHintManager::AddHint | ||||
459 | * | ||||
460 | * Purpose: | ||||
461 | * Adds and owns the passed named hint to it's list. | ||||
462 | * | ||||
463 | * Args: | ||||
464 | * pHint = pointer to the hint object to be added | ||||
465 | * | ||||
466 | * Return: | ||||
467 | * true = hint added to the list | ||||
468 | * false = hint not added | ||||
469 | ************************************************************************** | ||||
470 | */ | ||||
471 | bool CIccCreateXformHintManager::AddHint(IIccCreateXformHint* pHint) | ||||
472 | { | ||||
473 | if (!m_pList) { | ||||
474 | m_pList = new IIccCreateXformHintList; | ||||
475 | } | ||||
476 | |||||
477 | if (pHint) { | ||||
478 | if (GetHint(pHint->GetHintType())) { | ||||
479 | delete pHint; | ||||
480 | return false; | ||||
481 | } | ||||
482 | IIccCreateXformHintPtr Hint; | ||||
483 | Hint.ptr = pHint; | ||||
484 | m_pList->push_back(Hint); | ||||
485 | return true; | ||||
486 | } | ||||
487 | |||||
488 | return false; | ||||
489 | } | ||||
490 | |||||
491 | /** | ||||
492 | ************************************************************************** | ||||
493 | * Name: CIccCreateXformHintManager::DeleteHint | ||||
494 | * | ||||
495 | * Purpose: | ||||
496 | * Deletes the object referenced by the passed named hint pointer | ||||
497 | * and removes it from the list. | ||||
498 | * | ||||
499 | * Args: | ||||
500 | * pHint = pointer to the hint object to be deleted | ||||
501 | * | ||||
502 | * Return: | ||||
503 | * true = hint found and deleted | ||||
504 | * false = hint not found | ||||
505 | ************************************************************************** | ||||
506 | */ | ||||
507 | bool CIccCreateXformHintManager::DeleteHint(IIccCreateXformHint* pHint) | ||||
508 | { | ||||
509 | if (m_pList && pHint) { | ||||
510 | IIccCreateXformHintList::iterator i; | ||||
511 | for (i=m_pList->begin(); i!=m_pList->end(); i++) { | ||||
512 | if (i->ptr) { | ||||
513 | if (i->ptr == pHint) { | ||||
514 | delete pHint; | ||||
515 | pHint = NULL__null; | ||||
516 | m_pList->erase(i); | ||||
517 | return true; | ||||
518 | } | ||||
519 | } | ||||
520 | } | ||||
521 | } | ||||
522 | |||||
523 | return false; | ||||
524 | } | ||||
525 | |||||
526 | /** | ||||
527 | ************************************************************************** | ||||
528 | * Name: CIccCreateXformHintManager::GetHint | ||||
529 | * | ||||
530 | * Purpose: | ||||
531 | * Finds and returns a pointer to the named hint. | ||||
532 | * | ||||
533 | * Args: | ||||
534 | * hintName = name of the desired hint | ||||
535 | * | ||||
536 | * Return: | ||||
537 | * Appropriate IIccCreateXformHint pointer | ||||
538 | ************************************************************************** | ||||
539 | */ | ||||
540 | IIccCreateXformHint* CIccCreateXformHintManager::GetHint(const char* hintName) | ||||
541 | { | ||||
542 | IIccCreateXformHint* pHint=NULL__null; | ||||
543 | |||||
544 | if (m_pList) { | ||||
545 | IIccCreateXformHintList::iterator i; | ||||
546 | for (i=m_pList->begin(); i!=m_pList->end(); i++) { | ||||
547 | if (i->ptr) { | ||||
548 | if (!strcmp(i->ptr->GetHintType(), hintName)) { | ||||
549 | pHint = i->ptr; | ||||
550 | break; | ||||
551 | } | ||||
552 | } | ||||
553 | } | ||||
554 | } | ||||
555 | |||||
556 | return pHint; | ||||
557 | } | ||||
558 | |||||
559 | /** | ||||
560 | ************************************************************************** | ||||
561 | * Name: CIccXform::CIccXform | ||||
562 | * | ||||
563 | * Purpose: | ||||
564 | * Constructor | ||||
565 | ************************************************************************** | ||||
566 | */ | ||||
567 | CIccXform::CIccXform() | ||||
568 | { | ||||
569 | m_pProfile = NULL__null; | ||||
570 | m_bInput = true; | ||||
571 | m_nIntent = icUnknownIntent((icRenderingIntent) 0x3f3f3f3f); | ||||
572 | m_pAdjustPCS = NULL__null; | ||||
573 | m_bAdjustPCS = false; | ||||
574 | m_bAbsToRel = false; | ||||
575 | m_nMCS = icNoMCS; | ||||
576 | m_bUseSpectralPCS = false; | ||||
577 | m_bSrcPcsConversion = true; | ||||
578 | m_bDstPcsConversion = true; | ||||
579 | m_pConnectionConditions = NULL__null; | ||||
580 | m_pCmmEnvVarLookup = NULL__null; | ||||
581 | } | ||||
582 | |||||
583 | |||||
584 | /** | ||||
585 | ************************************************************************** | ||||
586 | * Name: CIccXform::~CIccXform | ||||
587 | * | ||||
588 | * Purpose: | ||||
589 | * Destructor | ||||
590 | ************************************************************************** | ||||
591 | */ | ||||
592 | CIccXform::~CIccXform() | ||||
593 | { | ||||
594 | if (m_pProfile) | ||||
595 | delete m_pProfile; | ||||
596 | |||||
597 | if (m_pAdjustPCS) { | ||||
598 | delete m_pAdjustPCS; | ||||
599 | } | ||||
600 | |||||
601 | if (m_pCmmEnvVarLookup) { | ||||
602 | delete m_pCmmEnvVarLookup; | ||||
603 | } | ||||
604 | |||||
605 | } | ||||
606 | |||||
607 | |||||
608 | void CIccXform::DetachAll() | ||||
609 | { | ||||
610 | m_pProfile = NULL__null; | ||||
611 | m_pConnectionConditions = NULL__null; | ||||
612 | } | ||||
613 | |||||
614 | /** | ||||
615 | ************************************************************************** | ||||
616 | * Name: CIccXform::Create | ||||
617 | * | ||||
618 | * Purpose: | ||||
619 | * This is a static Creation function that creates derived CIccXform objects and | ||||
620 | * initializes them. | ||||
621 | * | ||||
622 | * Args: | ||||
623 | * pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will | ||||
624 | * be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile | ||||
625 | * object needs to be allocated on the heap. | ||||
626 | * bInput = flag to indicate whether to use the input or output side of the profile, | ||||
627 | * nIntent = the rendering intent to apply to the profile, | ||||
628 | * nInterp = the interpolation algorithm to use for N-D luts. | ||||
629 | * nLutType = selection of which transform lut to use | ||||
630 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | ||||
631 | * pHintManager = pointer to object that contains xform creation hints | ||||
632 | * | ||||
633 | * Return: | ||||
634 | * A suitable pXform object | ||||
635 | ************************************************************************** | ||||
636 | */ | ||||
637 | CIccXform *CIccXform::Create(CIccProfile *pProfile, | ||||
638 | bool bInput/* =true */, | ||||
639 | icRenderingIntent nIntent/* =icUnknownIntent */, | ||||
640 | icXformInterp nInterp/* =icInterpLinear */, | ||||
641 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
642 | icXformLutType nLutType/* =icXformLutColor */, | ||||
643 | bool bUseD2BTags/* =true */, CIccCreateXformHintManager *pHintManager/* =NULL */) | ||||
644 | { | ||||
645 | CIccXform *rv = NULL__null; | ||||
646 | icRenderingIntent nTagIntent = nIntent; | ||||
647 | bool bUseSpectralPCS = false; | ||||
648 | bool bAbsToRel = false; | ||||
649 | bool bRelToAbs = false; | ||||
650 | icMCSConnectionType nMCS = icNoMCS; | ||||
651 | icXformLutType nUseLutType = nLutType; | ||||
652 | bool bUseColorimeticTags = true; | ||||
653 | |||||
654 | if (nLutType == icXformLutSpectral) { | ||||
655 | nUseLutType = icXformLutColor; | ||||
656 | bUseD2BTags = true; | ||||
657 | bUseColorimeticTags = false; | ||||
658 | } | ||||
659 | else if (nLutType == icXformLutColorimetric) { | ||||
660 | nUseLutType = icXformLutColor; | ||||
661 | } | ||||
662 | |||||
663 | if (pProfile->m_Header.deviceClass==icSigColorEncodingClass) { | ||||
664 | CIccProfile *pEncProfile; | ||||
665 | if (icConvertEncodingProfile(pEncProfile, pProfile)!=icEncConvertOk) | ||||
666 | return NULL__null; | ||||
667 | delete pProfile; | ||||
668 | pProfile = pEncProfile; | ||||
669 | } | ||||
670 | if (pProfile->m_Header.deviceClass==icSigLinkClass/* && nIntent==icAbsoluteColorimetric*/) { | ||||
671 | nIntent = icPerceptual; | ||||
672 | } | ||||
673 | |||||
674 | if (nTagIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | ||||
675 | nTagIntent = icPerceptual; | ||||
676 | |||||
677 | switch (nUseLutType) { | ||||
678 | case icXformLutColor: | ||||
679 | if (bInput) { | ||||
680 | CIccTag *pTag = NULL__null; | ||||
681 | if (bUseD2BTags) { | ||||
682 | if (pProfile->m_Header.spectralPCS && nLutType!=icXformLutColorimetric) { | ||||
683 | pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent); | ||||
684 | |||||
685 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | ||||
686 | pTag = pProfile->FindTag(icSigDToB1Tag); | ||||
687 | if (pTag) | ||||
688 | nTagIntent = icRelativeColorimetric; | ||||
689 | } | ||||
690 | else if (!pTag && nTagIntent == icRelativeColorimetric) { | ||||
691 | pTag = pProfile->FindTag(icSigDToB3Tag); | ||||
692 | if (pTag) { | ||||
693 | nTagIntent = icAbsoluteColorimetric; | ||||
694 | bAbsToRel = true; | ||||
695 | } | ||||
696 | } | ||||
697 | |||||
698 | if (pTag) | ||||
699 | bUseSpectralPCS = true; | ||||
700 | |||||
701 | if (!pTag) { | ||||
702 | pTag = pProfile->FindTag(icSigDToB0Tag); | ||||
703 | } | ||||
704 | if (!pTag) { | ||||
705 | pTag = pProfile->FindTag(icSigDToB1Tag); | ||||
706 | } | ||||
707 | if (!pTag) { | ||||
708 | pTag = pProfile->FindTag(icSigDToB3Tag); | ||||
709 | if (pTag) { | ||||
710 | nTagIntent = icAbsoluteColorimetric; | ||||
711 | bAbsToRel = true; | ||||
712 | } | ||||
713 | } | ||||
714 | } | ||||
715 | else if (pProfile->m_Header.version < icVersionNumberV50x05000000) { | ||||
716 | pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent); | ||||
717 | |||||
718 | if (!pTag && nTagIntent ==icAbsoluteColorimetric) { | ||||
719 | pTag = pProfile->FindTag(icSigDToB1Tag); | ||||
720 | if (pTag) | ||||
721 | nTagIntent = icRelativeColorimetric; | ||||
722 | } | ||||
723 | |||||
724 | //Apparently Using DtoB0 is not prescribed here by the v4 ICC Specification | ||||
725 | if (!pTag && pProfile->m_Header.version >= icVersionNumberV50x05000000) { | ||||
726 | pTag = pProfile->FindTag(icSigDToB0Tag); | ||||
727 | } | ||||
728 | } | ||||
729 | } | ||||
730 | |||||
731 | if (bUseColorimeticTags) { | ||||
732 | if (!pTag) { | ||||
733 | pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent); | ||||
734 | } | ||||
735 | |||||
736 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | ||||
737 | pTag = pProfile->FindTag(icSigAToB1Tag); | ||||
738 | if (pTag) | ||||
739 | nTagIntent = icRelativeColorimetric; | ||||
740 | } | ||||
741 | else if (!pTag && nTagIntent == icRelativeColorimetric) { | ||||
742 | pTag = pProfile->FindTag(icSigAToB3Tag); | ||||
743 | if (pTag) { | ||||
744 | nTagIntent = icAbsoluteColorimetric; | ||||
745 | bAbsToRel = true; | ||||
746 | } | ||||
747 | } | ||||
748 | |||||
749 | if (!pTag) { | ||||
750 | pTag = pProfile->FindTag(icSigAToB0Tag); | ||||
751 | } | ||||
752 | if (!pTag) { | ||||
753 | pTag = pProfile->FindTag(icSigAToB1Tag); | ||||
754 | } | ||||
755 | if (!pTag) { | ||||
756 | pTag = pProfile->FindTag(icSigAToB3Tag); | ||||
757 | if (pTag) { | ||||
758 | nTagIntent = icAbsoluteColorimetric; | ||||
759 | bAbsToRel = true; | ||||
760 | } | ||||
761 | } | ||||
762 | } | ||||
763 | |||||
764 | //Unsupported elements cause fall back behavior | ||||
765 | if (pTag && !pTag->IsSupported()) | ||||
766 | pTag = NULL__null; | ||||
767 | |||||
768 | if (!pTag) { | ||||
769 | if (pProfile->m_Header.version < icVersionNumberV50x05000000) { | ||||
770 | //Matrix/TRC profiles are deprecated in v5 profiles | ||||
771 | if (pProfile->m_Header.colorSpace == icSigRgbData) { | ||||
772 | rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, NULL__null, pHintManager); | ||||
773 | } | ||||
774 | else if (pProfile->m_Header.colorSpace == icSigGrayData) { | ||||
775 | rv = CIccXformCreator::CreateXform(icXformTypeMonochrome, NULL__null, pHintManager); | ||||
776 | } | ||||
777 | else | ||||
778 | return NULL__null; | ||||
779 | } | ||||
780 | else | ||||
781 | return NULL__null; | ||||
782 | } | ||||
783 | else if (pTag->GetType()==icSigMultiProcessElementType) { | ||||
784 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | ||||
785 | } | ||||
786 | else { | ||||
787 | switch(pProfile->m_Header.colorSpace) { | ||||
788 | case icSigXYZData: | ||||
789 | case icSigLabData: | ||||
790 | case icSigLuvData: | ||||
791 | case icSigYCbCrData: | ||||
792 | case icSigYxyData: | ||||
793 | case icSigRgbData: | ||||
794 | case icSigHsvData: | ||||
795 | case icSigHlsData: | ||||
796 | case icSigCmyData: | ||||
797 | case icSig3colorData: | ||||
798 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | ||||
799 | break; | ||||
800 | |||||
801 | case icSigCmykData: | ||||
802 | case icSig4colorData: | ||||
803 | rv = CIccXformCreator::CreateXform(icXformType4DLut, pTag, pHintManager); | ||||
804 | break; | ||||
805 | |||||
806 | default: | ||||
807 | rv = CIccXformCreator::CreateXform(icXformTypeNDLut, pTag, pHintManager); | ||||
808 | break; | ||||
809 | } | ||||
810 | } | ||||
811 | } | ||||
812 | else { | ||||
813 | CIccTag *pTag = NULL__null; | ||||
814 | |||||
815 | if (nLutType == icXformLutColorimetric && pProfile->m_Header.version >= icVersionNumberV50x05000000) { | ||||
816 | bUseD2BTags = false; | ||||
817 | } | ||||
818 | |||||
819 | if (bUseD2BTags) { | ||||
820 | pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent); | ||||
821 | |||||
822 | //Additional precedence not prescribed by the v4 ICC Specification | ||||
823 | if (!pTag && pProfile->m_Header.version >= icVersionNumberV50x05000000) { | ||||
824 | pTag = pProfile->FindTag(icSigBToD0Tag); | ||||
825 | |||||
826 | if (!pTag) { | ||||
827 | pTag = pProfile->FindTag(icSigBToD1Tag); | ||||
828 | if (pTag) { | ||||
829 | nTagIntent = icRelativeColorimetric; | ||||
830 | if (nTagIntent==icAbsoluteColorimetric) | ||||
831 | bRelToAbs = true; | ||||
832 | } | ||||
833 | } | ||||
834 | |||||
835 | if (!pTag) { | ||||
836 | pTag = pProfile->FindTag(icSigBToD3Tag); | ||||
837 | if (pTag) { | ||||
838 | nTagIntent = icAbsoluteColorimetric; | ||||
839 | bAbsToRel = true; | ||||
840 | } | ||||
841 | } | ||||
842 | } | ||||
843 | |||||
844 | //Unsupported elements cause fall back behavior | ||||
845 | if (pTag && !pTag->IsSupported()) | ||||
846 | pTag = NULL__null; | ||||
847 | |||||
848 | if (pTag) | ||||
849 | bUseSpectralPCS = true; | ||||
850 | |||||
851 | if (!pTag && nTagIntent == icAbsoluteColorimetric && pProfile->m_Header.version < icVersionNumberV50x05000000) { | ||||
852 | pTag = pProfile->FindTag(icSigBToD1Tag); | ||||
853 | |||||
854 | //Unsupported elements cause fall back behavior | ||||
855 | if (pTag && !pTag->IsSupported()) | ||||
856 | pTag = NULL__null; | ||||
857 | |||||
858 | if (pTag) | ||||
859 | nTagIntent = icRelativeColorimetric; | ||||
860 | } | ||||
861 | } | ||||
862 | |||||
863 | if (bUseColorimeticTags) { | ||||
864 | |||||
865 | if (!pTag) { | ||||
866 | pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent); | ||||
867 | } | ||||
868 | |||||
869 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | ||||
870 | pTag = pProfile->FindTag(icSigBToA1Tag); | ||||
871 | if (pTag) | ||||
872 | nTagIntent = icRelativeColorimetric; | ||||
873 | } | ||||
874 | |||||
875 | if (!pTag) { | ||||
876 | pTag = pProfile->FindTag(icSigBToA0Tag); | ||||
877 | } | ||||
878 | |||||
879 | //Additional precedence not prescribed by the v4 ICC Specification | ||||
880 | if (!pTag && pProfile->m_Header.version >= icVersionNumberV50x05000000) { | ||||
881 | |||||
882 | pTag = pProfile->FindTag(icSigBToA1Tag); | ||||
883 | if (pTag) { | ||||
884 | nTagIntent = icRelativeColorimetric; | ||||
885 | if (nTagIntent == icAbsoluteColorimetric) | ||||
886 | bRelToAbs = true; | ||||
887 | } | ||||
888 | |||||
889 | if (!pTag) { | ||||
890 | pTag = pProfile->FindTag(icSigBToA3Tag); | ||||
891 | if (pTag) { | ||||
892 | nTagIntent = icAbsoluteColorimetric; | ||||
893 | bAbsToRel = true; | ||||
894 | } | ||||
895 | } | ||||
896 | } | ||||
897 | } | ||||
898 | |||||
899 | if (!pTag) { | ||||
900 | if (pProfile->m_Header.version < icVersionNumberV50x05000000) { | ||||
901 | if (pProfile->m_Header.colorSpace == icSigRgbData) { | ||||
902 | rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, pTag, pHintManager); | ||||
903 | } | ||||
904 | else if (pProfile->m_Header.colorSpace == icSigGrayData) { | ||||
905 | rv = CIccXformCreator::CreateXform(icXformTypeMonochrome, NULL__null, pHintManager); | ||||
906 | } | ||||
907 | else | ||||
908 | return NULL__null; | ||||
909 | } | ||||
910 | else | ||||
911 | return NULL__null; | ||||
912 | } | ||||
913 | else if (pTag->GetType()==icSigMultiProcessElementType) { | ||||
914 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | ||||
915 | } | ||||
916 | else { | ||||
917 | switch(pProfile->m_Header.pcs) { | ||||
918 | case icSigXYZData: | ||||
919 | case icSigLabData: | ||||
920 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | ||||
921 | break; | ||||
922 | |||||
923 | default: | ||||
924 | break; | ||||
925 | } | ||||
926 | } | ||||
927 | } | ||||
928 | break; | ||||
929 | |||||
930 | case icXformLutNamedColor: | ||||
931 | { | ||||
932 | CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag); | ||||
933 | if (!pTag) | ||||
934 | return NULL__null; | ||||
935 | |||||
936 | CIccCreateNamedColorXformHint* pNamedColorHint = new CIccCreateNamedColorXformHint(); | ||||
937 | pNamedColorHint->csPcs = pProfile->m_Header.pcs; | ||||
938 | pNamedColorHint->csDevice = pProfile->m_Header.colorSpace; | ||||
939 | pNamedColorHint->csSpectralPcs = pProfile->m_Header.spectralPCS; | ||||
940 | pNamedColorHint->spectralRange = pProfile->m_Header.spectralRange; | ||||
941 | pNamedColorHint->biSpectralRange = pProfile->m_Header.biSpectralRange; | ||||
942 | if (pHintManager) { | ||||
943 | pHintManager->AddHint(pNamedColorHint); | ||||
944 | rv = CIccXformCreator::CreateXform(icXformTypeNamedColor, pTag, pHintManager); | ||||
945 | pHintManager->DeleteHint(pNamedColorHint); | ||||
946 | } | ||||
947 | else { | ||||
948 | CIccCreateXformHintManager HintManager; | ||||
949 | HintManager.AddHint(pNamedColorHint); | ||||
950 | rv = CIccXformCreator::CreateXform(icXformTypeNamedColor, pTag, &HintManager); | ||||
951 | } | ||||
952 | |||||
953 | if (pProfile->m_Header.spectralPCS) | ||||
954 | bUseSpectralPCS = true; | ||||
955 | } | ||||
956 | break; | ||||
957 | |||||
958 | case icXformLutPreview: | ||||
959 | { | ||||
960 | bInput = false; | ||||
961 | CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent); | ||||
962 | if (!pTag) { | ||||
963 | pTag = pProfile->FindTag(icSigPreview0Tag); | ||||
964 | } | ||||
965 | if (!pTag) { | ||||
966 | return NULL__null; | ||||
967 | } | ||||
968 | else { | ||||
969 | switch(pProfile->m_Header.pcs) { | ||||
970 | case icSigXYZData: | ||||
971 | case icSigLabData: | ||||
972 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | ||||
973 | |||||
974 | default: | ||||
975 | break; | ||||
976 | } | ||||
977 | } | ||||
978 | } | ||||
979 | break; | ||||
980 | |||||
981 | case icXformLutGamut: | ||||
982 | { | ||||
983 | bInput = false; | ||||
984 | CIccTag *pTag = pProfile->FindTag(icSigGamutTag); | ||||
985 | if (!pTag) { | ||||
986 | return NULL__null; | ||||
987 | } | ||||
988 | else { | ||||
989 | switch(pProfile->m_Header.pcs) { | ||||
990 | case icSigXYZData: | ||||
991 | case icSigLabData: | ||||
992 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | ||||
993 | |||||
994 | default: | ||||
995 | break; | ||||
996 | } | ||||
997 | } | ||||
998 | } | ||||
999 | break; | ||||
1000 | |||||
1001 | case icXformLutBRDFParam: | ||||
1002 | { | ||||
1003 | // get the correct tag first | ||||
1004 | |||||
1005 | CIccTag *pTag = NULL__null; | ||||
1006 | if (bUseD2BTags) { | ||||
1007 | if (pProfile->m_Header.spectralPCS) { | ||||
1008 | |||||
1009 | pTag = pProfile->FindTag(icSigBrdfSpectralParameter0Tag + nTagIntent); | ||||
1010 | |||||
1011 | if (pTag) | ||||
1012 | bUseSpectralPCS = true; | ||||
1013 | } | ||||
1014 | } | ||||
1015 | else | ||||
1016 | { | ||||
1017 | pTag = pProfile->FindTag(icSigBrdfColorimetricParameter0Tag + nTagIntent); | ||||
1018 | |||||
1019 | //Unsupported elements cause fall back behavior | ||||
1020 | if (pTag && !pTag->IsSupported()) | ||||
1021 | pTag = NULL__null; | ||||
1022 | } | ||||
1023 | |||||
1024 | // now extract the correct part from the structure | ||||
1025 | CIccStructBRDF* pStructTag = dynamic_cast<CIccStructBRDF*>(pTag); | ||||
1026 | |||||
1027 | if (pStructTag != NULL__null) | ||||
1028 | { | ||||
1029 | CIccTag *pTag2 = NULL__null; | ||||
1030 | |||||
1031 | switch (nLutType) { | ||||
1032 | case icXformLutBRDFParam: | ||||
1033 | pTag2 = pStructTag->GetElem(icSigBrdfTransformMbr); | ||||
1034 | break; | ||||
1035 | default: | ||||
1036 | // can't get here, get rid of warning | ||||
1037 | break; | ||||
1038 | } | ||||
1039 | if (pTag2) | ||||
1040 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag2, pHintManager); | ||||
1041 | } | ||||
1042 | } | ||||
1043 | break; | ||||
1044 | |||||
1045 | case icXformLutBRDFDirect: | ||||
1046 | { | ||||
1047 | // get the correct tag first | ||||
1048 | |||||
1049 | CIccTag *pTag = NULL__null; | ||||
1050 | if (bUseD2BTags) { | ||||
1051 | if (pProfile->m_Header.spectralPCS) { | ||||
1052 | |||||
1053 | pTag = pProfile->FindTag(icSigBRDFDToB0Tag + nTagIntent); | ||||
1054 | |||||
1055 | if (pTag) | ||||
1056 | bUseSpectralPCS = true; | ||||
1057 | } | ||||
1058 | } | ||||
1059 | else | ||||
1060 | { | ||||
1061 | pTag = pProfile->FindTag(icSigBRDFAToB0Tag + nTagIntent); | ||||
1062 | |||||
1063 | //Unsupported elements cause fall back behavior | ||||
1064 | if (pTag && !pTag->IsSupported()) | ||||
1065 | pTag = NULL__null; | ||||
1066 | } | ||||
1067 | |||||
1068 | if (pTag != NULL__null) | ||||
1069 | { | ||||
1070 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | ||||
1071 | } | ||||
1072 | } | ||||
1073 | break; | ||||
1074 | |||||
1075 | case icXformLutBRDFMcsParam: | ||||
1076 | { | ||||
1077 | CIccTag *pTag = NULL__null; | ||||
1078 | if (pProfile->m_Header.deviceClass == icSigMaterialVisualizationClass) { | ||||
1079 | bInput = true; | ||||
1080 | nMCS = icFromMCS; | ||||
1081 | |||||
1082 | if (pProfile->m_Header.spectralPCS) { | ||||
1083 | pTag = pProfile->FindTag(icSigBRDFMToS0Tag + nTagIntent); | ||||
1084 | |||||
1085 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | ||||
1086 | pTag = pProfile->FindTag(icSigBRDFMToS1Tag); | ||||
1087 | if (pTag) | ||||
1088 | nTagIntent = icRelativeColorimetric; | ||||
1089 | } | ||||
1090 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | ||||
1091 | pTag = pProfile->FindTag(icSigBRDFMToS3Tag); | ||||
1092 | if (pTag) { | ||||
1093 | nTagIntent = icAbsoluteColorimetric; | ||||
1094 | bAbsToRel = true; | ||||
1095 | } | ||||
1096 | } | ||||
1097 | |||||
1098 | if (!pTag) { | ||||
1099 | pTag = pProfile->FindTag(icSigBRDFMToS0Tag); | ||||
1100 | } | ||||
1101 | if (!pTag) { | ||||
1102 | pTag = pProfile->FindTag(icSigBRDFMToS1Tag); | ||||
1103 | } | ||||
1104 | if (!pTag) { | ||||
1105 | pTag = pProfile->FindTag(icSigBRDFMToS3Tag); | ||||
1106 | if (pTag) { | ||||
1107 | nTagIntent = icAbsoluteColorimetric; | ||||
1108 | bAbsToRel = true; | ||||
1109 | } | ||||
1110 | } | ||||
1111 | |||||
1112 | if (pTag) | ||||
1113 | bUseSpectralPCS = true; | ||||
1114 | } | ||||
1115 | if (!pTag && pProfile->m_Header.pcs != 0) { | ||||
1116 | pTag = pProfile->FindTag(icSigBRDFMToB0Tag + nTagIntent); | ||||
1117 | |||||
1118 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | ||||
1119 | pTag = pProfile->FindTag(icSigBRDFMToB1Tag); | ||||
1120 | if (pTag) | ||||
1121 | nTagIntent = icRelativeColorimetric; | ||||
1122 | } | ||||
1123 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | ||||
1124 | pTag = pProfile->FindTag(icSigBRDFMToB3Tag); | ||||
1125 | if (pTag) { | ||||
1126 | nTagIntent = icAbsoluteColorimetric; | ||||
1127 | bAbsToRel = true; | ||||
1128 | } | ||||
1129 | } | ||||
1130 | if (!pTag) { | ||||
1131 | pTag = pProfile->FindTag(icSigBRDFMToB0Tag); | ||||
1132 | } | ||||
1133 | if (!pTag) { | ||||
1134 | pTag = pProfile->FindTag(icSigBRDFMToB1Tag); | ||||
1135 | } | ||||
1136 | if (!pTag) { | ||||
1137 | pTag = pProfile->FindTag(icSigBRDFMToB3Tag); | ||||
1138 | if (pTag) { | ||||
1139 | nTagIntent = icAbsoluteColorimetric; | ||||
1140 | bAbsToRel = true; | ||||
1141 | } | ||||
1142 | } | ||||
1143 | } | ||||
1144 | |||||
1145 | //Unsupported elements cause fall back behavior | ||||
1146 | if (pTag && !pTag->IsSupported()) | ||||
1147 | pTag = NULL__null; | ||||
1148 | |||||
1149 | //Unsupported elements cause fall back behavior | ||||
1150 | if (pTag && !pTag->IsSupported()) | ||||
1151 | pTag = NULL__null; | ||||
1152 | } | ||||
1153 | if (pTag && pProfile->m_Header.mcs) { | ||||
1154 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | ||||
1155 | } | ||||
1156 | else | ||||
1157 | rv = NULL__null; | ||||
1158 | } | ||||
1159 | break; | ||||
1160 | |||||
1161 | case icXformLutMCS: | ||||
1162 | { | ||||
1163 | CIccTag *pTag = NULL__null; | ||||
1164 | if (pProfile->m_Header.deviceClass==icSigMaterialIdentificationClass || | ||||
1165 | pProfile->m_Header.deviceClass==icSigInputClass) { | ||||
1166 | bInput = true; | ||||
1167 | nMCS = icToMCS; | ||||
1168 | pTag = pProfile->FindTag(icSigAToM0Tag); | ||||
1169 | } | ||||
1170 | else if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) { | ||||
1171 | bInput = true; | ||||
1172 | nMCS = icFromMCS; | ||||
1173 | |||||
1174 | if (pProfile->m_Header.spectralPCS) { | ||||
1175 | pTag = pProfile->FindTag(icSigMToS0Tag + nTagIntent); | ||||
1176 | |||||
1177 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | ||||
1178 | pTag = pProfile->FindTag(icSigMToS1Tag); | ||||
1179 | if (pTag) | ||||
1180 | nTagIntent = icRelativeColorimetric; | ||||
1181 | } | ||||
1182 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | ||||
1183 | pTag = pProfile->FindTag(icSigMToS3Tag); | ||||
1184 | if (pTag) { | ||||
1185 | nTagIntent = icAbsoluteColorimetric; | ||||
1186 | bAbsToRel = true; | ||||
1187 | } | ||||
1188 | } | ||||
1189 | |||||
1190 | if (!pTag) { | ||||
1191 | pTag = pProfile->FindTag(icSigMToS0Tag); | ||||
1192 | } | ||||
1193 | if (!pTag) { | ||||
1194 | pTag = pProfile->FindTag(icSigMToS1Tag); | ||||
1195 | } | ||||
1196 | if (!pTag) { | ||||
1197 | pTag = pProfile->FindTag(icSigMToS3Tag); | ||||
1198 | if (pTag) { | ||||
1199 | nTagIntent = icAbsoluteColorimetric; | ||||
1200 | bAbsToRel = true; | ||||
1201 | } | ||||
1202 | } | ||||
1203 | |||||
1204 | if (pTag) | ||||
1205 | bUseSpectralPCS = true; | ||||
1206 | } | ||||
1207 | if (!pTag && pProfile->m_Header.pcs!=0) { | ||||
1208 | pTag = pProfile->FindTag(icSigMToB0Tag + nTagIntent); | ||||
1209 | |||||
1210 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | ||||
1211 | pTag = pProfile->FindTag(icSigMToB1Tag); | ||||
1212 | if (pTag) | ||||
1213 | nTagIntent = icRelativeColorimetric; | ||||
1214 | } | ||||
1215 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | ||||
1216 | pTag = pProfile->FindTag(icSigMToB3Tag); | ||||
1217 | if (pTag) { | ||||
1218 | nTagIntent = icAbsoluteColorimetric; | ||||
1219 | bAbsToRel = true; | ||||
1220 | } | ||||
1221 | } | ||||
1222 | |||||
1223 | if (!pTag) { | ||||
1224 | pTag = pProfile->FindTag(icSigMToB0Tag); | ||||
1225 | } | ||||
1226 | if (!pTag) { | ||||
1227 | pTag = pProfile->FindTag(icSigMToB1Tag); | ||||
1228 | } | ||||
1229 | if (!pTag) { | ||||
1230 | pTag = pProfile->FindTag(icSigMToB3Tag); | ||||
1231 | if (pTag) { | ||||
1232 | nTagIntent = icAbsoluteColorimetric; | ||||
1233 | bAbsToRel = true; | ||||
1234 | } | ||||
1235 | } | ||||
1236 | } | ||||
1237 | |||||
1238 | //Unsupported elements cause fall back behavior | ||||
1239 | if (pTag && !pTag->IsSupported()) | ||||
1240 | pTag = NULL__null; | ||||
1241 | } | ||||
1242 | else if (pProfile->m_Header.deviceClass==icSigMaterialLinkClass) { | ||||
1243 | bInput = false; | ||||
1244 | nMCS = icFromMCS; | ||||
1245 | pTag = pProfile->FindTag(icSigMToA0Tag); | ||||
1246 | } | ||||
1247 | if (pTag && pProfile->m_Header.mcs) { | ||||
1248 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | ||||
1249 | } | ||||
1250 | else | ||||
1251 | rv = NULL__null; | ||||
1252 | } | ||||
1253 | break; | ||||
1254 | |||||
1255 | } | ||||
1256 | |||||
1257 | if (rv) { | ||||
1258 | if (pPcc) | ||||
1259 | rv->m_pConnectionConditions = pPcc; | ||||
1260 | else | ||||
1261 | rv->m_pConnectionConditions = pProfile; | ||||
1262 | |||||
1263 | rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel, nMCS); | ||||
1264 | } | ||||
1265 | |||||
1266 | return rv; | ||||
1267 | } | ||||
1268 | |||||
1269 | /** | ||||
1270 | ************************************************************************** | ||||
1271 | * Name: CIccXform::Create | ||||
1272 | * | ||||
1273 | * Purpose: | ||||
1274 | * This is a static Creation function that creates derived CIccXform objects and | ||||
1275 | * initializes them. | ||||
1276 | * | ||||
1277 | * Args: | ||||
1278 | * pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will | ||||
1279 | * be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile | ||||
1280 | * object needs to be allocated on the heap. | ||||
1281 | * pTag = tag that specifies transform to use. It is assumed to use colorimetric PCS and have a lut type of icXformLutColor. | ||||
1282 | * bInput = flag to indicate whether to use the input or output side of the profile, | ||||
1283 | * nIntent = the rendering intent to apply to the profile, | ||||
1284 | * nInterp = the interpolation algorithm to use for N-D luts. | ||||
1285 | * pPcc = pointer to profile connection conditions to associate with transform | ||||
1286 | * pHintManager = pointer to object that contains xform creation hints | ||||
1287 | * | ||||
1288 | * Return: | ||||
1289 | * A suitable pXform object | ||||
1290 | ************************************************************************** | ||||
1291 | */ | ||||
1292 | CIccXform *CIccXform::Create(CIccProfile *pProfile, | ||||
1293 | CIccTag *pTag, | ||||
1294 | bool bInput/* =true */, | ||||
1295 | icRenderingIntent nIntent/* =icUnknownIntent */, | ||||
1296 | icXformInterp nInterp/* =icInterpLinear */, | ||||
1297 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
1298 | bool bUseSpectralPCS/* =false*/, | ||||
1299 | CIccCreateXformHintManager *pHintManager/* =NULL */) | ||||
1300 | { | ||||
1301 | CIccXform *rv = NULL__null; | ||||
1302 | icRenderingIntent nTagIntent = nIntent; | ||||
1303 | bool bAbsToRel = false; | ||||
1304 | bool bRelToAbs = false; | ||||
1305 | icMCSConnectionType nMCS = icNoMCS; | ||||
1306 | |||||
1307 | if (pProfile->m_Header.deviceClass == icSigColorEncodingClass) { | ||||
1308 | return NULL__null; | ||||
1309 | } | ||||
1310 | |||||
1311 | if (pProfile->m_Header.deviceClass == icSigLinkClass/* && nIntent==icAbsoluteColorimetric*/) { | ||||
1312 | nIntent = icPerceptual; | ||||
1313 | } | ||||
1314 | |||||
1315 | if (nTagIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | ||||
1316 | nTagIntent = icPerceptual; | ||||
1317 | |||||
1318 | //Unsupported elements cause fall back behavior | ||||
1319 | if (pTag && !pTag->IsSupported()) | ||||
1320 | return NULL__null; | ||||
1321 | |||||
1322 | if (bInput) { | ||||
1323 | if (pTag->GetType() == icSigMultiProcessElementType) { | ||||
1324 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | ||||
1325 | } | ||||
1326 | else { | ||||
1327 | switch (pProfile->m_Header.colorSpace) { | ||||
1328 | case icSigXYZData: | ||||
1329 | case icSigLabData: | ||||
1330 | case icSigLuvData: | ||||
1331 | case icSigYCbCrData: | ||||
1332 | case icSigYxyData: | ||||
1333 | case icSigRgbData: | ||||
1334 | case icSigHsvData: | ||||
1335 | case icSigHlsData: | ||||
1336 | case icSigCmyData: | ||||
1337 | case icSig3colorData: | ||||
1338 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | ||||
1339 | break; | ||||
1340 | |||||
1341 | case icSigCmykData: | ||||
1342 | case icSig4colorData: | ||||
1343 | rv = CIccXformCreator::CreateXform(icXformType4DLut, pTag, pHintManager); | ||||
1344 | break; | ||||
1345 | |||||
1346 | default: | ||||
1347 | rv = CIccXformCreator::CreateXform(icXformTypeNDLut, pTag, pHintManager); | ||||
1348 | break; | ||||
1349 | } | ||||
1350 | } | ||||
1351 | } | ||||
1352 | else { | ||||
1353 | if (pTag->GetType() == icSigMultiProcessElementType) { | ||||
1354 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | ||||
1355 | } | ||||
1356 | else { | ||||
1357 | switch (pProfile->m_Header.pcs) { | ||||
1358 | case icSigXYZData: | ||||
1359 | case icSigLabData: | ||||
1360 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | ||||
1361 | break; | ||||
1362 | |||||
1363 | default: | ||||
1364 | break; | ||||
1365 | } | ||||
1366 | } | ||||
1367 | } | ||||
1368 | |||||
1369 | if (rv) { | ||||
1370 | if (pPcc) | ||||
1371 | rv->m_pConnectionConditions = pPcc; | ||||
1372 | else | ||||
1373 | rv->m_pConnectionConditions = pProfile; | ||||
1374 | |||||
1375 | rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel, nMCS); | ||||
1376 | } | ||||
1377 | |||||
1378 | return rv; | ||||
1379 | } | ||||
1380 | |||||
1381 | /** | ||||
1382 | ****************************************************************************** | ||||
1383 | * Name: CIccXform::SetParams | ||||
1384 | * | ||||
1385 | * Purpose: | ||||
1386 | * This is an accessor function to set private values. | ||||
1387 | * | ||||
1388 | * Args: | ||||
1389 | * pProfile = pointer to profile associated with transform | ||||
1390 | * bInput = indicates whether profile is input profile | ||||
1391 | * nIntent = rendering intent to apply to the profile | ||||
1392 | * nInterp = the interpolation algorithm to use for N-D luts | ||||
1393 | ******************************************************************************/ | ||||
1394 | void CIccXform::SetParams(CIccProfile *pProfile, bool bInput, icRenderingIntent nIntent, icRenderingIntent nTagIntent, | ||||
1395 | bool bUseSpectralPCS, icXformInterp nInterp, CIccCreateXformHintManager *pHintManager/* =NULL */, | ||||
1396 | bool bAbsToRel/*=false*/, icMCSConnectionType nMCS/*=icNoMCS*/) | ||||
1397 | { | ||||
1398 | m_pProfile = pProfile; | ||||
1399 | m_bInput = bInput; | ||||
1400 | m_nIntent = nIntent; | ||||
1401 | m_nTagIntent = nTagIntent; | ||||
1402 | m_nInterp = nInterp; | ||||
1403 | m_pAdjustPCS = NULL__null; | ||||
1404 | m_bUseSpectralPCS = bUseSpectralPCS; | ||||
1405 | m_bAbsToRel = bAbsToRel; | ||||
1406 | m_nMCS = nMCS; | ||||
1407 | m_bLuminanceMatching = false; | ||||
1408 | |||||
1409 | if (pHintManager) { | ||||
1410 | IIccCreateXformHint *pHint=NULL__null; | ||||
1411 | |||||
1412 | pHint = pHintManager->GetHint("CIccCreateAdjustPCSXformHint"); | ||||
1413 | if (pHint) { | ||||
1414 | CIccCreateAdjustPCSXformHint *pAdjustPCSHint = (CIccCreateAdjustPCSXformHint*)pHint; | ||||
1415 | m_pAdjustPCS = pAdjustPCSHint->GetNewAdjustPCSXform(); | ||||
1416 | } | ||||
1417 | |||||
1418 | pHint = pHintManager->GetHint("CIccCreateCmmEnvVarXformHint"); | ||||
1419 | if (pHint) { | ||||
1420 | CIccCreateCmmEnvVarXformHint *pCmmEnvVarHint = (CIccCreateCmmEnvVarXformHint*)pHint; | ||||
1421 | m_pCmmEnvVarLookup = pCmmEnvVarHint->GetNewCmmEnvVarLookup(); | ||||
1422 | } | ||||
1423 | |||||
1424 | pHint = pHintManager->GetHint("CIccLuminanceMatchingHint"); | ||||
1425 | if (pHint) { | ||||
1426 | m_bLuminanceMatching = true; | ||||
1427 | } | ||||
1428 | } | ||||
1429 | } | ||||
1430 | |||||
1431 | /** | ||||
1432 | ************************************************************************** | ||||
1433 | * Name: CIccXform::Create | ||||
1434 | * | ||||
1435 | * Purpose: | ||||
1436 | * This is a static Creation function that creates derived CIccXform objects and | ||||
1437 | * initializes them. | ||||
1438 | * | ||||
1439 | * Args: | ||||
1440 | * Profile = reference to a CIccProfile object that will be used to create the transform. | ||||
1441 | * A copy of the CIccProfile object will be created and passed to the pointer based Create(). | ||||
1442 | * The copied object will be destroyed when the returned CIccXform object is destroyed. | ||||
1443 | * bInput = flag to indicate whether to use the input or output side of the profile, | ||||
1444 | * nIntent = the rendering intent to apply to the profile, | ||||
1445 | * nInterp = the interpolation algorithm to use for N-D luts. | ||||
1446 | * nLutType = selection of which transform lut to use | ||||
1447 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | ||||
1448 | * pHint = pointer to object passed to CIccXform creation functionality | ||||
1449 | * | ||||
1450 | * Return: | ||||
1451 | * A suitable pXform object | ||||
1452 | ************************************************************************** | ||||
1453 | */ | ||||
1454 | CIccXform *CIccXform::Create(CIccProfile &Profile, | ||||
1455 | bool bInput/* =true */, | ||||
1456 | icRenderingIntent nIntent/* =icUnknownIntent */, | ||||
1457 | icXformInterp nInterp/* =icInterpLinear */, | ||||
1458 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
1459 | icXformLutType nLutType/* =icXformLutColor */, | ||||
1460 | bool bUseD2BxB2DxTags/* =true */, | ||||
1461 | CIccCreateXformHintManager *pHintManager/* =NULL */) | ||||
1462 | { | ||||
1463 | CIccProfile *pProfile = new CIccProfile(Profile); | ||||
1464 | CIccXform *pXform = Create(pProfile, bInput, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | ||||
1465 | |||||
1466 | if (!pXform) | ||||
1467 | delete pProfile; | ||||
1468 | |||||
1469 | return pXform; | ||||
1470 | } | ||||
1471 | |||||
1472 | |||||
1473 | /** | ||||
1474 | ************************************************************************** | ||||
1475 | * Name: CIccXform::Begin | ||||
1476 | * | ||||
1477 | * Purpose: | ||||
1478 | * This function will be called before the xform is applied. Derived objects | ||||
1479 | * should also call this base class function to initialize for Absolute Colorimetric | ||||
1480 | * Intent handling which is performed through the use of the CheckSrcAbs and | ||||
1481 | * CheckDstAbs functions. | ||||
1482 | ************************************************************************** | ||||
1483 | */ | ||||
1484 | icStatusCMM CIccXform::Begin() | ||||
1485 | { | ||||
1486 | IIccProfileConnectionConditions *pCond = GetConnectionConditions(); | ||||
1487 | |||||
1488 | icFloatNumber mediaXYZ[3]; | ||||
1489 | icFloatNumber illumXYZ[3]; | ||||
1490 | |||||
1491 | if (m_nIntent==icAbsoluteColorimetric) { | ||||
1492 | if (pCond) { | ||||
1493 | pCond->getMediaWhiteXYZ(mediaXYZ); | ||||
1494 | |||||
1495 | m_MediaXYZ.X = icFtoF16(mediaXYZ[0]); | ||||
1496 | m_MediaXYZ.Y = icFtoF16(mediaXYZ[1]); | ||||
1497 | m_MediaXYZ.Z = icFtoF16(mediaXYZ[2]); | ||||
1498 | } | ||||
1499 | else { | ||||
1500 | CIccTag *pTag = m_pProfile->FindTag(icSigMediaWhitePointTag); | ||||
1501 | |||||
1502 | if (!pTag || pTag->GetType()!=icSigXYZType) | ||||
1503 | return icCmmStatInvalidProfile; | ||||
1504 | |||||
1505 | CIccTagXYZ *pXyzTag = (CIccTagXYZ*)pTag; | ||||
1506 | |||||
1507 | m_MediaXYZ = (*pXyzTag)[0]; | ||||
1508 | mediaXYZ[0] = icFtoD(m_MediaXYZ.X); | ||||
1509 | mediaXYZ[1] = icFtoD(m_MediaXYZ.Y); | ||||
1510 | mediaXYZ[2] = icFtoD(m_MediaXYZ.Z); | ||||
1511 | } | ||||
1512 | } | ||||
1513 | |||||
1514 | icXYZNumber illXYZ; | ||||
1515 | if (pCond) { | ||||
1516 | pCond->getNormIlluminantXYZ(illumXYZ); | ||||
1517 | illXYZ.X = icDtoF(illumXYZ[0]); | ||||
1518 | illXYZ.Y = icDtoF(illumXYZ[1]); | ||||
1519 | illXYZ.Z = icDtoF(illumXYZ[2]); | ||||
1520 | } | ||||
1521 | else { | ||||
1522 | illXYZ = m_pProfile->m_Header.illuminant; | ||||
1523 | illumXYZ[0] = icFtoD(illXYZ.X); | ||||
1524 | illumXYZ[1] = icFtoD(illXYZ.Y); | ||||
1525 | illumXYZ[2] = icFtoD(illXYZ.Z); | ||||
1526 | } | ||||
1527 | |||||
1528 | // set up for any needed PCS adjustment | ||||
1529 | if (m_nIntent == icAbsoluteColorimetric && | ||||
1530 | (m_MediaXYZ.X != illXYZ.X || | ||||
1531 | m_MediaXYZ.Y != illXYZ.Y || | ||||
1532 | m_MediaXYZ.Z != illXYZ.Z)) { | ||||
1533 | |||||
1534 | icColorSpaceSignature Space = m_pProfile->m_Header.pcs; | ||||
1535 | |||||
1536 | if (IsSpacePCS(Space)(((Space)==icSigXYZData || (Space)==icSigLabData) || IsSpaceSpectralPCS (Space))) { | ||||
1537 | m_bAdjustPCS = true; // turn ON PCS adjustment | ||||
1538 | |||||
1539 | // scale factors depend upon media white point | ||||
1540 | // set up for input transform | ||||
1541 | if (!m_bInput) { | ||||
1542 | m_PCSScale[0] = illumXYZ[0] / mediaXYZ[0]; | ||||
1543 | m_PCSScale[1] = illumXYZ[1] / mediaXYZ[1]; | ||||
1544 | m_PCSScale[2] = illumXYZ[2] / mediaXYZ[2]; | ||||
1545 | } | ||||
1546 | else { | ||||
1547 | m_PCSScale[0] = mediaXYZ[0] / illumXYZ[0]; | ||||
1548 | m_PCSScale[1] = mediaXYZ[1] / illumXYZ[1]; | ||||
1549 | m_PCSScale[2] = mediaXYZ[2] / illumXYZ[2]; | ||||
1550 | |||||
1551 | } | ||||
1552 | |||||
1553 | m_PCSOffset[0] = 0.0; | ||||
1554 | m_PCSOffset[1] = 0.0; | ||||
1555 | m_PCSOffset[2] = 0.0; | ||||
1556 | } | ||||
1557 | } | ||||
1558 | else if (m_nIntent == icPerceptual && (IsVersion2() || !HasPerceptualHandling())) { | ||||
1559 | icColorSpaceSignature Space = m_pProfile->m_Header.pcs; | ||||
1560 | |||||
1561 | if (IsSpacePCS(Space)(((Space)==icSigXYZData || (Space)==icSigLabData) || IsSpaceSpectralPCS (Space)) && m_pProfile->m_Header.deviceClass!=icSigAbstractClass) { | ||||
1562 | m_bAdjustPCS = true; // turn ON PCS adjustment | ||||
1563 | |||||
1564 | // set up for input transform, which needs version 2 black point to version 4 | ||||
1565 | m_PCSScale[0] = (icFloatNumber) (1.0 - icPerceptualRefBlackX0.00336 / icPerceptualRefWhiteX0.9642); // scale factors | ||||
1566 | m_PCSScale[1] = (icFloatNumber) (1.0 - icPerceptualRefBlackY0.0034731 / icPerceptualRefWhiteY1.0000); | ||||
1567 | m_PCSScale[2] = (icFloatNumber) (1.0 - icPerceptualRefBlackZ0.00287 / icPerceptualRefWhiteZ0.8249); | ||||
1568 | |||||
1569 | m_PCSOffset[0] = (icFloatNumber) (icPerceptualRefBlackX0.00336 * 32768.0 / 65535.0); // offset factors | ||||
1570 | m_PCSOffset[1] = (icFloatNumber) (icPerceptualRefBlackY0.0034731 * 32768.0 / 65535.0); | ||||
1571 | m_PCSOffset[2] = (icFloatNumber) (icPerceptualRefBlackZ0.00287 * 32768.0 / 65535.0); | ||||
1572 | |||||
1573 | if (!m_bInput) { // output transform must convert version 4 black point to version 2 | ||||
1574 | m_PCSScale[0] = (icFloatNumber) 1.0 / m_PCSScale[0]; // invert scale factors | ||||
1575 | m_PCSScale[1] = (icFloatNumber) 1.0 / m_PCSScale[1]; | ||||
1576 | m_PCSScale[2] = (icFloatNumber) 1.0 / m_PCSScale[2]; | ||||
1577 | |||||
1578 | m_PCSOffset[0] = - m_PCSOffset[0] * m_PCSScale[0]; // negate offset factors | ||||
1579 | m_PCSOffset[1] = - m_PCSOffset[1] * m_PCSScale[1]; | ||||
1580 | m_PCSOffset[2] = - m_PCSOffset[2] * m_PCSScale[2]; | ||||
1581 | } | ||||
1582 | } | ||||
1583 | } | ||||
1584 | |||||
1585 | |||||
1586 | if (m_pAdjustPCS) { | ||||
1587 | CIccProfile ProfileCopy(*m_pProfile); | ||||
1588 | |||||
1589 | // need to read in all the tags, so that a copy of the profile can be made | ||||
1590 | if (!ProfileCopy.ReadTags(m_pProfile)) { | ||||
1591 | return icCmmStatInvalidProfile; | ||||
1592 | } | ||||
1593 | |||||
1594 | if (!m_pAdjustPCS->CalcFactors(&ProfileCopy, this, m_PCSScale, m_PCSOffset)) { | ||||
1595 | return icCmmStatIncorrectApply; | ||||
1596 | } | ||||
1597 | |||||
1598 | m_bAdjustPCS = true; | ||||
1599 | delete m_pAdjustPCS; | ||||
1600 | m_pAdjustPCS = NULL__null; | ||||
1601 | } | ||||
1602 | |||||
1603 | return icCmmStatOk; | ||||
1604 | } | ||||
1605 | |||||
1606 | /** | ||||
1607 | ************************************************************************** | ||||
1608 | * Name: CIccXform::GetNewApply | ||||
1609 | * | ||||
1610 | * Purpose: | ||||
1611 | * This Factory function allocates data specific for the application of the xform. | ||||
1612 | * This allows multiple threads to simultaneously use the same xform. | ||||
1613 | ************************************************************************** | ||||
1614 | */ | ||||
1615 | CIccApplyXform *CIccXform::GetNewApply(icStatusCMM &status) | ||||
1616 | { | ||||
1617 | CIccApplyXform *rv = new CIccApplyXform(this); | ||||
1618 | |||||
1619 | if (!rv) { | ||||
1620 | status = icCmmStatAllocErr; | ||||
1621 | return NULL__null; | ||||
1622 | } | ||||
1623 | |||||
1624 | status = icCmmStatOk; | ||||
1625 | return rv; | ||||
1626 | } | ||||
1627 | |||||
1628 | /** | ||||
1629 | ************************************************************************** | ||||
1630 | * Name: CIccXform::AdjustPCS | ||||
1631 | * | ||||
1632 | * Purpose: | ||||
1633 | * This function will take care of any PCS adjustments | ||||
1634 | * needed by the xform (the PCS is always version 4 relative). | ||||
1635 | * | ||||
1636 | * Args: | ||||
1637 | * DstPixel = Destination pixel where the result is stored, | ||||
1638 | * SrcPixel = Source pixel which is to be applied. | ||||
1639 | * | ||||
1640 | ************************************************************************** | ||||
1641 | */ | ||||
1642 | void CIccXform::AdjustPCS(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | ||||
1643 | { | ||||
1644 | icColorSpaceSignature Space = m_pProfile->m_Header.pcs; | ||||
1645 | |||||
1646 | if (Space==icSigLabData) { | ||||
1647 | if (UseLegacyPCS()) { | ||||
1648 | CIccPCS::Lab2ToXyz(DstPixel, SrcPixel, true); | ||||
1649 | } | ||||
1650 | else { | ||||
1651 | CIccPCS::LabToXyz(DstPixel, SrcPixel, true); | ||||
1652 | } | ||||
1653 | } | ||||
1654 | else { | ||||
1655 | DstPixel[0] = SrcPixel[0]; | ||||
1656 | DstPixel[1] = SrcPixel[1]; | ||||
1657 | DstPixel[2] = SrcPixel[2]; | ||||
1658 | } | ||||
1659 | |||||
1660 | DstPixel[0] = DstPixel[0] * m_PCSScale[0] + m_PCSOffset[0]; | ||||
1661 | DstPixel[1] = DstPixel[1] * m_PCSScale[1] + m_PCSOffset[1]; | ||||
1662 | DstPixel[2] = DstPixel[2] * m_PCSScale[2] + m_PCSOffset[2]; | ||||
1663 | |||||
1664 | if (Space==icSigLabData) { | ||||
1665 | if (UseLegacyPCS()) { | ||||
1666 | |||||
1667 | CIccPCS::XyzToLab2(DstPixel, DstPixel, true); | ||||
1668 | } | ||||
1669 | else { | ||||
1670 | CIccPCS::XyzToLab(DstPixel, DstPixel, true); | ||||
1671 | } | ||||
1672 | } | ||||
1673 | #ifndef SAMPLEICC_NOCLIPLABTOXYZ | ||||
1674 | else { | ||||
1675 | DstPixel[0] = CIccPCS::NegClip(DstPixel[0]); | ||||
1676 | DstPixel[1] = CIccPCS::NegClip(DstPixel[1]); | ||||
1677 | DstPixel[2] = CIccPCS::NegClip(DstPixel[2]); | ||||
1678 | } | ||||
1679 | #endif | ||||
1680 | } | ||||
1681 | |||||
1682 | /** | ||||
1683 | ************************************************************************** | ||||
1684 | * Name: CIccXform::CheckSrcAbs | ||||
1685 | * | ||||
1686 | * Purpose: | ||||
1687 | * This function will be called by a derived CIccXform object's Apply() function | ||||
1688 | * BEFORE the actual xform is performed to take care of Absolute to Relative | ||||
1689 | * adjustments needed by the xform (IE the PCS is always version 4 relative). | ||||
1690 | * | ||||
1691 | * Args: | ||||
1692 | * Pixel = src pixel data (will not be modified) | ||||
1693 | * | ||||
1694 | * Return: | ||||
1695 | * returns Pixel or adjusted pixel data. | ||||
1696 | ************************************************************************** | ||||
1697 | */ | ||||
1698 | const icFloatNumber *CIccXform::CheckSrcAbs(CIccApplyXform *pApply, const icFloatNumber *Pixel) const | ||||
1699 | { | ||||
1700 | if (m_bAdjustPCS && !m_bInput && m_bSrcPcsConversion) { | ||||
1701 | icFloatNumber *pAbsLab = pApply->m_AbsLab; | ||||
1702 | AdjustPCS(pAbsLab, Pixel); | ||||
1703 | return pAbsLab; | ||||
1704 | } | ||||
1705 | |||||
1706 | return Pixel; | ||||
1707 | } | ||||
1708 | |||||
1709 | /** | ||||
1710 | ************************************************************************** | ||||
1711 | * Name: CIccXform::CheckDstAbs | ||||
1712 | * | ||||
1713 | * Purpose: | ||||
1714 | * This function will be called by a derived CIccXform object's Apply() function | ||||
1715 | * AFTER the actual xform is performed to take care of Absolute to Relative | ||||
1716 | * adjustments needed by the xform (IE the PCS is always version 4 relative). | ||||
1717 | * | ||||
1718 | * Args: | ||||
1719 | * Pixel = source pixel data which will be modified | ||||
1720 | * | ||||
1721 | ************************************************************************** | ||||
1722 | */ | ||||
1723 | void CIccXform::CheckDstAbs(icFloatNumber *Pixel) const | ||||
1724 | { | ||||
1725 | if (m_bAdjustPCS && m_bInput && m_bDstPcsConversion) { | ||||
1726 | AdjustPCS(Pixel, Pixel); | ||||
1727 | } | ||||
1728 | } | ||||
1729 | |||||
1730 | /** | ||||
1731 | ************************************************************************** | ||||
1732 | * Name: CIccXform::GetSrcSpace | ||||
1733 | * | ||||
1734 | * Purpose: | ||||
1735 | * Return the color space that is input to the transform. | ||||
1736 | * If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid | ||||
1737 | * confusion with PCS encoding of these spaces. Device encoding of XYZ | ||||
1738 | * and Lab spaces left to the device. | ||||
1739 | ************************************************************************** | ||||
1740 | */ | ||||
1741 | icColorSpaceSignature CIccXform::GetSrcSpace() const | ||||
1742 | { | ||||
1743 | icColorSpaceSignature rv; | ||||
1744 | icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass; | ||||
1745 | |||||
1746 | if (m_bInput) { | ||||
1747 | rv = m_pProfile->m_Header.colorSpace; | ||||
1748 | |||||
1749 | if (deviceClass != icSigAbstractClass) { | ||||
1750 | //convert signature to device colorspace signature (avoid confusion about encoding). | ||||
1751 | if (rv==icSigXYZData) { | ||||
1752 | rv = icSigDevXYZData((icColorSpaceSignature) 0x6458595A); | ||||
1753 | } | ||||
1754 | else if (rv==icSigLabData) { | ||||
1755 | rv = icSigDevLabData((icColorSpaceSignature) 0x644C6162); | ||||
1756 | } | ||||
1757 | } | ||||
1758 | } | ||||
1759 | else if (!m_bUseSpectralPCS || !m_pProfile->m_Header.spectralPCS) { | ||||
1760 | rv = m_pProfile->m_Header.pcs; | ||||
1761 | } | ||||
1762 | else { | ||||
1763 | rv = icGetColorSpaceType(m_pProfile->m_Header.spectralPCS)((icColorSpaceSignature)(((icUInt32Number)m_pProfile->m_Header .spectralPCS)&0xffff0000)); | ||||
1764 | } | ||||
1765 | |||||
1766 | return rv; | ||||
1767 | } | ||||
1768 | |||||
1769 | /** | ||||
1770 | ************************************************************************** | ||||
1771 | * Name: CIccXform::GetNumSrcSamples | ||||
1772 | * | ||||
1773 | * Purpose: | ||||
1774 | * Return the color space that is input to the transform. | ||||
1775 | * If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid | ||||
1776 | * confusion with PCS encoding of these spaces. Device encoding of XYZ | ||||
1777 | * and Lab spaces left to the device. | ||||
1778 | ************************************************************************** | ||||
1779 | */ | ||||
1780 | icUInt16Number CIccXform::GetNumSrcSamples() const | ||||
1781 | { | ||||
1782 | icUInt16Number rv; | ||||
1783 | |||||
1784 | if (m_nMCS==icFromMCS) { | ||||
1785 | rv = (icUInt16Number)icGetSpaceSamples((icColorSpaceSignature)m_pProfile->m_Header.mcs); | ||||
1786 | } | ||||
1787 | else if (m_bInput) { | ||||
1788 | rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.colorSpace); | ||||
1789 | } | ||||
1790 | else if (!m_bUseSpectralPCS || !m_pProfile->m_Header.spectralPCS) { | ||||
1791 | rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.pcs); | ||||
1792 | } | ||||
1793 | else { | ||||
1794 | rv = (icUInt16Number)icGetSpectralSpaceSamples(&m_pProfile->m_Header); | ||||
1795 | } | ||||
1796 | |||||
1797 | return rv; | ||||
1798 | } | ||||
1799 | |||||
1800 | /** | ||||
1801 | ************************************************************************** | ||||
1802 | * Name: CIccXform::GetDstSpace | ||||
1803 | * | ||||
1804 | * Purpose: | ||||
1805 | * Return the color space that is output by the transform. | ||||
1806 | * If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid | ||||
1807 | * confusion with PCS encoding of these spaces. Device encoding of XYZ | ||||
1808 | * and Lab spaces left to the device. | ||||
1809 | ************************************************************************** | ||||
1810 | */ | ||||
1811 | icColorSpaceSignature CIccXform::GetDstSpace() const | ||||
1812 | { | ||||
1813 | icColorSpaceSignature rv; | ||||
1814 | icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass; | ||||
1815 | |||||
1816 | if (m_nMCS==icToMCS) { | ||||
1817 | rv = (icColorSpaceSignature)m_pProfile->m_Header.mcs; | ||||
1818 | } | ||||
1819 | else if (m_bInput) { | ||||
1820 | if (m_bUseSpectralPCS && m_pProfile->m_Header.spectralPCS) | ||||
1821 | rv = icGetColorSpaceType(m_pProfile->m_Header.spectralPCS)((icColorSpaceSignature)(((icUInt32Number)m_pProfile->m_Header .spectralPCS)&0xffff0000)); | ||||
1822 | else | ||||
1823 | rv = m_pProfile->m_Header.pcs; | ||||
1824 | } | ||||
1825 | else { | ||||
1826 | rv = m_pProfile->m_Header.colorSpace; | ||||
1827 | |||||
1828 | //convert signature to device colorspace signature (avoid confusion about encoding). | ||||
1829 | if (deviceClass != icSigAbstractClass) { | ||||
1830 | if (rv==icSigXYZData) { | ||||
1831 | rv = icSigDevXYZData((icColorSpaceSignature) 0x6458595A); | ||||
1832 | } | ||||
1833 | else if (rv==icSigLabData) { | ||||
1834 | rv = icSigDevLabData((icColorSpaceSignature) 0x644C6162); | ||||
1835 | } | ||||
1836 | } | ||||
1837 | } | ||||
1838 | |||||
1839 | return rv; | ||||
1840 | } | ||||
1841 | |||||
1842 | /** | ||||
1843 | ************************************************************************** | ||||
1844 | * Name: CIccXform::GetNumDstSamples | ||||
1845 | * | ||||
1846 | * Purpose: | ||||
1847 | * Return the color space that is input to the transform. | ||||
1848 | * If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid | ||||
1849 | * confusion with PCS encoding of these spaces. Device encoding of XYZ | ||||
1850 | * and Lab spaces left to the device. | ||||
1851 | ************************************************************************** | ||||
1852 | */ | ||||
1853 | icUInt16Number CIccXform::GetNumDstSamples() const | ||||
1854 | { | ||||
1855 | icUInt16Number rv; | ||||
1856 | |||||
1857 | if (m_nMCS==icToMCS) { | ||||
1858 | rv = (icUInt16Number)icGetSpaceSamples((icColorSpaceSignature)m_pProfile->m_Header.mcs); | ||||
1859 | } | ||||
1860 | else if (!m_bInput) { | ||||
1861 | rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.colorSpace); | ||||
1862 | } | ||||
1863 | else if (!m_bUseSpectralPCS || !m_pProfile->m_Header.spectralPCS) { | ||||
1864 | rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.pcs); | ||||
1865 | } | ||||
1866 | else { | ||||
1867 | rv = (icUInt16Number)icGetSpectralSpaceSamples(&m_pProfile->m_Header); | ||||
1868 | } | ||||
1869 | |||||
1870 | return rv; | ||||
1871 | } | ||||
1872 | |||||
1873 | |||||
1874 | /** | ||||
1875 | ************************************************************************** | ||||
1876 | * Name: CIccApplyXform::CIccApplyXform | ||||
1877 | * | ||||
1878 | * Purpose: | ||||
1879 | * Constructor | ||||
1880 | ************************************************************************** | ||||
1881 | */ | ||||
1882 | CIccApplyXform::CIccApplyXform(CIccXform *pXform) | ||||
1883 | { | ||||
1884 | m_pXform = pXform; | ||||
1885 | } | ||||
1886 | |||||
1887 | /** | ||||
1888 | ************************************************************************** | ||||
1889 | * Name: CIccApplyXform::CIccApplyXform | ||||
1890 | * | ||||
1891 | * Purpose: | ||||
1892 | * Destructor | ||||
1893 | ************************************************************************** | ||||
1894 | */ | ||||
1895 | CIccApplyXform::~CIccApplyXform() | ||||
1896 | { | ||||
1897 | } | ||||
1898 | |||||
1899 | |||||
1900 | /** | ||||
1901 | ************************************************************************** | ||||
1902 | * Name: CIccApplyPcsXform::CIccApplyPcsXform | ||||
1903 | * | ||||
1904 | * Purpose: | ||||
1905 | * Constructor | ||||
1906 | ************************************************************************** | ||||
1907 | */ | ||||
1908 | CIccApplyPcsXform::CIccApplyPcsXform(CIccXform *pXform) : CIccApplyXform(pXform) | ||||
1909 | { | ||||
1910 | m_list = new CIccApplyPcsStepList(); | ||||
1911 | m_temp1 = NULL__null; | ||||
1912 | m_temp2 = NULL__null; | ||||
1913 | } | ||||
1914 | |||||
1915 | /** | ||||
1916 | ************************************************************************** | ||||
1917 | * Name: CIccApplyPcsXform::~CIccApplyPcsXform | ||||
1918 | * | ||||
1919 | * Purpose: | ||||
1920 | * Destructor | ||||
1921 | ************************************************************************** | ||||
1922 | */ | ||||
1923 | CIccApplyPcsXform::~CIccApplyPcsXform() | ||||
1924 | { | ||||
1925 | |||||
1926 | if (m_list
| ||||
1927 | CIccApplyPcsStepList::iterator i; | ||||
1928 | for (i=m_list->begin(); i!=m_list->end(); i++) { | ||||
1929 | if (i->ptr) | ||||
1930 | delete i->ptr; | ||||
1931 | } | ||||
1932 | |||||
1933 | delete m_list; | ||||
1934 | } | ||||
1935 | |||||
1936 | if (m_temp1
| ||||
1937 | delete m_temp1; | ||||
| |||||
1938 | if (m_temp2) | ||||
1939 | delete m_temp2; | ||||
1940 | } | ||||
1941 | |||||
1942 | /** | ||||
1943 | ************************************************************************** | ||||
1944 | * Name: CIccApplyPcsXform::Init | ||||
1945 | * | ||||
1946 | * Purpose: | ||||
1947 | * Initialize temporary variables used during pcs processing | ||||
1948 | ************************************************************************** | ||||
1949 | */ | ||||
1950 | bool CIccApplyPcsXform::Init() | ||||
1951 | { | ||||
1952 | CIccPcsXform *pXform = (CIccPcsXform*)m_pXform; | ||||
1953 | icUInt16Number nChan = pXform->MaxChannels(); | ||||
1954 | |||||
1955 | if (nChan) { | ||||
1956 | m_temp1 = new icFloatNumber[nChan]; | ||||
1957 | m_temp2 = new icFloatNumber[nChan]; | ||||
1958 | } | ||||
1959 | |||||
1960 | return m_temp1
| ||||
1961 | } | ||||
1962 | |||||
1963 | |||||
1964 | void CIccApplyPcsXform::AppendApplyStep(CIccApplyPcsStep *pStep) | ||||
1965 | { | ||||
1966 | CIccApplyPcsStepPtr ptr; | ||||
1967 | |||||
1968 | if (pStep && m_list) { | ||||
1969 | ptr.ptr = pStep; | ||||
1970 | m_list->push_back(ptr); | ||||
1971 | } | ||||
1972 | } | ||||
1973 | |||||
1974 | |||||
1975 | /** | ||||
1976 | ************************************************************************** | ||||
1977 | * Name: CIccPcsXform::CIccPcsXform | ||||
1978 | * | ||||
1979 | * Purpose: | ||||
1980 | * Constructor | ||||
1981 | ************************************************************************** | ||||
1982 | */ | ||||
1983 | CIccPcsXform::CIccPcsXform() | ||||
1984 | { | ||||
1985 | m_list = new CIccPcsStepList(); | ||||
1986 | |||||
1987 | m_srcSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | ||||
1988 | m_nSrcSamples = 0; | ||||
1989 | |||||
1990 | m_dstSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | ||||
1991 | m_nDstSamples = 0; | ||||
1992 | } | ||||
1993 | |||||
1994 | /** | ||||
1995 | ************************************************************************** | ||||
1996 | * Name: CIccPcsXform::~CIccPcsXform | ||||
1997 | * | ||||
1998 | * Purpose: | ||||
1999 | * Destructor | ||||
2000 | ************************************************************************** | ||||
2001 | */ | ||||
2002 | CIccPcsXform::~CIccPcsXform() | ||||
2003 | { | ||||
2004 | if (m_list) { | ||||
2005 | CIccPcsStepList::iterator step; | ||||
2006 | for (step=m_list->begin(); step!=m_list->end(); step++) { | ||||
2007 | if (step->ptr) { | ||||
2008 | delete step->ptr; | ||||
2009 | step->ptr = NULL__null; | ||||
2010 | } | ||||
2011 | } | ||||
2012 | delete m_list; | ||||
2013 | } | ||||
2014 | } | ||||
2015 | |||||
2016 | /** | ||||
2017 | ************************************************************************** | ||||
2018 | * Name: CIccPcsXform::Connect | ||||
2019 | * | ||||
2020 | * Purpose: | ||||
2021 | * Insert PCS transform operations to perform PCS processing between | ||||
2022 | * pFromXform and pToXform | ||||
2023 | ************************************************************************** | ||||
2024 | */ | ||||
2025 | icStatusCMM CIccPcsXform::Connect(CIccXform *pFromXform, CIccXform *pToXform) | ||||
2026 | { | ||||
2027 | icStatusCMM stat; | ||||
2028 | |||||
2029 | if (!pFromXform || !pToXform) | ||||
| |||||
2030 | return icCmmStatBadXform; | ||||
2031 | |||||
2032 | if (pFromXform->IsMCS() && pToXform->IsMCS()) { | ||||
2033 | CIccProfile *pFromProfile = pFromXform->GetProfilePtr(); | ||||
2034 | CIccProfile *pToProfile = pToXform->GetProfilePtr(); | ||||
2035 | |||||
2036 | if (!pFromProfile || !pToProfile) { | ||||
2037 | return icCmmStatBadSpaceLink; | ||||
2038 | } | ||||
2039 | CIccTagArray *pFromChannels = (CIccTagArray*)(pFromProfile->FindTagOfType(icSigMaterialTypeArrayTag, icSigTagArrayType)); | ||||
2040 | CIccTagArray *pToChannels = (CIccTagArray*)(pToProfile->FindTagOfType(icSigMaterialTypeArrayTag, icSigTagArrayType)); | ||||
2041 | |||||
2042 | if (!pFromChannels || !pToChannels) { | ||||
2043 | return icCmmStatBadSpaceLink; | ||||
2044 | } | ||||
2045 | if (pFromChannels->GetTagArrayType()!=icSigUtf8TextTypeArray || | ||||
2046 | pToChannels->GetTagArrayType()!=icSigUtf8TextTypeArray || | ||||
2047 | !pFromChannels->AreAllOfType(icSigUtf8TextType) || | ||||
2048 | !pToChannels->AreAllOfType(icSigUtf8TextType)) { | ||||
2049 | return icCmmStatBadSpaceLink; | ||||
2050 | } | ||||
2051 | |||||
2052 | m_nSrcSamples = pFromXform->GetNumDstSamples(); | ||||
2053 | m_nDstSamples = pToXform->GetNumSrcSamples(); | ||||
2054 | |||||
2055 | if (pFromChannels->GetSize() != m_nSrcSamples || pToChannels->GetSize() != m_nDstSamples) { | ||||
2056 | return icCmmStatBadSpaceLink; | ||||
2057 | } | ||||
2058 | int i, j; | ||||
2059 | |||||
2060 | if (pFromProfile->m_Header.flags&icMCSNeedsSubsetTrue0x00000004) { | ||||
2061 | for (i=0; i<m_nSrcSamples; i++) { | ||||
2062 | const icUChar *szSrcChan = ((CIccTagUtf8Text*)pFromChannels->GetIndex(i))->GetText(); | ||||
2063 | for (j=0; j<m_nDstSamples; j++) { | ||||
2064 | const icUChar *szDstChan = ((CIccTagUtf8Text*)pToChannels->GetIndex(i))->GetText(); | ||||
2065 | if (!icUtf8StrCmp(szSrcChan, szDstChan)strcmp((const char*)szSrcChan, (const char*)szDstChan)) | ||||
2066 | break; | ||||
2067 | } | ||||
2068 | if (j==m_nDstSamples) | ||||
2069 | return icCmmStatBadMCSLink; | ||||
2070 | } | ||||
2071 | } | ||||
2072 | |||||
2073 | if (pToProfile->m_Header.flags&icMCSNeedsSubsetTrue0x00000004) { | ||||
2074 | for (i=0; i<m_nDstSamples; i++) { | ||||
2075 | const icUChar *szDstChan = ((CIccTagUtf8Text*)pToChannels->GetIndex(i))->GetText(); | ||||
2076 | for (j=0; j<m_nSrcSamples; j++) { | ||||
2077 | const icUChar *szSrcChan = ((CIccTagUtf8Text*)pFromChannels->GetIndex(i))->GetText(); | ||||
2078 | if (!icUtf8StrCmp(szSrcChan, szDstChan)strcmp((const char*)szSrcChan, (const char*)szDstChan)) | ||||
2079 | break; | ||||
2080 | } | ||||
2081 | if (j==m_nSrcSamples) | ||||
2082 | return icCmmStatBadMCSLink; | ||||
2083 | } | ||||
2084 | } | ||||
2085 | CIccTag *pTag = pToProfile->FindTag(icSigMaterialDefaultValuesTag); | ||||
2086 | CIccTagNumArray *pDefaults = NULL__null; | ||||
2087 | if (pTag && pTag->IsNumArrayType()) { | ||||
2088 | pDefaults = (CIccTagNumArray *)pTag; | ||||
2089 | } | ||||
2090 | |||||
2091 | pushRouteMcs(pFromChannels, pToChannels, pDefaults); | ||||
2092 | } | ||||
2093 | else { | ||||
2094 | if (!pFromXform->IsInput() || (pToXform->IsInput() && !pToXform->IsAbstract())) { | ||||
2095 | return icCmmStatBadSpaceLink; | ||||
2096 | } | ||||
2097 | |||||
2098 | m_srcSpace = pFromXform->GetDstSpace(); | ||||
2099 | if (IsSpaceSpectralPCS(m_srcSpace)) | ||||
2100 | m_srcSpace = icGetColorSpaceType(m_srcSpace)((icColorSpaceSignature)(((icUInt32Number)m_srcSpace)&0xffff0000 )); | ||||
2101 | |||||
2102 | m_nSrcSamples = pFromXform->GetNumDstSamples(); | ||||
2103 | |||||
2104 | m_dstSpace = pToXform->GetSrcSpace(); | ||||
2105 | if (IsSpaceSpectralPCS(m_dstSpace)) | ||||
2106 | m_dstSpace = icGetColorSpaceType(m_dstSpace)((icColorSpaceSignature)(((icUInt32Number)m_dstSpace)&0xffff0000 )); | ||||
2107 | |||||
2108 | m_nDstSamples = pToXform->GetNumSrcSamples(); | ||||
2109 | |||||
2110 | switch (m_srcSpace) { | ||||
2111 | case icSigLabPcsDataicSigLabData: | ||||
2112 | switch (m_dstSpace) { | ||||
2113 | case icSigLabPcsDataicSigLabData: | ||||
2114 | if (pFromXform->UseLegacyPCS()) | ||||
2115 | pushLab2ToXyz(pFromXform->m_pConnectionConditions); | ||||
2116 | else | ||||
2117 | pushLabToXyz(pFromXform->m_pConnectionConditions); | ||||
2118 | if (pFromXform->NeedAdjustPCS()) { | ||||
2119 | pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]); | ||||
2120 | pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]); | ||||
2121 | } | ||||
2122 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2123 | return stat; | ||||
2124 | } | ||||
2125 | if (pToXform->NeedAdjustPCS()) { | ||||
2126 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2127 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2128 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2129 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2130 | } | ||||
2131 | if (pToXform->UseLegacyPCS()) | ||||
2132 | pushXyzToLab2(pToXform->m_pConnectionConditions); | ||||
2133 | else | ||||
2134 | pushXyzToLab(pToXform->m_pConnectionConditions); | ||||
2135 | break; | ||||
2136 | |||||
2137 | case icSigXYZPcsDataicSigXYZData: | ||||
2138 | if (pFromXform->UseLegacyPCS()) | ||||
2139 | pushLab2ToXyz(pFromXform->m_pConnectionConditions); | ||||
2140 | else | ||||
2141 | pushLabToXyz(pFromXform->m_pConnectionConditions); | ||||
2142 | if (pFromXform->NeedAdjustPCS()) { | ||||
2143 | pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]); | ||||
2144 | pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]); | ||||
2145 | } | ||||
2146 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2147 | return stat; | ||||
2148 | } | ||||
2149 | if (pToXform->NeedAdjustPCS()) { | ||||
2150 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2151 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2152 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2153 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2154 | } | ||||
2155 | pushXyzToXyzIn(); | ||||
2156 | break; | ||||
2157 | |||||
2158 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | ||||
2159 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | ||||
2160 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | ||||
2161 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | ||||
2162 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | ||||
2163 | return icCmmStatUnsupportedPcsLink; | ||||
2164 | } | ||||
2165 | break; | ||||
2166 | |||||
2167 | case icSigXYZPcsDataicSigXYZData: | ||||
2168 | switch (m_dstSpace) { | ||||
2169 | case icSigLabPcsDataicSigLabData: | ||||
2170 | pushXyzInToXyz(); | ||||
2171 | if (pFromXform->NeedAdjustPCS()) { | ||||
2172 | pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]); | ||||
2173 | pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]); | ||||
2174 | } | ||||
2175 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2176 | return stat; | ||||
2177 | } | ||||
2178 | if (pToXform->NeedAdjustPCS()) { | ||||
2179 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2180 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2181 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2182 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2183 | } | ||||
2184 | if (pToXform->UseLegacyPCS()) | ||||
2185 | pushXyzToLab2(pToXform->m_pConnectionConditions); | ||||
2186 | else | ||||
2187 | pushXyzToLab(pToXform->m_pConnectionConditions); | ||||
2188 | break; | ||||
2189 | |||||
2190 | case icSigXYZPcsDataicSigXYZData: | ||||
2191 | pushXyzInToXyz(); | ||||
2192 | if (pFromXform->NeedAdjustPCS()) { | ||||
2193 | pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]); | ||||
2194 | pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]); | ||||
2195 | } | ||||
2196 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2197 | return stat; | ||||
2198 | } | ||||
2199 | if (pToXform->NeedAdjustPCS()) { | ||||
2200 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2201 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2202 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2203 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2204 | } | ||||
2205 | pushXyzToXyzIn(); | ||||
2206 | break; | ||||
2207 | |||||
2208 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | ||||
2209 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | ||||
2210 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | ||||
2211 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | ||||
2212 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | ||||
2213 | return icCmmStatUnsupportedPcsLink; | ||||
2214 | } | ||||
2215 | break; | ||||
2216 | |||||
2217 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | ||||
2218 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | ||||
2219 | switch (m_dstSpace) { | ||||
2220 | case icSigLabPcsDataicSigLabData: | ||||
2221 | pushRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions); | ||||
2222 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2223 | return stat; | ||||
2224 | } | ||||
2225 | if (pToXform->NeedAdjustPCS()) { | ||||
2226 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2227 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2228 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2229 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2230 | } | ||||
2231 | if (pToXform->UseLegacyPCS()) | ||||
2232 | pushXyzToLab2(pToXform->m_pConnectionConditions); | ||||
2233 | else | ||||
2234 | pushXyzToLab(pToXform->m_pConnectionConditions); | ||||
2235 | break; | ||||
2236 | |||||
2237 | case icSigXYZPcsDataicSigXYZData: | ||||
2238 | pushRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions); | ||||
2239 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2240 | return stat; | ||||
2241 | } | ||||
2242 | if (pToXform->NeedAdjustPCS()) { | ||||
2243 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2244 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2245 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2246 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2247 | } | ||||
2248 | pushXyzToXyzIn(); | ||||
2249 | break; | ||||
2250 | |||||
2251 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | ||||
2252 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | ||||
2253 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | ||||
2254 | pToXform->m_pProfile->m_Header.spectralRange); | ||||
2255 | break; | ||||
2256 | |||||
2257 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | ||||
2258 | pushApplyIllum(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions); | ||||
2259 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | ||||
2260 | pToXform->m_pProfile->m_Header.spectralRange); | ||||
2261 | break; | ||||
2262 | |||||
2263 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | ||||
2264 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | ||||
2265 | return icCmmStatUnsupportedPcsLink; | ||||
2266 | } | ||||
2267 | break; | ||||
2268 | |||||
2269 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): { | ||||
2270 | CIccProfile *pFromProfile = pFromXform->GetProfilePtr(); | ||||
2271 | CIccProfile *pToProfile = pToXform->GetProfilePtr(); | ||||
2272 | |||||
2273 | switch (m_dstSpace) { | ||||
2274 | case icSigLabPcsDataicSigLabData: | ||||
2275 | pushRad2Xyz(pFromProfile, pFromXform->m_pConnectionConditions, false); | ||||
2276 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2277 | return stat; | ||||
2278 | } | ||||
2279 | if (pToXform->NeedAdjustPCS()) { | ||||
2280 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2281 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2282 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2283 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2284 | } | ||||
2285 | if (pToXform->UseLegacyPCS()) | ||||
2286 | pushXyzToLab2(pToXform->m_pConnectionConditions); | ||||
2287 | else | ||||
2288 | pushXyzToLab(pToXform->m_pConnectionConditions); | ||||
2289 | break; | ||||
2290 | |||||
2291 | case icSigXYZPcsDataicSigXYZData: | ||||
2292 | pushRad2Xyz(pFromProfile, pFromXform->m_pConnectionConditions, false); | ||||
2293 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2294 | return stat; | ||||
2295 | } | ||||
2296 | if (pToXform->NeedAdjustPCS()) { | ||||
2297 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2298 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2299 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2300 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2301 | } | ||||
2302 | pushXyzToXyzIn(); | ||||
2303 | break; | ||||
2304 | |||||
2305 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | ||||
2306 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | ||||
2307 | return icCmmStatUnsupportedPcsLink; | ||||
2308 | |||||
2309 | |||||
2310 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | ||||
2311 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | ||||
2312 | pToXform->m_pProfile->m_Header.spectralRange); | ||||
2313 | break; | ||||
2314 | |||||
2315 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | ||||
2316 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | ||||
2317 | return icCmmStatUnsupportedPcsLink; | ||||
2318 | } | ||||
2319 | } | ||||
2320 | break; | ||||
2321 | |||||
2322 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | ||||
2323 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | ||||
2324 | switch (m_dstSpace) { | ||||
2325 | case icSigLabPcsDataicSigLabData: | ||||
2326 | pushBiRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions); | ||||
2327 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2328 | return stat; | ||||
2329 | } | ||||
2330 | if (pToXform->NeedAdjustPCS()) { | ||||
2331 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2332 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2333 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2334 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2335 | } | ||||
2336 | if (pToXform->UseLegacyPCS()) | ||||
2337 | pushXyzToLab2(pToXform->m_pConnectionConditions); | ||||
2338 | else | ||||
2339 | pushXyzToLab(pToXform->m_pConnectionConditions); | ||||
2340 | break; | ||||
2341 | |||||
2342 | case icSigXYZPcsDataicSigXYZData: | ||||
2343 | if ((stat=pushBiRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions))!=icCmmStatOk) { | ||||
2344 | return stat; | ||||
2345 | } | ||||
2346 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | ||||
2347 | return stat; | ||||
2348 | } | ||||
2349 | if (pToXform->NeedAdjustPCS()) { | ||||
2350 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | ||||
2351 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | ||||
2352 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | ||||
2353 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | ||||
2354 | } | ||||
2355 | pushXyzToXyzIn(); | ||||
2356 | break; | ||||
2357 | |||||
2358 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | ||||
2359 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | ||||
2360 | if ((stat=pushBiRef2Ref(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions))!=icCmmStatOk) { | ||||
2361 | return stat; | ||||
2362 | } | ||||
2363 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | ||||
2364 | pToXform->m_pProfile->m_Header.spectralRange); | ||||
2365 | break; | ||||
2366 | |||||
2367 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | ||||
2368 | if ((stat=pushBiRef2Rad(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions))!=icCmmStatOk) { | ||||
2369 | return stat; | ||||
2370 | } | ||||
2371 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | ||||
2372 | pToXform->m_pProfile->m_Header.spectralRange); | ||||
2373 | break; | ||||
2374 | |||||
2375 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | ||||
2376 | if (icSameSpectralRange(pFromXform->m_pProfile->m_Header.spectralRange, pToXform->m_pProfile->m_Header.spectralRange) && | ||||
2377 | icSameSpectralRange(pFromXform->m_pProfile->m_Header.biSpectralRange, pToXform->m_pProfile->m_Header.biSpectralRange)) | ||||
2378 | break; | ||||
2379 | else | ||||
2380 | return icCmmStatUnsupportedPcsLink; | ||||
2381 | |||||
2382 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | ||||
2383 | return icCmmStatUnsupportedPcsLink; | ||||
2384 | } | ||||
2385 | break; | ||||
2386 | } | ||||
2387 | } | ||||
2388 | |||||
2389 | icStatusCMM rv = Optimize(); | ||||
2390 | if (rv!=icCmmStatOk) | ||||
2391 | return rv; | ||||
2392 | |||||
2393 | if (m_list->begin()==m_list->end()) | ||||
2394 | return icCmmStatIdentityXform; | ||||
2395 | |||||
2396 | return icCmmStatOk; | ||||
2397 | } | ||||
2398 | |||||
2399 | |||||
2400 | /** | ||||
2401 | ************************************************************************** | ||||
2402 | * Name: CIccPcsXform::Optimize | ||||
2403 | * | ||||
2404 | * Purpose: | ||||
2405 | * Analyzes and concatenates/removes transforms in pcs transformation chain | ||||
2406 | ************************************************************************** | ||||
2407 | */ | ||||
2408 | icStatusCMM CIccPcsXform::Optimize() | ||||
2409 | { | ||||
2410 | if (!m_list) | ||||
2411 | return icCmmStatBadXform; | ||||
2412 | |||||
2413 | CIccPcsStepList steps = *m_list; | ||||
2414 | CIccPcsStepList::iterator next, last; | ||||
2415 | bool done=false; | ||||
2416 | |||||
2417 | #if 0 | ||||
2418 | std::string str; | ||||
2419 | for (next = steps.begin(); next != steps.end(); next++) { | ||||
2420 | next->ptr->dump(str); | ||||
2421 | } | ||||
2422 | printf("PCS_Steps:\r\n%s", str.c_str()); | ||||
2423 | #endif | ||||
2424 | |||||
2425 | while (!done) { | ||||
2426 | CIccPcsStepList newSteps; | ||||
2427 | CIccPcsStepPtr ptr; | ||||
2428 | |||||
2429 | done = true; | ||||
2430 | |||||
2431 | next = steps.begin(); | ||||
2432 | if (next==steps.end()) { | ||||
2433 | *m_list = steps; | ||||
2434 | return icCmmStatIdentityXform; | ||||
2435 | } | ||||
2436 | last = next; | ||||
2437 | next++; | ||||
2438 | |||||
2439 | ptr.ptr = last->ptr; | ||||
2440 | |||||
2441 | for (;next!=steps.end(); next++) { | ||||
2442 | CIccPcsStep *pStep = ptr.ptr->concat(next->ptr); | ||||
2443 | |||||
2444 | if (pStep) { | ||||
2445 | done = false; | ||||
2446 | |||||
2447 | delete ptr.ptr; | ||||
2448 | delete next->ptr; | ||||
2449 | ptr.ptr = pStep; | ||||
2450 | } | ||||
2451 | else { | ||||
2452 | if (!ptr.ptr->isIdentity()) { | ||||
2453 | newSteps.push_back(ptr); | ||||
2454 | } | ||||
2455 | ptr.ptr = next->ptr; | ||||
2456 | } | ||||
2457 | } | ||||
2458 | if (!ptr.ptr->isIdentity()) { | ||||
2459 | newSteps.push_back(ptr); | ||||
2460 | } | ||||
2461 | |||||
2462 | steps = newSteps; | ||||
2463 | |||||
2464 | // for (next=steps.begin(); next!=steps.end(); next++) { | ||||
2465 | // ptr.ptr = next->ptr; | ||||
2466 | // done = true; | ||||
2467 | // } | ||||
2468 | |||||
2469 | } | ||||
2470 | |||||
2471 | if (!steps.empty()) { | ||||
2472 | CIccPcsStepList newSteps; | ||||
2473 | CIccPcsStepPtr ptr; | ||||
2474 | |||||
2475 | for (next=steps.begin(); next != steps.end(); next++) { | ||||
2476 | ptr.ptr = next->ptr->reduce(); | ||||
2477 | if (ptr.ptr != next->ptr) | ||||
2478 | delete next->ptr; | ||||
2479 | newSteps.push_back(ptr); | ||||
2480 | } | ||||
2481 | steps = newSteps; | ||||
2482 | } | ||||
2483 | |||||
2484 | *m_list = steps; | ||||
2485 | |||||
2486 | return icCmmStatOk; | ||||
2487 | } | ||||
2488 | |||||
2489 | |||||
2490 | /** | ||||
2491 | ************************************************************************** | ||||
2492 | * Name: CIccPcsXform::GetNewApply | ||||
2493 | * | ||||
2494 | * Purpose: | ||||
2495 | * Allocates a CIccApplyXform based object that can store local data for | ||||
2496 | * processing (needed by CIccPcsStepMpe). | ||||
2497 | ************************************************************************** | ||||
2498 | */ | ||||
2499 | CIccApplyXform *CIccPcsXform::GetNewApply(icStatusCMM &status) | ||||
2500 | { | ||||
2501 | CIccApplyPcsXform *pNew = new CIccApplyPcsXform(this); | ||||
2502 | |||||
2503 | if (pNew
| ||||
2504 | if (!pNew->Init()) { | ||||
2505 | delete pNew; | ||||
2506 | status = icCmmStatAllocErr; | ||||
2507 | return NULL__null; | ||||
2508 | } | ||||
2509 | } | ||||
2510 | else { | ||||
2511 | status = icCmmStatAllocErr; | ||||
2512 | return NULL__null; | ||||
2513 | } | ||||
2514 | |||||
2515 | CIccPcsStepList::iterator i; | ||||
2516 | CIccApplyPcsStep *pStep; | ||||
2517 | |||||
2518 | for (i=m_list->begin(); i!=m_list->end(); i++) { | ||||
2519 | pStep = i->ptr->GetNewApply(); | ||||
2520 | if (!pStep || status != icCmmStatOk) { | ||||
2521 | delete pNew; | ||||
2522 | return NULL__null; | ||||
2523 | } | ||||
2524 | pNew->AppendApplyStep(pStep); | ||||
2525 | } | ||||
2526 | |||||
2527 | return pNew; | ||||
2528 | } | ||||
2529 | |||||
2530 | |||||
2531 | /** | ||||
2532 | ************************************************************************** | ||||
2533 | * Name: CIccPcsXform::MaxChannels | ||||
2534 | * | ||||
2535 | * Purpose: | ||||
2536 | * Returns the maximum number of channels used by PCS xform steps | ||||
2537 | ************************************************************************** | ||||
2538 | */ | ||||
2539 | icUInt16Number CIccPcsXform::MaxChannels() | ||||
2540 | { | ||||
2541 | icUInt16Number nMax = 0; | ||||
2542 | CIccPcsStepList::const_iterator s = m_list->begin(); | ||||
2543 | if (s==m_list->end()) | ||||
2544 | return nMax; | ||||
2545 | nMax = s->ptr->GetDstChannels(); | ||||
2546 | s++; | ||||
2547 | for (; s!= m_list->end(); s++) { | ||||
2548 | if (s->ptr->GetSrcChannels()>nMax) | ||||
2549 | nMax = s->ptr->GetSrcChannels(); | ||||
2550 | } | ||||
2551 | return nMax; | ||||
2552 | } | ||||
2553 | |||||
2554 | /** | ||||
2555 | ************************************************************************** | ||||
2556 | * Name: CIccPcsXform::pushRouteMcs | ||||
2557 | * | ||||
2558 | * Purpose: | ||||
2559 | * Insert PCS step that routes MCS channel data from one profile to another | ||||
2560 | ************************************************************************** | ||||
2561 | */ | ||||
2562 | void CIccPcsXform::pushRouteMcs(CIccTagArray *pSrcChannels, CIccTagArray *pDstChannels, CIccTagNumArray *pDefaults) | ||||
2563 | { | ||||
2564 | CIccPcsStepPtr ptr; | ||||
2565 | |||||
2566 | ptr.ptr = new CIccPcsStepRouteMcs(pSrcChannels, pDstChannels, pDefaults); | ||||
2567 | m_list->push_back(ptr); | ||||
2568 | } | ||||
2569 | |||||
2570 | |||||
2571 | /** | ||||
2572 | ************************************************************************** | ||||
2573 | * Name: CIccPcsXform::pushLab2ToXyz | ||||
2574 | * | ||||
2575 | * Purpose: | ||||
2576 | * Insert PCS step that converts from V2 Lab internal to actual XYZ | ||||
2577 | ************************************************************************** | ||||
2578 | */ | ||||
2579 | void CIccPcsXform::pushLab2ToXyz( IIccProfileConnectionConditions *pPCC) | ||||
2580 | { | ||||
2581 | icFloatNumber xyzWhite[3]; | ||||
2582 | pPCC->getNormIlluminantXYZ(xyzWhite); | ||||
2583 | |||||
2584 | CIccPcsStepPtr ptr; | ||||
2585 | |||||
2586 | ptr.ptr = new CIccPcsStepLab2ToXYZ(xyzWhite); | ||||
2587 | m_list->push_back(ptr); | ||||
2588 | } | ||||
2589 | |||||
2590 | |||||
2591 | /** | ||||
2592 | ************************************************************************** | ||||
2593 | * Name: CIccPcsXform::pushXyzToLab2 | ||||
2594 | * | ||||
2595 | * Purpose: | ||||
2596 | * Insert PCS step that converts from actual XYZ to V2 Lab internal | ||||
2597 | ************************************************************************** | ||||
2598 | */ | ||||
2599 | void CIccPcsXform::pushXyzToLab2(IIccProfileConnectionConditions *pPCC) | ||||
2600 | { | ||||
2601 | icFloatNumber xyzWhite[3]; | ||||
2602 | pPCC->getNormIlluminantXYZ(xyzWhite); | ||||
2603 | |||||
2604 | CIccPcsStepPtr ptr; | ||||
2605 | |||||
2606 | ptr.ptr = new CIccPcsStepXYZToLab2(xyzWhite); | ||||
2607 | m_list->push_back(ptr); | ||||
2608 | } | ||||
2609 | |||||
2610 | |||||
2611 | /** | ||||
2612 | ************************************************************************** | ||||
2613 | * Name: CIccPcsXform::pushLabToXyz | ||||
2614 | * | ||||
2615 | * Purpose: | ||||
2616 | * Insert PCS step that converts from V4 Lab internal to actual XYZ | ||||
2617 | ************************************************************************** | ||||
2618 | */ | ||||
2619 | void CIccPcsXform::pushLabToXyz(IIccProfileConnectionConditions *pPCC) | ||||
2620 | { | ||||
2621 | icFloatNumber xyzWhite[3]; | ||||
2622 | pPCC->getNormIlluminantXYZ(xyzWhite); | ||||
2623 | |||||
2624 | CIccPcsStepPtr ptr; | ||||
2625 | |||||
2626 | ptr.ptr = new CIccPcsStepLabToXYZ(xyzWhite); | ||||
2627 | m_list->push_back(ptr); | ||||
2628 | } | ||||
2629 | |||||
2630 | |||||
2631 | /** | ||||
2632 | ************************************************************************** | ||||
2633 | * Name: CIccPcsXform::pushXyzToLab | ||||
2634 | * | ||||
2635 | * Purpose: | ||||
2636 | * Insert PCS step that converts from actual XYZ to V4 Lab internal | ||||
2637 | ************************************************************************** | ||||
2638 | */ | ||||
2639 | void CIccPcsXform::pushXyzToLab( IIccProfileConnectionConditions *pPCC) | ||||
2640 | { | ||||
2641 | icFloatNumber xyzWhite[3]; | ||||
2642 | pPCC->getNormIlluminantXYZ(xyzWhite); | ||||
2643 | |||||
2644 | CIccPcsStepPtr ptr; | ||||
2645 | |||||
2646 | ptr.ptr = new CIccPcsStepXYZToLab(xyzWhite); | ||||
2647 | m_list->push_back(ptr); | ||||
2648 | } | ||||
2649 | |||||
2650 | /** | ||||
2651 | ************************************************************************** | ||||
2652 | * Name: CIccPcsXform::pushScale3 | ||||
2653 | * | ||||
2654 | * Purpose: | ||||
2655 | * Insert PCS step that individually scaled three channels (conceptually | ||||
2656 | * equivalent to inserting a 3x3 diagonal matrix). | ||||
2657 | ************************************************************************** | ||||
2658 | */ | ||||
2659 | void CIccPcsXform::pushScale3(icFloatNumber v1, icFloatNumber v2, icFloatNumber v3) | ||||
2660 | { | ||||
2661 | CIccPcsStepScale *scale; | ||||
2662 | CIccPcsStepPtr ptr; | ||||
2663 | |||||
2664 | scale = new CIccPcsStepScale(3); | ||||
2665 | icFloatNumber *data = scale->data(); | ||||
2666 | data[0] = v1; | ||||
2667 | data[1] = v2; | ||||
2668 | data[2] = v3; | ||||
2669 | |||||
2670 | ptr.ptr = scale; | ||||
2671 | m_list->push_back(ptr); | ||||
2672 | } | ||||
2673 | |||||
2674 | /** | ||||
2675 | ************************************************************************** | ||||
2676 | * Name: CIccPcsXform::pushXyzToXyzIn | ||||
2677 | * | ||||
2678 | * Purpose: | ||||
2679 | * Insert PCS step that converts from actual XYZ to internal XYZ | ||||
2680 | ************************************************************************** | ||||
2681 | */ | ||||
2682 | void CIccPcsXform::pushXyzToXyzIn() | ||||
2683 | { | ||||
2684 | icFloatNumber scale = (icFloatNumber) (32768.0 / 65535.0); | ||||
2685 | pushScale3(scale, scale, scale); | ||||
2686 | } | ||||
2687 | |||||
2688 | |||||
2689 | /** | ||||
2690 | ************************************************************************** | ||||
2691 | * Name: CIccPcsXform::pushXyzInToXyz | ||||
2692 | * | ||||
2693 | * Purpose: | ||||
2694 | * Insert PCS step that converts from internal XYZ to actual XYZ | ||||
2695 | ************************************************************************** | ||||
2696 | */ | ||||
2697 | void CIccPcsXform::pushXyzInToXyz() | ||||
2698 | { | ||||
2699 | icFloatNumber scale = (icFloatNumber) (65535.0 / 32768.0); | ||||
2700 | return pushScale3(scale, scale, scale); | ||||
2701 | } | ||||
2702 | |||||
2703 | |||||
2704 | /** | ||||
2705 | ************************************************************************** | ||||
2706 | * Name: CIccPcsXform::pushXyzToXyzLum | ||||
2707 | * | ||||
2708 | * Purpose: | ||||
2709 | * Insert PCS step that converts from normalized XYZ to XYZ Luminance | ||||
2710 | ************************************************************************** | ||||
2711 | */ | ||||
2712 | void CIccPcsXform::pushXyzToXyzLum(IIccProfileConnectionConditions *pPCC) | ||||
2713 | { | ||||
2714 | icFloatNumber XYZLum[3]; | ||||
2715 | pPCC->getLumIlluminantXYZ(&XYZLum[0]); | ||||
2716 | |||||
2717 | icFloatNumber scale = XYZLum[1]; | ||||
2718 | |||||
2719 | return pushScale3(scale, scale, scale); | ||||
2720 | } | ||||
2721 | |||||
2722 | |||||
2723 | /** | ||||
2724 | ************************************************************************** | ||||
2725 | * Name: CIccPcsXform::pushXyzLumToXyz | ||||
2726 | * | ||||
2727 | * Purpose: | ||||
2728 | * Insert PCS step that converts from XYZ Luminance to normalized XYZ | ||||
2729 | ************************************************************************** | ||||
2730 | */ | ||||
2731 | void CIccPcsXform::pushXyzLumToXyz(IIccProfileConnectionConditions *pPCC) | ||||
2732 | { | ||||
2733 | icFloatNumber XYZLum[3]; | ||||
2734 | pPCC->getLumIlluminantXYZ(&XYZLum[0]); | ||||
2735 | |||||
2736 | icFloatNumber scale = 1.0f / XYZLum[1]; | ||||
2737 | |||||
2738 | return pushScale3(scale, scale, scale); | ||||
2739 | } | ||||
2740 | |||||
2741 | |||||
2742 | /** | ||||
2743 | ************************************************************************** | ||||
2744 | * Name: CIccPcsXform::pushXyzToXyzIn | ||||
2745 | * | ||||
2746 | * Purpose: | ||||
2747 | * Insert PCS step that adds an offset to 3 channels. If bConvertIntXyzOffset | ||||
2748 | * is true the the offset is assumed to be in Internal XYZ format and | ||||
2749 | * will be converted to be an actual XYZ offset. | ||||
2750 | ************************************************************************** | ||||
2751 | */ | ||||
2752 | void CIccPcsXform::pushOffset3(icFloatNumber v1, icFloatNumber v2, icFloatNumber v3, bool bConvertIntXyzOffset/*=true*/) | ||||
2753 | { | ||||
2754 | CIccPcsStepOffset *offset; | ||||
2755 | CIccPcsStepPtr ptr; | ||||
2756 | |||||
2757 | offset = new CIccPcsStepOffset(3); | ||||
2758 | icFloatNumber *data = offset->data(); | ||||
2759 | if (bConvertIntXyzOffset) { | ||||
2760 | data[0] = v1*65535.0f/32768.0f; | ||||
2761 | data[1] = v2*65535.0f/32768.0f; | ||||
2762 | data[2] = v3*65535.0f/32768.0f; | ||||
2763 | } | ||||
2764 | else { | ||||
2765 | data[0] = v1; | ||||
2766 | data[1] = v2; | ||||
2767 | data[2] = v3; | ||||
2768 | } | ||||
2769 | |||||
2770 | ptr.ptr = offset; | ||||
2771 | m_list->push_back(ptr); | ||||
2772 | } | ||||
2773 | |||||
2774 | |||||
2775 | /** | ||||
2776 | ************************************************************************** | ||||
2777 | * Name: CIccPcsXform::pushScale | ||||
2778 | * | ||||
2779 | * Purpose: | ||||
2780 | * Insert PCS step that individually n channels (conceptually | ||||
2781 | * equivalent to inserting a nxn diagonal matrix). | ||||
2782 | ************************************************************************** | ||||
2783 | */ | ||||
2784 | void CIccPcsXform::pushScale(icUInt16Number n, const icFloatNumber *vals) | ||||
2785 | { | ||||
2786 | CIccPcsStepScale *scale = new CIccPcsStepScale(n); | ||||
2787 | memcpy(scale->data(), vals, n*sizeof(icFloatNumber)); | ||||
2788 | |||||
2789 | CIccPcsStepPtr ptr; | ||||
2790 | ptr.ptr = scale; | ||||
2791 | m_list->push_back(ptr); | ||||
2792 | } | ||||
2793 | |||||
2794 | |||||
2795 | /** | ||||
2796 | ************************************************************************** | ||||
2797 | * Name: CIccPcsXform::pushMatrix | ||||
2798 | * | ||||
2799 | * Purpose: | ||||
2800 | * Insert PCS step defined by a nRows x nCols matrix with specified vals | ||||
2801 | ************************************************************************** | ||||
2802 | */ | ||||
2803 | void CIccPcsXform::pushMatrix(icUInt16Number nRows, icUInt16Number nCols, const icFloatNumber *vals) | ||||
2804 | { | ||||
2805 | CIccPcsStepMatrix *mtx = new CIccPcsStepMatrix(nRows, nCols); | ||||
2806 | memcpy(mtx->entry(0), vals, nRows*nCols*sizeof(icFloatNumber)); | ||||
2807 | |||||
2808 | CIccPcsStepPtr ptr; | ||||
2809 | ptr.ptr = mtx; | ||||
2810 | m_list->push_back(ptr); | ||||
2811 | } | ||||
2812 | |||||
2813 | |||||
2814 | /** | ||||
2815 | ************************************************************************** | ||||
2816 | * Name: CIccPcsXform::pushXYZConvert | ||||
2817 | * | ||||
2818 | * Purpose: | ||||
2819 | * Insert PCS step that converts from source XYZ colorimetry to dest XYZ | ||||
2820 | * colorimetry accounting for possible changes in illuminant and/or observer. | ||||
2821 | * Luminance matching is also accounted for. | ||||
2822 | ************************************************************************** | ||||
2823 | */ | ||||
2824 | icStatusCMM CIccPcsXform::pushXYZConvert(CIccXform *pFromXform, CIccXform *pToXform) | ||||
2825 | { | ||||
2826 | IIccProfileConnectionConditions *pSrcPcc = pFromXform->GetConnectionConditions(); | ||||
2827 | IIccProfileConnectionConditions *pDstPcc = pToXform->GetConnectionConditions(); | ||||
2828 | |||||
2829 | if (!pSrcPcc || !pDstPcc) | ||||
2830 | return icCmmStatBadConnection; | ||||
2831 | |||||
2832 | //If source and dest observer and illuminant are same then no transform is needed | ||||
2833 | if (pSrcPcc->isEquivalentPcc(*pDstPcc)) { | ||||
2834 | return icCmmStatOk; | ||||
2835 | } | ||||
2836 | |||||
2837 | CIccPcsStepPtr ptr; | ||||
2838 | |||||
2839 | if (!pSrcPcc->isStandardPcc()) { | ||||
2840 | |||||
2841 | CIccTagMultiProcessElement *pMpe = pSrcPcc->getCustomToStandardPcc(); | ||||
2842 | |||||
2843 | if (!pMpe || pMpe->NumInputChannels()!=3 || pMpe->NumOutputChannels()!=3) | ||||
2844 | return icCmmStatBadSpaceLink; | ||||
2845 | |||||
2846 | ptr.ptr = NULL__null; | ||||
2847 | |||||
2848 | //push single matrix element as a CIccPcsStepMatrix so it can be optimized | ||||
2849 | if (pMpe->NumElements()==1) { | ||||
2850 | CIccMultiProcessElement *pElem = pMpe->GetElement(0); | ||||
2851 | if (pElem) { | ||||
2852 | if (pElem->GetType()==icSigMatrixElemType) { | ||||
2853 | CIccMpeMatrix *pMatElem = (CIccMpeMatrix*)pElem; | ||||
2854 | |||||
2855 | icFloatNumber *pMat = pMatElem->GetMatrix(); | ||||
2856 | icFloatNumber *pOffset = pMatElem->GetConstants(); | ||||
2857 | |||||
2858 | if (pMat && (!pOffset || (pOffset[0]==0.0 && pOffset[1]==0.0 && pOffset[2]==0.0))) { | ||||
2859 | CIccPcsStepMatrix *pStepMtx = new CIccPcsStepMatrix(3, 3); | ||||
2860 | |||||
2861 | if (pStepMtx ) { | ||||
2862 | memcpy(pStepMtx->entry(0,0), pMat, 9*sizeof(icFloatNumber)); | ||||
2863 | } | ||||
2864 | ptr.ptr = pStepMtx; | ||||
2865 | } | ||||
2866 | } | ||||
2867 | } | ||||
2868 | } | ||||
2869 | |||||
2870 | if (!ptr.ptr) { | ||||
2871 | CIccPcsStepMpe *pStepMpe = new CIccPcsStepMpe((CIccTagMultiProcessElement*)pMpe->NewCopy()); | ||||
2872 | |||||
2873 | if (!pStepMpe) | ||||
2874 | return icCmmStatAllocErr; | ||||
2875 | |||||
2876 | if (!pStepMpe->Begin()) { | ||||
2877 | delete pStepMpe; | ||||
2878 | return icCmmStatBadConnection; | ||||
2879 | } | ||||
2880 | |||||
2881 | ptr.ptr = pStepMpe; | ||||
2882 | } | ||||
2883 | |||||
2884 | m_list->push_back(ptr); | ||||
2885 | } | ||||
2886 | |||||
2887 | if (!pDstPcc->isStandardPcc()) { | ||||
2888 | |||||
2889 | CIccTagMultiProcessElement *pMpe = pDstPcc->getStandardToCustomPcc(); | ||||
2890 | |||||
2891 | if (!pMpe || pMpe->NumInputChannels()!=3 || pMpe->NumOutputChannels()!=3) | ||||
2892 | return icCmmStatBadSpaceLink; | ||||
2893 | |||||
2894 | ptr.ptr = NULL__null; | ||||
2895 | |||||
2896 | //push single matrix element as a CIccPcsStepMatrix so it can be optimized | ||||
2897 | if (pMpe->NumElements()==1) { | ||||
2898 | CIccMultiProcessElement *pElem = pMpe->GetElement(0); | ||||
2899 | if (pElem) { | ||||
2900 | if (pElem->GetType()==icSigMatrixElemType) { | ||||
2901 | CIccMpeMatrix *pMatElem = (CIccMpeMatrix*)pElem; | ||||
2902 | |||||
2903 | icFloatNumber *pMat = pMatElem->GetMatrix(); | ||||
2904 | icFloatNumber *pOffset = pMatElem->GetConstants(); | ||||
2905 | |||||
2906 | if (pMat && (!pOffset || (pOffset[0]==0.0 && pOffset[1]==0.0 && pOffset[2]==0.0))) { | ||||
2907 | CIccPcsStepMatrix *pStepMtx = new CIccPcsStepMatrix(3, 3); | ||||
2908 | |||||
2909 | if (pStepMtx ) { | ||||
2910 | memcpy(pStepMtx->entry(0,0), pMat, 9*sizeof(icFloatNumber)); | ||||
2911 | } | ||||
2912 | ptr.ptr = pStepMtx; | ||||
2913 | } | ||||
2914 | } | ||||
2915 | } | ||||
2916 | } | ||||
2917 | |||||
2918 | if (!ptr.ptr) { | ||||
2919 | CIccPcsStepMpe *pStepMpe = new CIccPcsStepMpe((CIccTagMultiProcessElement*)pMpe->NewCopy()); | ||||
2920 | |||||
2921 | if (!pStepMpe) | ||||
2922 | return icCmmStatAllocErr; | ||||
2923 | |||||
2924 | if (!pStepMpe->Begin()) { | ||||
2925 | delete pStepMpe; | ||||
2926 | return icCmmStatBadConnection; | ||||
2927 | } | ||||
2928 | |||||
2929 | ptr.ptr = pStepMpe; | ||||
2930 | } | ||||
2931 | |||||
2932 | m_list->push_back(ptr); | ||||
2933 | } | ||||
2934 | |||||
2935 | if (pFromXform->LuminanceMatching()) { | ||||
2936 | pushXyzToXyzLum(pSrcPcc); | ||||
2937 | } | ||||
2938 | if (pToXform->LuminanceMatching()) { | ||||
2939 | pushXyzLumToXyz(pDstPcc); | ||||
2940 | } | ||||
2941 | |||||
2942 | return icCmmStatOk; | ||||
2943 | } | ||||
2944 | |||||
2945 | void CIccPcsXform::pushXYZNormalize(IIccProfileConnectionConditions *pPcc, const icSpectralRange &srcRange, const icSpectralRange &dstRange) | ||||
2946 | { | ||||
2947 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | ||||
2948 | CIccPcsXform tmp; | ||||
2949 | |||||
2950 | icSpectralRange illuminantRange; | ||||
2951 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | ||||
2952 | |||||
2953 | icSpectralRange observerRange; | ||||
2954 | const icFloatNumber *observer = pView->getObserver(observerRange); | ||||
2955 | |||||
2956 | //make sure illuminant goes through identical conversion steps | ||||
2957 | if (!icSameSpectralRange(srcRange, illuminantRange) || !icSameSpectralRange(dstRange, illuminantRange)) { | ||||
2958 | tmp.pushSpecToRange(illuminantRange, srcRange); | ||||
2959 | tmp.pushSpecToRange(srcRange, dstRange); | ||||
2960 | tmp.pushSpecToRange(dstRange, observerRange); | ||||
2961 | } | ||||
2962 | else { | ||||
2963 | tmp.pushSpecToRange(illuminantRange, observerRange); | ||||
2964 | } | ||||
2965 | tmp.pushMatrix(3, observerRange.steps, observer); | ||||
2966 | |||||
2967 | icStatusCMM stat=icCmmStatOk; | ||||
2968 | CIccApplyXform *pApply = tmp.GetNewApply(stat); | ||||
2969 | if (pApply) { | ||||
2970 | icFloatNumber xyz[3], normxyz[3], pccxyz[3]; | ||||
2971 | |||||
2972 | //Get absolute xyz for illuminant and observer | ||||
2973 | tmp.Apply(pApply, xyz, illuminant); | ||||
2974 | |||||
2975 | //calculate normalized XYZ | ||||
2976 | normxyz[0] = xyz[0] / xyz[1]; | ||||
2977 | normxyz[1] = xyz[1] / xyz[1]; | ||||
2978 | normxyz[2] = xyz[2] / xyz[1]; | ||||
2979 | |||||
2980 | //get desired XYZ from pcc (might be slightly different from calculated normxyz) | ||||
2981 | pPcc->getNormIlluminantXYZ(pccxyz); | ||||
2982 | |||||
2983 | #if 1 | ||||
2984 | //push scale factor to normalize XYZ values and correct for difference between calculated and desired XYZ | ||||
2985 | pushScale3(pccxyz[0] / (normxyz[0] * xyz[1]), | ||||
2986 | pccxyz[1] / (normxyz[1] * xyz[1]), | ||||
2987 | pccxyz[2] / (normxyz[2] * xyz[1])); | ||||
2988 | #else | ||||
2989 | pushScale3(1.0f/xyz[1], 1.0f/xyz[1], 1.0f/xyz[1]); | ||||
2990 | #endif | ||||
2991 | |||||
2992 | delete pApply; | ||||
2993 | } | ||||
2994 | } | ||||
2995 | |||||
2996 | /** | ||||
2997 | ************************************************************************** | ||||
2998 | * Name: CIccPcsXform::pushRef2Xyz | ||||
2999 | * | ||||
3000 | * Purpose: | ||||
3001 | * Insert PCS step that convert reflectance to XYZ colorimetry defined by the | ||||
3002 | * observer and illuminant accessed through the Profile Connections Conditions | ||||
3003 | * handle pPcc. | ||||
3004 | ************************************************************************** | ||||
3005 | */ | ||||
3006 | void CIccPcsXform::pushRef2Xyz(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | ||||
3007 | { | ||||
3008 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | ||||
3009 | |||||
3010 | if (pView) { | ||||
3011 | icSpectralRange illuminantRange; | ||||
3012 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | ||||
3013 | |||||
3014 | icSpectralRange observerRange; | ||||
3015 | const icFloatNumber *observer = pView->getObserver(observerRange); | ||||
3016 | |||||
3017 | pushSpecToRange(pProfile->m_Header.spectralRange, illuminantRange); | ||||
3018 | pushScale(illuminantRange.steps, illuminant); | ||||
3019 | pushSpecToRange(illuminantRange, observerRange); | ||||
3020 | pushMatrix(3, observerRange.steps, observer); | ||||
3021 | |||||
3022 | pushXYZNormalize(pPcc, illuminantRange, illuminantRange); | ||||
3023 | } | ||||
3024 | } | ||||
3025 | |||||
3026 | |||||
3027 | /** | ||||
3028 | ************************************************************************** | ||||
3029 | * Name: CIccPcsXform::rangeMap | ||||
3030 | * | ||||
3031 | * Purpose: | ||||
3032 | * This helper function generates a PCS step matrix that can be used to convert | ||||
3033 | * spectral vectors from one spectral range to another using linear interpolation. | ||||
3034 | ************************************************************************** | ||||
3035 | */ | ||||
3036 | CIccPcsStepMatrix *CIccPcsXform::rangeMap(const icSpectralRange &srcRange, const icSpectralRange &dstRange) | ||||
3037 | { | ||||
3038 | if (srcRange.steps != dstRange.steps || | ||||
3039 | srcRange.start != dstRange.start || | ||||
3040 | srcRange.end != dstRange.end) { | ||||
3041 | CIccPcsStepMatrix *mtx = new CIccPcsStepMatrix(dstRange.steps, srcRange.steps); | ||||
3042 | if (!mtx->SetRange(srcRange, dstRange)) | ||||
3043 | { | ||||
3044 | delete mtx; | ||||
3045 | return NULL__null; | ||||
3046 | } | ||||
3047 | return mtx; | ||||
3048 | } | ||||
3049 | |||||
3050 | return NULL__null; | ||||
3051 | } | ||||
3052 | |||||
3053 | |||||
3054 | /** | ||||
3055 | ************************************************************************** | ||||
3056 | * Name: CIccPcsXform::pushSpecToRange | ||||
3057 | * | ||||
3058 | * Purpose: | ||||
3059 | * Insert PCS step that res-samples spectral vector data from a source spectral | ||||
3060 | * range to a destination spectral range. | ||||
3061 | ************************************************************************** | ||||
3062 | */ | ||||
3063 | void CIccPcsXform::pushSpecToRange(const icSpectralRange &srcRange, const icSpectralRange &dstRange) | ||||
3064 | { | ||||
3065 | if (!icSameSpectralRange(srcRange, dstRange)) { | ||||
3066 | CIccPcsStepPtr ptr; | ||||
3067 | ptr.ptr = rangeMap(srcRange, dstRange); | ||||
3068 | |||||
3069 | if (ptr.ptr) | ||||
3070 | m_list->push_back(ptr); | ||||
3071 | } | ||||
3072 | } | ||||
3073 | |||||
3074 | |||||
3075 | /** | ||||
3076 | ************************************************************************** | ||||
3077 | * Name: CIccPcsXform::pushApplyIllum | ||||
3078 | * | ||||
3079 | * Purpose: | ||||
3080 | * Insert PCS step that applies an illuminant to incoming spectral transmissive | ||||
3081 | * vectors to . Illuminant from Profile Connection | ||||
3082 | * Conditions will be resampled to match the sampling range of the incoming | ||||
3083 | * vectors. | ||||
3084 | ************************************************************************** | ||||
3085 | */ | ||||
3086 | void CIccPcsXform::pushApplyIllum(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | ||||
3087 | { | ||||
3088 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | ||||
3089 | |||||
3090 | if (pView) { | ||||
3091 | CIccPcsStepPtr ptr; | ||||
3092 | |||||
3093 | icSpectralRange illuminantRange; | ||||
3094 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | ||||
3095 | |||||
3096 | CIccPcsStepScale *pScale = new CIccPcsStepScale(illuminantRange.steps); | ||||
3097 | memcpy(pScale->data(), illuminant, illuminantRange.steps*sizeof(icFloatNumber)); | ||||
3098 | |||||
3099 | if (icSameSpectralRange(pProfile->m_Header.spectralRange, illuminantRange)) { | ||||
3100 | ptr.ptr = pScale; | ||||
3101 | m_list->push_back(ptr); | ||||
3102 | } | ||||
3103 | else { | ||||
3104 | ptr.ptr = rangeMap(pProfile->m_Header.spectralRange, illuminantRange); | ||||
3105 | if (ptr.ptr) { | ||||
3106 | m_list->push_back(ptr); | ||||
3107 | } | ||||
3108 | |||||
3109 | ptr.ptr = pScale; | ||||
3110 | m_list->push_back(ptr); | ||||
3111 | |||||
3112 | ptr.ptr = rangeMap(illuminantRange, pProfile->m_Header.spectralRange); | ||||
3113 | if (ptr.ptr) | ||||
3114 | m_list->push_back(ptr); | ||||
3115 | } | ||||
3116 | } | ||||
3117 | } | ||||
3118 | |||||
3119 | |||||
3120 | /** | ||||
3121 | ************************************************************************** | ||||
3122 | * Name: CIccPcsXform::pushRad2Xyz | ||||
3123 | * | ||||
3124 | * Purpose: | ||||
3125 | * Insert PCS step that converts from source spectral radiometric vectors to | ||||
3126 | * actual XYZ colorimetry based upon observer information in Profile | ||||
3127 | * Connection Conditions. | ||||
3128 | ************************************************************************** | ||||
3129 | */ | ||||
3130 | void CIccPcsXform::pushRad2Xyz(CIccProfile* pProfile, IIccProfileConnectionConditions *pPcc, bool bAbsoluteCIEColorimetry) | ||||
3131 | { | ||||
3132 | const CIccTagSpectralViewingConditions *pProfView = pProfile ? pProfile->getPccViewingConditions() : NULL__null; | ||||
3133 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | ||||
3134 | if (pProfView && pView) { | ||||
3135 | icSpectralRange illuminantRange; | ||||
3136 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | ||||
3137 | |||||
3138 | icSpectralRange observerRange; | ||||
3139 | const icFloatNumber *observer = pView->getObserver(observerRange); | ||||
3140 | |||||
3141 | //Preserve smallest step size | ||||
3142 | icFloatNumber dPCSStepSize = (icF16toF(pProfile->m_Header.spectralRange.end) - icF16toF(pProfile->m_Header.spectralRange.start))/(icFloatNumber)pProfile->m_Header.spectralRange.steps; | ||||
3143 | icFloatNumber dObsStepSize = (icF16toF(observerRange.end) - icF16toF(observerRange.start)) / (icFloatNumber) observerRange.steps; | ||||
3144 | |||||
3145 | if (dPCSStepSize<dObsStepSize) { | ||||
3146 | icFloatNumber *obs = pView->applyRangeToObserver(pProfile->m_Header.spectralRange); | ||||
3147 | |||||
3148 | pushMatrix(3, pProfile->m_Header.spectralRange.steps, obs); | ||||
3149 | free(obs); | ||||
3150 | } | ||||
3151 | else { | ||||
3152 | pushSpecToRange(pProfile->m_Header.spectralRange, observerRange); | ||||
3153 | pushMatrix(3, observerRange.steps, observer); | ||||
3154 | |||||
3155 | } | ||||
3156 | icFloatNumber k; | ||||
3157 | if (bAbsoluteCIEColorimetry) { | ||||
3158 | k = 683; | ||||
3159 | } | ||||
3160 | else { | ||||
3161 | k = 1.0f / pPcc->getObserverWhiteScaleFactor(illuminant, illuminantRange); | ||||
3162 | } | ||||
3163 | pushScale3(k, k, k); | ||||
3164 | } | ||||
3165 | } | ||||
3166 | |||||
3167 | |||||
3168 | /** | ||||
3169 | ************************************************************************** | ||||
3170 | * Name: CIccPcsXform::pushBiRef2Rad | ||||
3171 | * | ||||
3172 | * Purpose: | ||||
3173 | * Insert PCS steps that apply an illuminant to incoming bi-spectral reflectance | ||||
3174 | * matrices to get estimate of light "reflected" by surface. | ||||
3175 | ************************************************************************** | ||||
3176 | */ | ||||
3177 | icStatusCMM CIccPcsXform::pushBiRef2Rad(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | ||||
3178 | { | ||||
3179 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | ||||
3180 | |||||
3181 | if (pView) { | ||||
3182 | icSpectralRange illuminantRange; | ||||
3183 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | ||||
3184 | |||||
3185 | if (icGetColorSpaceType(pProfile->m_Header.spectralPCS)((icColorSpaceSignature)(((icUInt32Number)pProfile->m_Header .spectralPCS)&0xffff0000))==icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData)) { | ||||
3186 | CIccPcsStepSrcSparseMatrix *pMtx = new CIccPcsStepSrcSparseMatrix(pProfile->m_Header.spectralRange.steps, | ||||
3187 | pProfile->m_Header.biSpectralRange.steps, | ||||
3188 | (icUInt16Number)icGetSpaceSamples((icColorSpaceSignature)pProfile->m_Header.spectralPCS)); | ||||
3189 | if (!pMtx) | ||||
3190 | return icCmmStatAllocErr; | ||||
3191 | |||||
3192 | CIccPcsStepMatrix *illumMtx = rangeMap(illuminantRange, pProfile->m_Header.biSpectralRange); | ||||
3193 | if (illumMtx) { | ||||
3194 | illumMtx->Apply(NULL__null, pMtx->data(), illuminant); | ||||
3195 | delete illumMtx; | ||||
3196 | } | ||||
3197 | else { | ||||
3198 | memcpy(pMtx->data(), illuminant, illuminantRange.steps*sizeof(icFloatNumber)); | ||||
3199 | } | ||||
3200 | |||||
3201 | CIccPcsStepPtr ptr; | ||||
3202 | ptr.ptr = pMtx; | ||||
3203 | m_list->push_back(ptr); | ||||
3204 | |||||
3205 | } | ||||
3206 | else { | ||||
3207 | CIccPcsStepSrcMatrix *pMtx = new CIccPcsStepSrcMatrix(pProfile->m_Header.spectralRange.steps, pProfile->m_Header.biSpectralRange.steps); | ||||
3208 | if (!pMtx) | ||||
3209 | return icCmmStatAllocErr; | ||||
3210 | |||||
3211 | CIccPcsStepMatrix *illumMtx = rangeMap(illuminantRange, pProfile->m_Header.biSpectralRange); | ||||
3212 | if (illumMtx) { | ||||
3213 | illumMtx->Apply(NULL__null, pMtx->data(), illuminant); | ||||
3214 | delete illumMtx; | ||||
3215 | } | ||||
3216 | else { | ||||
3217 | memcpy(pMtx->data(), illuminant, illuminantRange.steps*sizeof(icFloatNumber)); | ||||
3218 | } | ||||
3219 | |||||
3220 | CIccPcsStepPtr ptr; | ||||
3221 | ptr.ptr = pMtx; | ||||
3222 | m_list->push_back(ptr); | ||||
3223 | |||||
3224 | } | ||||
3225 | } | ||||
3226 | |||||
3227 | return icCmmStatOk; | ||||
3228 | } | ||||
3229 | |||||
3230 | |||||
3231 | /** | ||||
3232 | ************************************************************************** | ||||
3233 | * Name: CIccPcsXform::pushBiRef2Xyz | ||||
3234 | * | ||||
3235 | * Purpose: | ||||
3236 | * Insert PCS step that applies an illuminant to incoming bi-spectral reflectance | ||||
3237 | * matrices to get actual XYZ values. The illuminant from the Profile | ||||
3238 | * Connection Conditions is re-sampled to match the number of columns in | ||||
3239 | * the incoming matrices. | ||||
3240 | ************************************************************************** | ||||
3241 | */ | ||||
3242 | icStatusCMM CIccPcsXform::pushBiRef2Xyz(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | ||||
3243 | { | ||||
3244 | icStatusCMM stat = pushBiRef2Rad(pProfile, pPcc); | ||||
3245 | if (stat
| ||||
3246 | return stat; | ||||
3247 | |||||
3248 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | ||||
3249 | |||||
3250 | if (pView) { | ||||
3251 | icSpectralRange observerRange; | ||||
3252 | const icFloatNumber *observer = pView->getObserver(observerRange); | ||||
3253 | |||||
3254 | pushSpecToRange(pProfile->m_Header.spectralRange, observerRange); | ||||
3255 | pushMatrix(3, observerRange.steps, observer); | ||||
3256 | pushXYZNormalize(pPcc, pProfile->m_Header.biSpectralRange, pProfile->m_Header.spectralRange); | ||||
3257 | } | ||||
3258 | else { | ||||
3259 | return icCmmStatBadConnection; | ||||
3260 | } | ||||
3261 | |||||
3262 | return icCmmStatOk; | ||||
3263 | } | ||||
3264 | |||||
3265 | |||||
3266 | /** | ||||
3267 | ************************************************************************** | ||||
3268 | * Name: CIccPcsXform::pushBiRef2Ref | ||||
3269 | * | ||||
3270 | * Purpose: | ||||
3271 | * Insert PCS steps that apply an illuminant to incoming bi-spectral reflectance | ||||
3272 | * matrices and then normalizes by the illuminant to get an estimate of | ||||
3273 | * reflectance factor under that illuminant. | ||||
3274 | ************************************************************************** | ||||
3275 | */ | ||||
3276 | icStatusCMM CIccPcsXform::pushBiRef2Ref(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | ||||
3277 | { | ||||
3278 | icStatusCMM stat = pushBiRef2Rad(pProfile, pPcc); | ||||
3279 | if (stat!=icCmmStatOk) | ||||
3280 | return stat; | ||||
3281 | |||||
3282 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | ||||
3283 | |||||
3284 | if (pView) { | ||||
3285 | icSpectralRange illuminantRange; | ||||
3286 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | ||||
3287 | |||||
3288 | CIccPcsStepScale *pScale = new CIccPcsStepScale(pProfile->m_Header.spectralRange.steps); | ||||
3289 | |||||
3290 | if (pScale) { | ||||
3291 | icFloatNumber *pData = pScale->data(); | ||||
3292 | CIccPcsStepMatrix *illumMtx = rangeMap(illuminantRange, pProfile->m_Header.spectralRange); | ||||
3293 | int i; | ||||
3294 | |||||
3295 | if (illumMtx) { | ||||
3296 | illumMtx->Apply(NULL__null, pData, illuminant); | ||||
3297 | for (i=0; i<pProfile->m_Header.spectralRange.steps; i++) | ||||
3298 | pData[i] = 1.0f / pData[i]; | ||||
3299 | |||||
3300 | delete illumMtx; | ||||
3301 | |||||
3302 | CIccPcsStepPtr ptr; | ||||
3303 | ptr.ptr = pScale; | ||||
3304 | m_list->push_back(ptr); | ||||
3305 | } | ||||
3306 | else { | ||||
3307 | for (i=0; i<pProfile->m_Header.spectralRange.steps; i++) { | ||||
3308 | pData[i] = 1.0f / illuminant[i]; | ||||
3309 | } | ||||
3310 | } | ||||
3311 | } | ||||
3312 | else | ||||
3313 | return icCmmStatAllocErr; | ||||
3314 | } | ||||
3315 | else | ||||
3316 | return icCmmStatBadConnection; | ||||
3317 | |||||
3318 | return icCmmStatOk; | ||||
3319 | } | ||||
3320 | |||||
3321 | |||||
3322 | #ifdef _DEBUG | ||||
3323 | //#define DUMPCSSTEPRESULTS | ||||
3324 | #ifdef DUMPCSSTEPRESULTS | ||||
3325 | #define ICCDUMPPIXEL(n, pix) \ | ||||
3326 | if ((n)<96) { \ | ||||
3327 | printf("["); \ | ||||
3328 | int i; \ | ||||
3329 | for (i=0; i<(n); i++) { \ | ||||
3330 | if (i && !(i%12)) \ | ||||
3331 | printf("...\n"); \ | ||||
3332 | printf(" %.5f", pix[i]); \ | ||||
3333 | } \ | ||||
3334 | printf("]\n"); \ | ||||
3335 | } \ | ||||
3336 | else { \ | ||||
3337 | printf("[ BigAray with %d elements]\n", (n)); \ | ||||
3338 | } | ||||
3339 | #else | ||||
3340 | #define ICCDUMPPIXEL(n, pix) | ||||
3341 | #endif | ||||
3342 | #else | ||||
3343 | #define ICCDUMPPIXEL(n, pix) | ||||
3344 | #endif | ||||
3345 | |||||
3346 | |||||
3347 | /** | ||||
3348 | ************************************************************************** | ||||
3349 | * Name: CIccPcsXform::Apply | ||||
3350 | * | ||||
3351 | * Purpose: | ||||
3352 | * Applies the PcsXfrom steps using the apply pXform data to SrcPixel to get DstPixel | ||||
3353 | ************************************************************************** | ||||
3354 | */ | ||||
3355 | void CIccPcsXform::Apply(CIccApplyXform *pXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | ||||
3356 | { | ||||
3357 | CIccApplyPcsXform *pApplyXform = (CIccApplyPcsXform*)pXform; | ||||
3358 | CIccApplyPcsStepList *pList = pApplyXform->m_list; | ||||
3359 | |||||
3360 | ICCDUMPPIXEL(GetNumSrcSamples(), SrcPixel); | ||||
3361 | |||||
3362 | if (!pList) { | ||||
3363 | memcpy(DstPixel, SrcPixel, GetNumSrcSamples()*sizeof(icFloatNumber)); | ||||
3364 | ICCDUMPPIXEL(GetNumSrcSamples(), DstPixel); | ||||
3365 | return; | ||||
3366 | } | ||||
3367 | |||||
3368 | CIccApplyPcsStepList::iterator s, n; | ||||
3369 | s = n =pList->begin(); | ||||
3370 | |||||
3371 | if (s==pList->end()) { | ||||
3372 | memcpy(DstPixel, SrcPixel, GetNumSrcSamples()*sizeof(icFloatNumber)); | ||||
3373 | ICCDUMPPIXEL(GetNumSrcSamples(), DstPixel); | ||||
3374 | return; | ||||
3375 | } | ||||
3376 | |||||
3377 | n++; | ||||
3378 | |||||
3379 | if (n==pList->end()) { | ||||
3380 | s->ptr->Apply(DstPixel, SrcPixel); | ||||
3381 | ICCDUMPPIXEL(s->ptr->GetStep()->GetDstChannels(), DstPixel); | ||||
3382 | } | ||||
3383 | else { | ||||
3384 | const icFloatNumber *src = SrcPixel; | ||||
3385 | icFloatNumber *p1 = pApplyXform->m_temp1; | ||||
3386 | icFloatNumber *p2 = pApplyXform->m_temp2; | ||||
3387 | icFloatNumber *t; | ||||
3388 | |||||
3389 | for (;n!=pList->end(); s=n, n++) { | ||||
3390 | s->ptr->Apply(p1, src); | ||||
3391 | ICCDUMPPIXEL(s->ptr->GetStep()->GetDstChannels(), p1); | ||||
3392 | src=p1; | ||||
3393 | t=p1; p1=p2; p2=t; | ||||
3394 | } | ||||
3395 | s->ptr->Apply(DstPixel, src); | ||||
3396 | ICCDUMPPIXEL(s->ptr->GetStep()->GetDstChannels(), DstPixel); | ||||
3397 | } | ||||
3398 | } | ||||
3399 | |||||
3400 | /** | ||||
3401 | ************************************************************************** | ||||
3402 | * Name: CIccPcsStep::GetNewApply | ||||
3403 | * | ||||
3404 | * Purpose: | ||||
3405 | * Allocates a new CIccApplyPcsStep to be used with processing. | ||||
3406 | ************************************************************************** | ||||
3407 | */ | ||||
3408 | CIccApplyPcsStep* CIccPcsStep::GetNewApply() | ||||
3409 | { | ||||
3410 | return new CIccApplyPcsStep(this); | ||||
3411 | } | ||||
3412 | |||||
3413 | |||||
3414 | /** | ||||
3415 | ************************************************************************** | ||||
3416 | * Name: CIccPcsStepIdentity::Apply | ||||
3417 | * | ||||
3418 | * Purpose: | ||||
3419 | * Copies pSrc to pDst | ||||
3420 | ************************************************************************** | ||||
3421 | */ | ||||
3422 | void CIccPcsStepIdentity::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
3423 | { | ||||
3424 | if (pDst != pSrc) | ||||
3425 | memcpy(pDst, pSrc, m_nChannels*sizeof(icFloatNumber)); | ||||
3426 | } | ||||
3427 | |||||
3428 | |||||
3429 | /** | ||||
3430 | ************************************************************************** | ||||
3431 | * Name: CIccPcsStepIdentity::dump | ||||
3432 | * | ||||
3433 | * Purpose: | ||||
3434 | * dumps the context of the step | ||||
3435 | ************************************************************************** | ||||
3436 | */ | ||||
3437 | void CIccPcsStepIdentity::dump(std::string &str) const | ||||
3438 | { | ||||
3439 | str += "\nCIccPcsStepIdentity\n\n"; | ||||
3440 | } | ||||
3441 | |||||
3442 | |||||
3443 | /** | ||||
3444 | ************************************************************************** | ||||
3445 | * Name: CIccPcsStepIdentity::CIccPcsStepIdentity | ||||
3446 | * | ||||
3447 | * Purpose: | ||||
3448 | * Constructor | ||||
3449 | ************************************************************************** | ||||
3450 | */ | ||||
3451 | CIccPcsStepRouteMcs::CIccPcsStepRouteMcs(CIccTagArray *pSrcChannels, CIccTagArray *pDstChannels, CIccTagNumArray *pDefaults) | ||||
3452 | { | ||||
3453 | m_nSrcChannels = (icUInt16Number)pSrcChannels->GetSize(); | ||||
3454 | m_nDstChannels = (icUInt16Number)pDstChannels->GetSize(); | ||||
3455 | m_Index = new int[m_nDstChannels]; | ||||
3456 | m_Defaults = new icFloatNumber[m_nDstChannels]; | ||||
3457 | |||||
3458 | memset(m_Defaults, 0, m_nDstChannels*sizeof(icFloatNumber)); | ||||
3459 | |||||
3460 | if (pDefaults) { | ||||
3461 | pDefaults->GetValues(m_Defaults, 0, m_nDstChannels); | ||||
3462 | } | ||||
3463 | |||||
3464 | int i, j; | ||||
3465 | char *szSrc; | ||||
3466 | |||||
3467 | for (i=0; i<m_nDstChannels; i++) { | ||||
3468 | const icUChar *szDstChan = ((CIccTagUtf8Text*)(pDstChannels->GetIndex(i)))->GetText(); | ||||
3469 | for (j=0; j<m_nSrcChannels; j++) { | ||||
3470 | const icUChar *szSrcChan = ((CIccTagUtf8Text*)(pSrcChannels->GetIndex(j)))->GetText(); | ||||
3471 | szSrc = (char*)szSrcChan; | ||||
3472 | if (!icUtf8StrCmp(szDstChan, szSrcChan)strcmp((const char*)szDstChan, (const char*)szSrcChan)) | ||||
3473 | break; | ||||
3474 | } | ||||
3475 | if (j==m_nSrcChannels) { | ||||
3476 | m_Index[i] = -1; | ||||
3477 | } | ||||
3478 | else { | ||||
3479 | m_Index[i] = j; | ||||
3480 | } | ||||
3481 | //printf("%d - %d %s\n", m_Index[i], i, szDstChan); | ||||
3482 | } | ||||
3483 | } | ||||
3484 | |||||
3485 | |||||
3486 | /** | ||||
3487 | ************************************************************************** | ||||
3488 | * Name: CIccPcsStepIdentity::~CIccPcsStepIdentity | ||||
3489 | * | ||||
3490 | * Purpose: | ||||
3491 | * Destructor | ||||
3492 | ************************************************************************** | ||||
3493 | */ | ||||
3494 | CIccPcsStepRouteMcs::~CIccPcsStepRouteMcs() | ||||
3495 | { | ||||
3496 | if (m_Index) | ||||
3497 | delete [] m_Index; | ||||
3498 | if (m_Defaults) | ||||
3499 | delete [] m_Defaults; | ||||
3500 | } | ||||
3501 | |||||
3502 | |||||
3503 | /** | ||||
3504 | ************************************************************************** | ||||
3505 | * Name: CIccPcsStepRouteMcs::isIdentity | ||||
3506 | * | ||||
3507 | * Purpose: | ||||
3508 | * Determines if applying this step will result in negligible change in data | ||||
3509 | ************************************************************************** | ||||
3510 | */ | ||||
3511 | bool CIccPcsStepRouteMcs::isIdentity() const | ||||
3512 | { | ||||
3513 | if (m_nSrcChannels!=m_nDstChannels) | ||||
3514 | return false; | ||||
3515 | |||||
3516 | int i; | ||||
3517 | for (i=0; i<m_nDstChannels; i++) { | ||||
3518 | if (m_Index[i]!=i) | ||||
3519 | return false; | ||||
3520 | } | ||||
3521 | |||||
3522 | return true; | ||||
3523 | } | ||||
3524 | |||||
3525 | |||||
3526 | |||||
3527 | /** | ||||
3528 | ************************************************************************** | ||||
3529 | * Name: CIccPcsStepRouteMcs::Apply | ||||
3530 | * | ||||
3531 | * Purpose: | ||||
3532 | * Copies pSrc to pDst | ||||
3533 | ************************************************************************** | ||||
3534 | */ | ||||
3535 | void CIccPcsStepRouteMcs::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
3536 | { | ||||
3537 | if (pDst != pSrc) { | ||||
3538 | int i; | ||||
3539 | for (i=0; i<m_nDstChannels; i++) { | ||||
3540 | if (m_Index[i]>=0) | ||||
3541 | pDst[i] = pSrc[m_Index[i]]; | ||||
3542 | else | ||||
3543 | pDst[i] = m_Defaults[i]; | ||||
3544 | } | ||||
3545 | } | ||||
3546 | } | ||||
3547 | |||||
3548 | |||||
3549 | /** | ||||
3550 | ************************************************************************** | ||||
3551 | * Name: CIccPcsStepRouteMcs::dump | ||||
3552 | * | ||||
3553 | * Purpose: | ||||
3554 | * dumps the context of the step | ||||
3555 | ************************************************************************** | ||||
3556 | */ | ||||
3557 | void CIccPcsStepRouteMcs::dump(std::string &str) const | ||||
3558 | { | ||||
3559 | str += "\nCIccPcsStepRouteMcs\n\n"; | ||||
3560 | } | ||||
3561 | |||||
3562 | extern icFloatNumber icD50XYZ[3]; | ||||
3563 | |||||
3564 | /** | ||||
3565 | ************************************************************************** | ||||
3566 | * Name: CIccPcsLabStep::isSameWhite | ||||
3567 | * | ||||
3568 | * Purpose: | ||||
3569 | * Determines if this step has same white point as that passed in | ||||
3570 | ************************************************************************** | ||||
3571 | */ | ||||
3572 | bool CIccPcsLabStep::isSameWhite(const icFloatNumber *xyzWhite) | ||||
3573 | { | ||||
3574 | return (m_xyzWhite[0]==xyzWhite[0] && | ||||
3575 | m_xyzWhite[1]==xyzWhite[1] && | ||||
3576 | m_xyzWhite[2]==xyzWhite[2]); | ||||
3577 | } | ||||
3578 | |||||
3579 | |||||
3580 | |||||
3581 | /** | ||||
3582 | ************************************************************************** | ||||
3583 | * Name: CIccPcsStepLabToXYZ::CIccPcsStepLabToXYZ | ||||
3584 | * | ||||
3585 | * Purpose: | ||||
3586 | * Constructor | ||||
3587 | ************************************************************************** | ||||
3588 | */ | ||||
3589 | CIccPcsStepLabToXYZ::CIccPcsStepLabToXYZ(const icFloatNumber *xyzWhite/*=NULL*/) | ||||
3590 | { | ||||
3591 | if (xyzWhite) { | ||||
3592 | memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite)); | ||||
3593 | } | ||||
3594 | else { | ||||
3595 | memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite)); | ||||
3596 | } | ||||
3597 | } | ||||
3598 | |||||
3599 | |||||
3600 | /** | ||||
3601 | ************************************************************************** | ||||
3602 | * Name: CIccPcsStepLabToXYZ::Apply | ||||
3603 | * | ||||
3604 | * Purpose: | ||||
3605 | * Converts from V4 Internal Lab to actual XYZ | ||||
3606 | ************************************************************************** | ||||
3607 | */ | ||||
3608 | void CIccPcsStepLabToXYZ::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
3609 | { | ||||
3610 | icFloatNumber Lab[3]; | ||||
3611 | |||||
3612 | //lab4 to XYZ | ||||
3613 | Lab[0] = pSrc[0] * 100.0f; | ||||
3614 | Lab[1] = (icFloatNumber)(pSrc[1]*255.0f - 128.0f); | ||||
3615 | Lab[2] = (icFloatNumber)(pSrc[2]*255.0f - 128.0f); | ||||
3616 | |||||
3617 | icLabtoXYZ(pDst, Lab, m_xyzWhite); | ||||
3618 | } | ||||
3619 | |||||
3620 | |||||
3621 | /** | ||||
3622 | ************************************************************************** | ||||
3623 | * Name: CIccPcsStepLabToXYZ::dump | ||||
3624 | * | ||||
3625 | * Purpose: | ||||
3626 | * dumps the context of the step | ||||
3627 | ************************************************************************** | ||||
3628 | */ | ||||
3629 | void CIccPcsStepLabToXYZ::dump(std::string &str) const | ||||
3630 | { | ||||
3631 | str += "\nCIccPcsStepLabToXYZ\n\n"; | ||||
3632 | } | ||||
3633 | |||||
3634 | |||||
3635 | /** | ||||
3636 | ************************************************************************** | ||||
3637 | * Name: CIccPcsStepLabToXYZ::concat | ||||
3638 | * | ||||
3639 | * Purpose: | ||||
3640 | * Determines if this step can be combined with the next step. | ||||
3641 | * Checks if next step is an icPcsStepXyzToLab step resulting in a combined | ||||
3642 | * identity transform. | ||||
3643 | ************************************************************************** | ||||
3644 | */ | ||||
3645 | CIccPcsStep *CIccPcsStepLabToXYZ::concat(CIccPcsStep *pNext) const | ||||
3646 | { | ||||
3647 | if (pNext && pNext->GetType()==icPcsStepXYZToLab) { | ||||
3648 | CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext; | ||||
3649 | if (pStep->isSameWhite(m_xyzWhite)) | ||||
3650 | return new CIccPcsStepIdentity(3); | ||||
3651 | } | ||||
3652 | return NULL__null; | ||||
3653 | } | ||||
3654 | |||||
3655 | |||||
3656 | /** | ||||
3657 | ************************************************************************** | ||||
3658 | * Name: CIccPcsStepXYZToLab::CIccPcsStepXYZToLab | ||||
3659 | * | ||||
3660 | * Purpose: | ||||
3661 | * Constructor | ||||
3662 | ************************************************************************** | ||||
3663 | */ | ||||
3664 | CIccPcsStepXYZToLab::CIccPcsStepXYZToLab(const icFloatNumber *xyzWhite/*=NULL*/) | ||||
3665 | { | ||||
3666 | if (xyzWhite) { | ||||
3667 | memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite)); | ||||
3668 | } | ||||
3669 | else { | ||||
3670 | memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite)); | ||||
3671 | } | ||||
3672 | } | ||||
3673 | |||||
3674 | |||||
3675 | /** | ||||
3676 | ************************************************************************** | ||||
3677 | * Name: CIccPcsStepXYZToLab::Apply | ||||
3678 | * | ||||
3679 | * Purpose: | ||||
3680 | * Converts from actual XYZ to V4 Internal Lab | ||||
3681 | ************************************************************************** | ||||
3682 | */ | ||||
3683 | void CIccPcsStepXYZToLab::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
3684 | { | ||||
3685 | icFloatNumber Lab[3]; | ||||
3686 | icXYZtoLab(Lab, (icFloatNumber*)pSrc, m_xyzWhite); | ||||
3687 | //lab4 from XYZ | ||||
3688 | pDst[0] = Lab[0] / 100.0f; | ||||
3689 | pDst[1] = (icFloatNumber)((Lab[1] + 128.0f) / 255.0f); | ||||
3690 | pDst[2] = (icFloatNumber)((Lab[2] + 128.0f) / 255.0f); | ||||
3691 | } | ||||
3692 | |||||
3693 | |||||
3694 | /** | ||||
3695 | ************************************************************************** | ||||
3696 | * Name: CIccPcsStepXYZToLab::dump | ||||
3697 | * | ||||
3698 | * Purpose: | ||||
3699 | * dumps the context of the step | ||||
3700 | ************************************************************************** | ||||
3701 | */ | ||||
3702 | void CIccPcsStepXYZToLab::dump(std::string &str) const | ||||
3703 | { | ||||
3704 | str += "\nCIccPcsStepXYZToLab\n\n"; | ||||
3705 | } | ||||
3706 | |||||
3707 | |||||
3708 | /** | ||||
3709 | ************************************************************************** | ||||
3710 | * Name: CIccPcsStepXYZToLab::concat | ||||
3711 | * | ||||
3712 | * Purpose: | ||||
3713 | * Determines if this step can be combined with the next step. | ||||
3714 | * Checks if next step is an icPcsStepLabToXYZ step resulting in a combined | ||||
3715 | * identity transform. | ||||
3716 | ************************************************************************** | ||||
3717 | */ | ||||
3718 | CIccPcsStep *CIccPcsStepXYZToLab::concat(CIccPcsStep *pNext) const | ||||
3719 | { | ||||
3720 | if (pNext && pNext->GetType()==icPcsStepLabToXYZ) { | ||||
3721 | CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext; | ||||
3722 | if (pStep->isSameWhite(m_xyzWhite)) | ||||
3723 | return new CIccPcsStepIdentity(3); | ||||
3724 | } | ||||
3725 | return NULL__null; | ||||
3726 | } | ||||
3727 | |||||
3728 | |||||
3729 | /** | ||||
3730 | ************************************************************************** | ||||
3731 | * Name: CIccPcsStepLab2ToXYZ::CIccPcsStepLab2ToXYZ | ||||
3732 | * | ||||
3733 | * Purpose: | ||||
3734 | * Constructor | ||||
3735 | ************************************************************************** | ||||
3736 | */ | ||||
3737 | CIccPcsStepLab2ToXYZ::CIccPcsStepLab2ToXYZ(const icFloatNumber *xyzWhite/*=NULL*/) | ||||
3738 | { | ||||
3739 | if (xyzWhite) { | ||||
3740 | memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite)); | ||||
3741 | } | ||||
3742 | else { | ||||
3743 | memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite)); | ||||
3744 | } | ||||
3745 | } | ||||
3746 | |||||
3747 | /** | ||||
3748 | ************************************************************************** | ||||
3749 | * Name: CIccPcsStepLab2ToXYZ::Apply | ||||
3750 | * | ||||
3751 | * Purpose: | ||||
3752 | * Converts from actual XYZ to V2 Internal Lab | ||||
3753 | ************************************************************************** | ||||
3754 | */ | ||||
3755 | void CIccPcsStepLab2ToXYZ::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
3756 | { | ||||
3757 | icFloatNumber Lab[3]; | ||||
3758 | |||||
3759 | //lab2 to XYZ | ||||
3760 | Lab[0] = pSrc[0] * (65535.0f / 65280.0f) * 100.0f; | ||||
3761 | Lab[1] = (icFloatNumber)(pSrc[1] * 65535.0f / 65280.0f * 255.0f - 128.0f); | ||||
3762 | Lab[2] = (icFloatNumber)(pSrc[2] * 65535.0f / 65280.0f * 255.0f - 128.0f); | ||||
3763 | |||||
3764 | icLabtoXYZ(pDst, Lab, m_xyzWhite); | ||||
3765 | } | ||||
3766 | |||||
3767 | |||||
3768 | /** | ||||
3769 | ************************************************************************** | ||||
3770 | * Name: CIccPcsStepLab2ToXYZ::dump | ||||
3771 | * | ||||
3772 | * Purpose: | ||||
3773 | * dumps the context of the step | ||||
3774 | ************************************************************************** | ||||
3775 | */ | ||||
3776 | void CIccPcsStepLab2ToXYZ::dump(std::string &str) const | ||||
3777 | { | ||||
3778 | str += "\nCIccPcsStepLab2ToXYZ\n\n"; | ||||
3779 | } | ||||
3780 | |||||
3781 | |||||
3782 | /** | ||||
3783 | ************************************************************************** | ||||
3784 | * Name: CIccPcsStepLab2ToXYZ::concat | ||||
3785 | * | ||||
3786 | * Purpose: | ||||
3787 | * Determines if this step can be combined with the next step. | ||||
3788 | * Checks if next step is an icPcsStepXYZToLab2 step resulting in a combined | ||||
3789 | * identity transform. | ||||
3790 | ************************************************************************** | ||||
3791 | */ | ||||
3792 | CIccPcsStep *CIccPcsStepLab2ToXYZ::concat(CIccPcsStep *pNext) const | ||||
3793 | { | ||||
3794 | if (pNext && pNext->GetType()==icPcsStepXYZToLab2) { | ||||
3795 | CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext; | ||||
3796 | if (pStep->isSameWhite(m_xyzWhite)) | ||||
3797 | return new CIccPcsStepIdentity(3); | ||||
3798 | } | ||||
3799 | return NULL__null; | ||||
3800 | } | ||||
3801 | |||||
3802 | |||||
3803 | /** | ||||
3804 | ************************************************************************** | ||||
3805 | * Name: CIccPcsStepXYZToLab2::CIccPcsStepXYZToLab2 | ||||
3806 | * | ||||
3807 | * Purpose: | ||||
3808 | * Constructor | ||||
3809 | ************************************************************************** | ||||
3810 | */ | ||||
3811 | CIccPcsStepXYZToLab2::CIccPcsStepXYZToLab2(const icFloatNumber *xyzWhite/*=NULL*/) | ||||
3812 | { | ||||
3813 | if (xyzWhite) { | ||||
3814 | memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite)); | ||||
3815 | } | ||||
3816 | else { | ||||
3817 | memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite)); | ||||
3818 | } | ||||
3819 | } | ||||
3820 | |||||
3821 | |||||
3822 | /** | ||||
3823 | ************************************************************************** | ||||
3824 | * Name: CIccPcsStepXYZToLab2::Apply | ||||
3825 | * | ||||
3826 | * Purpose: | ||||
3827 | * Converts from V2 Internal Lab to actual XYZ | ||||
3828 | ************************************************************************** | ||||
3829 | */ | ||||
3830 | void CIccPcsStepXYZToLab2::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
3831 | { | ||||
3832 | icFloatNumber Lab[3]; | ||||
3833 | icXYZtoLab(Lab, (icFloatNumber*)pSrc, m_xyzWhite); | ||||
3834 | //lab2 from XYZ | ||||
3835 | pDst[0] = (Lab[0] / 100.0f) * (65280.0f / 65535.0f); | ||||
3836 | pDst[1] = (icFloatNumber)((Lab[1] + 128.0f) / 255.0f) * (65280.0f / 65535.0f); | ||||
3837 | pDst[2] = (icFloatNumber)((Lab[2] + 128.0f) / 255.0f) * (65280.0f / 65535.0f); | ||||
3838 | } | ||||
3839 | |||||
3840 | |||||
3841 | /** | ||||
3842 | ************************************************************************** | ||||
3843 | * Name: CIccPcsStepXYZToLab2::dump | ||||
3844 | * | ||||
3845 | * Purpose: | ||||
3846 | * dumps the context of the step | ||||
3847 | ************************************************************************** | ||||
3848 | */ | ||||
3849 | void CIccPcsStepXYZToLab2::dump(std::string &str) const | ||||
3850 | { | ||||
3851 | str += "\nCIccPcsStepXYZToLab2\n\n"; | ||||
3852 | } | ||||
3853 | |||||
3854 | |||||
3855 | /** | ||||
3856 | ************************************************************************** | ||||
3857 | * Name: CIccPcsStepXYZToLab2::concat | ||||
3858 | * | ||||
3859 | * Purpose: | ||||
3860 | * Determines if this step can be combined with the next step. | ||||
3861 | * Checks if next step is an icPcsStepLab2ToXYZ step resulting in a combined | ||||
3862 | * identity transform. | ||||
3863 | ************************************************************************** | ||||
3864 | */ | ||||
3865 | CIccPcsStep *CIccPcsStepXYZToLab2::concat(CIccPcsStep *pNext) const | ||||
3866 | { | ||||
3867 | if (pNext && pNext->GetType()==icPcsStepLab2ToXYZ) { | ||||
3868 | CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext; | ||||
3869 | if (pStep->isSameWhite(m_xyzWhite)) | ||||
3870 | return new CIccPcsStepIdentity(3); | ||||
3871 | } | ||||
3872 | return NULL__null; | ||||
3873 | } | ||||
3874 | |||||
3875 | |||||
3876 | /** | ||||
3877 | ************************************************************************** | ||||
3878 | * Name: CIccPcsStepOffset::CIccPcsStepOffset | ||||
3879 | * | ||||
3880 | * Purpose: | ||||
3881 | * Constructor | ||||
3882 | ************************************************************************** | ||||
3883 | */ | ||||
3884 | CIccPcsStepOffset::CIccPcsStepOffset(icUInt16Number nChannels) | ||||
3885 | { | ||||
3886 | m_nChannels = nChannels; | ||||
3887 | m_vals = new icFloatNumber[nChannels]; | ||||
3888 | } | ||||
3889 | |||||
3890 | |||||
3891 | /** | ||||
3892 | ************************************************************************** | ||||
3893 | * Name: CIccPcsStepOffset::CIccPcsStepOffset | ||||
3894 | * | ||||
3895 | * Purpose: | ||||
3896 | * Destructor | ||||
3897 | ************************************************************************** | ||||
3898 | */ | ||||
3899 | CIccPcsStepOffset::~CIccPcsStepOffset() | ||||
3900 | { | ||||
3901 | if (m_vals) | ||||
3902 | delete m_vals; | ||||
3903 | } | ||||
3904 | |||||
3905 | |||||
3906 | /** | ||||
3907 | ************************************************************************** | ||||
3908 | * Name: CIccPcsStepOffset::Apply | ||||
3909 | * | ||||
3910 | * Purpose: | ||||
3911 | * Added a fixed offset to the pSrc vector passed in | ||||
3912 | ************************************************************************** | ||||
3913 | */ | ||||
3914 | void CIccPcsStepOffset::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
3915 | { | ||||
3916 | if (m_nChannels==3) { | ||||
3917 | pDst[0] = m_vals[0] + pSrc[0]; | ||||
3918 | pDst[1] = m_vals[1] + pSrc[1]; | ||||
3919 | pDst[2] = m_vals[2] + pSrc[2]; | ||||
3920 | } | ||||
3921 | else { | ||||
3922 | int i; | ||||
3923 | for (i=0; i<m_nChannels; i++) { | ||||
3924 | pDst[i] = m_vals[i] + pSrc[i]; | ||||
3925 | } | ||||
3926 | } | ||||
3927 | } | ||||
3928 | |||||
3929 | |||||
3930 | /** | ||||
3931 | ************************************************************************** | ||||
3932 | * Name: CIccPcsStepOffset::dump | ||||
3933 | * | ||||
3934 | * Purpose: | ||||
3935 | * dumps the context of the step | ||||
3936 | ************************************************************************** | ||||
3937 | */ | ||||
3938 | void CIccPcsStepOffset::dump(std::string &str) const | ||||
3939 | { | ||||
3940 | str += "\nCIccPcsStepOffset\n\n"; | ||||
3941 | char buf[80]; | ||||
3942 | for (int i=0; i<m_nChannels; i++) { | ||||
3943 | sprintf(buf, ICCPCSSTEPDUMPFMT" %.8f", m_vals[i]); | ||||
3944 | str += buf; | ||||
3945 | } | ||||
3946 | str +="\n"; | ||||
3947 | } | ||||
3948 | |||||
3949 | |||||
3950 | /** | ||||
3951 | ************************************************************************** | ||||
3952 | * Name: CIccPcsStepOffset::Apply | ||||
3953 | * | ||||
3954 | * Purpose: | ||||
3955 | * Creates a new CIccPcsStepOffet step that is the result of adding the | ||||
3956 | * offset of this object to the offset of another object. | ||||
3957 | ************************************************************************** | ||||
3958 | */ | ||||
3959 | CIccPcsStepOffset *CIccPcsStepOffset::Add(const CIccPcsStepOffset *offset) const | ||||
3960 | { | ||||
3961 | if (offset->m_nChannels != m_nChannels) | ||||
3962 | return NULL__null; | ||||
3963 | |||||
3964 | CIccPcsStepOffset *pNew = new CIccPcsStepOffset(m_nChannels); | ||||
3965 | |||||
3966 | if (pNew) { | ||||
3967 | int i; | ||||
3968 | for (i=0; i<m_nChannels; i++) { | ||||
3969 | pNew->m_vals[i] = m_vals[i] + offset->m_vals[i]; | ||||
3970 | } | ||||
3971 | } | ||||
3972 | |||||
3973 | return pNew; | ||||
3974 | } | ||||
3975 | |||||
3976 | /** | ||||
3977 | ************************************************************************** | ||||
3978 | * Name: CIccPcsStepOffset::concat | ||||
3979 | * | ||||
3980 | * Purpose: | ||||
3981 | * Determines if this step can be combined with the next step. | ||||
3982 | * Checks if next step is a compatible icPcsStepOffset step resulting in a | ||||
3983 | * single combined offset. | ||||
3984 | ************************************************************************** | ||||
3985 | */ | ||||
3986 | CIccPcsStep *CIccPcsStepOffset::concat(CIccPcsStep *pNext) const | ||||
3987 | { | ||||
3988 | if (pNext && pNext->GetType()==icPcsStepOffset && m_nChannels==pNext->GetSrcChannels()) | ||||
3989 | return Add((const CIccPcsStepOffset*)pNext); | ||||
3990 | |||||
3991 | return NULL__null; | ||||
3992 | } | ||||
3993 | |||||
3994 | |||||
3995 | /** | ||||
3996 | ************************************************************************** | ||||
3997 | * Name: CIccPcsStepOffset::isIdentity | ||||
3998 | * | ||||
3999 | * Purpose: | ||||
4000 | * Determines if applying this step will result in negligible change in data | ||||
4001 | ************************************************************************** | ||||
4002 | */ | ||||
4003 | bool CIccPcsStepOffset::isIdentity() const | ||||
4004 | { | ||||
4005 | int i; | ||||
4006 | for (i=0; i<m_nChannels; i++) { | ||||
4007 | if (m_vals[i]<-icNearRange0.000001 || m_vals[i]>icNearRange0.000001) | ||||
4008 | return false; | ||||
4009 | } | ||||
4010 | |||||
4011 | return true; | ||||
4012 | } | ||||
4013 | |||||
4014 | |||||
4015 | /** | ||||
4016 | ************************************************************************** | ||||
4017 | * Name: CIccPcsStepScale::CIccPcsStepScale | ||||
4018 | * | ||||
4019 | * Purpose: | ||||
4020 | * Constructor | ||||
4021 | ************************************************************************** | ||||
4022 | */ | ||||
4023 | CIccPcsStepScale::CIccPcsStepScale(icUInt16Number nChannels) | ||||
4024 | { | ||||
4025 | m_nChannels = nChannels; | ||||
4026 | m_vals = new icFloatNumber[nChannels]; | ||||
4027 | } | ||||
4028 | |||||
4029 | |||||
4030 | /** | ||||
4031 | ************************************************************************** | ||||
4032 | * Name: CIccPcsStepScale::~CIccPcsStepScale | ||||
4033 | * | ||||
4034 | * Purpose: | ||||
4035 | * Destructor | ||||
4036 | ************************************************************************** | ||||
4037 | */ | ||||
4038 | CIccPcsStepScale::~CIccPcsStepScale() | ||||
4039 | { | ||||
4040 | if (m_vals) | ||||
4041 | delete m_vals; | ||||
4042 | } | ||||
4043 | |||||
4044 | /** | ||||
4045 | ************************************************************************** | ||||
4046 | * Name: CIccPcsStepScale::Apply | ||||
4047 | * | ||||
4048 | * Purpose: | ||||
4049 | * Multiplies fixed scale values to the pSrc vector passed in | ||||
4050 | ************************************************************************** | ||||
4051 | */ | ||||
4052 | void CIccPcsStepScale::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
4053 | { | ||||
4054 | if (m_nChannels==3) { | ||||
4055 | pDst[0] = m_vals[0] * pSrc[0]; | ||||
4056 | pDst[1] = m_vals[1] * pSrc[1]; | ||||
4057 | pDst[2] = m_vals[2] * pSrc[2]; | ||||
4058 | } | ||||
4059 | else { | ||||
4060 | int i; | ||||
4061 | for (i=0; i<m_nChannels; i++) { | ||||
4062 | pDst[i] = m_vals[i] * pSrc[i]; | ||||
4063 | } | ||||
4064 | } | ||||
4065 | } | ||||
4066 | |||||
4067 | |||||
4068 | /** | ||||
4069 | ************************************************************************** | ||||
4070 | * Name: CIccPcsStepScale::dump | ||||
4071 | * | ||||
4072 | * Purpose: | ||||
4073 | * dumps the context of the step | ||||
4074 | ************************************************************************** | ||||
4075 | */ | ||||
4076 | void CIccPcsStepScale::dump(std::string &str) const | ||||
4077 | { | ||||
4078 | str += "\nCIccPcsStepScale\n\n"; | ||||
4079 | char buf[80]; | ||||
4080 | for (int i=0; i<m_nChannels; i++) { | ||||
4081 | sprintf(buf, ICCPCSSTEPDUMPFMT" %.8f", m_vals[i]); | ||||
4082 | str += buf; | ||||
4083 | } | ||||
4084 | str +="\n"; | ||||
4085 | } | ||||
4086 | |||||
4087 | |||||
4088 | /** | ||||
4089 | ************************************************************************** | ||||
4090 | * Name: CIccPcsStepScale::Mult | ||||
4091 | * | ||||
4092 | * Purpose: | ||||
4093 | * Creates a new CIccPcsStepScale step that is the result of multiplying the | ||||
4094 | * scale of this object to the scale of another object. | ||||
4095 | ************************************************************************** | ||||
4096 | */ | ||||
4097 | CIccPcsStepScale *CIccPcsStepScale::Mult(const CIccPcsStepScale *scale) const | ||||
4098 | { | ||||
4099 | if (scale->m_nChannels != m_nChannels) | ||||
4100 | return NULL__null; | ||||
4101 | |||||
4102 | CIccPcsStepScale *pNew = new CIccPcsStepScale(m_nChannels); | ||||
4103 | |||||
4104 | if (pNew) { | ||||
4105 | int i; | ||||
4106 | for (i=0; i<m_nChannels; i++) { | ||||
4107 | pNew->m_vals[i] = m_vals[i] * scale->m_vals[i]; | ||||
4108 | } | ||||
4109 | } | ||||
4110 | return pNew; | ||||
4111 | } | ||||
4112 | |||||
4113 | /** | ||||
4114 | ************************************************************************** | ||||
4115 | * Name: CIccPcsStepScale::Mult | ||||
4116 | * | ||||
4117 | * Purpose: | ||||
4118 | * Creates a new CIccPcsStepMatrix step that is the result of multiplying the | ||||
4119 | * scale of this object to the scale of another matrix. | ||||
4120 | ************************************************************************** | ||||
4121 | */ | ||||
4122 | CIccPcsStepMatrix *CIccPcsStepScale::Mult(const CIccPcsStepMatrix *matrix) const | ||||
4123 | { | ||||
4124 | if (matrix->GetSrcChannels() != m_nChannels) | ||||
4125 | return NULL__null; | ||||
4126 | |||||
4127 | CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(matrix->GetDstChannels(), matrix->GetSrcChannels()); | ||||
4128 | |||||
4129 | if (pNew) { | ||||
4130 | int i, j; | ||||
4131 | for (j=0; j<matrix->GetDstChannels(); j++) { | ||||
4132 | const icFloatNumber *row = matrix->entry(j); | ||||
4133 | icFloatNumber *to=pNew->entry(j); | ||||
4134 | |||||
4135 | for (i=0; i<m_nChannels; i++) { | ||||
4136 | to[i] = m_vals[i] * row[i]; | ||||
4137 | } | ||||
4138 | } | ||||
4139 | } | ||||
4140 | |||||
4141 | return pNew; | ||||
4142 | } | ||||
4143 | |||||
4144 | /** | ||||
4145 | ************************************************************************** | ||||
4146 | * Name: CIccPcsStepScale::Mult | ||||
4147 | * | ||||
4148 | * Purpose: | ||||
4149 | * Creates a new CIccPcsStepMatrix step that is the result of multiplying the | ||||
4150 | * scale of this object to the scale of another matrix. | ||||
4151 | ************************************************************************** | ||||
4152 | */ | ||||
4153 | CIccPcsStepMatrix *CIccPcsStepScale::Mult(const CIccMpeMatrix *matrix) const | ||||
4154 | { | ||||
4155 | if (matrix->NumInputChannels() != m_nChannels) | ||||
4156 | return NULL__null; | ||||
4157 | |||||
4158 | CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(matrix->NumOutputChannels(), matrix->NumInputChannels()); | ||||
4159 | |||||
4160 | if (pNew) { | ||||
4161 | int i, j; | ||||
4162 | icFloatNumber *mtx = matrix->GetMatrix(); | ||||
4163 | for (j = 0; j < matrix->NumOutputChannels(); j++) { | ||||
4164 | const icFloatNumber *row = &mtx[j*matrix->NumInputChannels()]; | ||||
4165 | icFloatNumber *to = pNew->entry(j); | ||||
4166 | |||||
4167 | for (i = 0; i < m_nChannels; i++) { | ||||
4168 | to[i] = m_vals[i] * row[i]; | ||||
4169 | } | ||||
4170 | } | ||||
4171 | } | ||||
4172 | |||||
4173 | return pNew; | ||||
4174 | } | ||||
4175 | |||||
4176 | |||||
4177 | /** | ||||
4178 | ************************************************************************** | ||||
4179 | * Name: CIccPcsStepScale::concat | ||||
4180 | * | ||||
4181 | * Purpose: | ||||
4182 | * Determines if this step can be combined with the next step. | ||||
4183 | * Checks if next step is a compatible icPcsStepScale or icPcsStepMatrix step | ||||
4184 | * resulting in a single combined object. | ||||
4185 | ************************************************************************** | ||||
4186 | */ | ||||
4187 | CIccPcsStep *CIccPcsStepScale::concat(CIccPcsStep *pNext) const | ||||
4188 | { | ||||
4189 | if (pNext) { | ||||
4190 | if (pNext->GetType()==icPcsStepScale && m_nChannels==pNext->GetSrcChannels()) | ||||
4191 | return Mult((const CIccPcsStepScale*)pNext); | ||||
4192 | if (pNext->GetType()==icPcsStepMatrix && m_nChannels==pNext->GetSrcChannels()) | ||||
4193 | return Mult((const CIccPcsStepMatrix*)pNext); | ||||
4194 | if (pNext->GetType() == icPcsStepMpe && m_nChannels == pNext->GetSrcChannels()) { | ||||
4195 | CIccPcsStepMpe *pMpe = (CIccPcsStepMpe*)pNext; | ||||
4196 | CIccMpeMatrix *pMatrix = pMpe->GetMatrix(); | ||||
4197 | if (pMatrix) | ||||
4198 | return Mult(pMatrix); | ||||
4199 | } | ||||
4200 | } | ||||
4201 | |||||
4202 | return NULL__null; | ||||
4203 | } | ||||
4204 | |||||
4205 | |||||
4206 | /** | ||||
4207 | ************************************************************************** | ||||
4208 | * Name: CIccPcsStepScale::isIdentity | ||||
4209 | * | ||||
4210 | * Purpose: | ||||
4211 | * Determines if applying this step will result in negligible change in data | ||||
4212 | ************************************************************************** | ||||
4213 | */ | ||||
4214 | bool CIccPcsStepScale::isIdentity() const | ||||
4215 | { | ||||
4216 | int i; | ||||
4217 | for (i=0; i<m_nChannels; i++) { | ||||
4218 | if (m_vals[i]<1.0f-icNearRange0.000001 || m_vals[i]>1.0f+icNearRange0.000001) | ||||
4219 | return false; | ||||
4220 | } | ||||
4221 | |||||
4222 | return true; | ||||
4223 | } | ||||
4224 | |||||
4225 | |||||
4226 | |||||
4227 | /** | ||||
4228 | ************************************************************************** | ||||
4229 | * Name: CIccPcsStepMatrix::dump | ||||
4230 | * | ||||
4231 | * Purpose: | ||||
4232 | * dumps the context of the step | ||||
4233 | ************************************************************************** | ||||
4234 | */ | ||||
4235 | void CIccPcsStepMatrix::dump(std::string &str) const | ||||
4236 | { | ||||
4237 | str += "\nCIccPcsStepMatrix\n\n"; | ||||
4238 | dumpMtx(str); | ||||
4239 | } | ||||
4240 | |||||
4241 | |||||
4242 | /** | ||||
4243 | ************************************************************************** | ||||
4244 | * Name: CIccPcsStepMatrix::Mult | ||||
4245 | * | ||||
4246 | * Purpose: | ||||
4247 | * Creates a new CIccPcsStepMatrix step that is the result of multiplying the | ||||
4248 | * matrix of this object to the scale of another object. | ||||
4249 | ************************************************************************** | ||||
4250 | */ | ||||
4251 | CIccPcsStepMatrix *CIccPcsStepMatrix::Mult(const CIccPcsStepScale *scale) const | ||||
4252 | { | ||||
4253 | icUInt16Number mCols = scale->GetSrcChannels(); | ||||
4254 | icUInt16Number mRows = mCols; | ||||
4255 | |||||
4256 | if (m_nRows != mCols) | ||||
4257 | return NULL__null; | ||||
4258 | |||||
4259 | CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(m_nRows, m_nCols); | ||||
4260 | const icFloatNumber *data = scale->data(); | ||||
4261 | |||||
4262 | int i, j; | ||||
4263 | for (j=0; j<m_nRows; j++) { | ||||
4264 | const icFloatNumber *row = entry(j); | ||||
4265 | icFloatNumber *to = pNew->entry(j); | ||||
4266 | for (i=0; i<m_nCols; i++) { | ||||
4267 | to[i] = data[j] * row[i]; | ||||
4268 | } | ||||
4269 | } | ||||
4270 | |||||
4271 | return pNew; | ||||
4272 | } | ||||
4273 | |||||
4274 | /** | ||||
4275 | ************************************************************************** | ||||
4276 | * Name: CIccPcsStepMatrix::Mult | ||||
4277 | * | ||||
4278 | * Purpose: | ||||
4279 | * Creates a new CIccPcsStepMatrix step that is the result of concatentating | ||||
4280 | * another matrix with this matrix. (IE result = matrix * this). | ||||
4281 | ************************************************************************** | ||||
4282 | */ | ||||
4283 | CIccPcsStepMatrix *CIccPcsStepMatrix::Mult(const CIccPcsStepMatrix *matrix) const | ||||
4284 | { | ||||
4285 | icUInt16Number mCols = matrix->m_nCols; | ||||
4286 | icUInt16Number mRows = matrix->m_nRows; | ||||
4287 | |||||
4288 | if (m_nRows != mCols) | ||||
4289 | return NULL__null; | ||||
4290 | |||||
4291 | CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(mRows, m_nCols); | ||||
4292 | |||||
4293 | int i, j, k; | ||||
4294 | for (j=0; j<mRows; j++) { | ||||
4295 | const icFloatNumber *row = matrix->entry(j); | ||||
4296 | for (i=0; i<m_nCols; i++) { | ||||
4297 | icFloatNumber *to = pNew->entry(j, i); | ||||
4298 | const icFloatNumber *from = entry(0, i); | ||||
4299 | |||||
4300 | *to = 0.0f; | ||||
4301 | for (k=0; k<m_nRows; k++) { | ||||
4302 | *to += row[k] * (*from); | ||||
4303 | from += m_nCols; | ||||
4304 | } | ||||
4305 | } | ||||
4306 | } | ||||
4307 | |||||
4308 | return pNew; | ||||
4309 | } | ||||
4310 | |||||
4311 | |||||
4312 | /** | ||||
4313 | ************************************************************************** | ||||
4314 | * Name: CIccPcsStepMatrix::concat | ||||
4315 | * | ||||
4316 | * Purpose: | ||||
4317 | * Determines if this step can be combined with the next step. | ||||
4318 | * Checks if next step is a compatible icPcsStepScale or icPcsStepMatrix step | ||||
4319 | * resulting in a single combined object. | ||||
4320 | ************************************************************************** | ||||
4321 | */ | ||||
4322 | CIccPcsStep *CIccPcsStepMatrix::concat(CIccPcsStep *pNext) const | ||||
4323 | { | ||||
4324 | if (pNext) { | ||||
4325 | if (pNext->GetType()==icPcsStepScale && GetDstChannels()==pNext->GetSrcChannels()) | ||||
4326 | return Mult((const CIccPcsStepScale*)pNext); | ||||
4327 | if (pNext->GetType()==icPcsStepMatrix && GetDstChannels()==pNext->GetSrcChannels()) | ||||
4328 | return Mult((const CIccPcsStepMatrix*)pNext); | ||||
4329 | } | ||||
4330 | |||||
4331 | return NULL__null; | ||||
4332 | } | ||||
4333 | |||||
4334 | /** | ||||
4335 | ************************************************************************** | ||||
4336 | * Name: CIccPcsStepMatrix::concat | ||||
4337 | * | ||||
4338 | * Purpose: | ||||
4339 | * Determines if this step can be combined with the next step. | ||||
4340 | * Checks if next step is a compatible icPcsStepScale or icPcsStepMatrix step | ||||
4341 | * resulting in a single combined object. | ||||
4342 | ************************************************************************** | ||||
4343 | */ | ||||
4344 | CIccPcsStep *CIccPcsStepMatrix::reduce() const | ||||
4345 | { | ||||
4346 | int nVals = m_nRows*m_nCols; | ||||
4347 | int nNonZeros = 0; | ||||
4348 | int i; | ||||
4349 | |||||
4350 | for (i=0; i<nVals; i++) { | ||||
4351 | icFloatNumber v = m_vals[i]; | ||||
4352 | if (icNotZero(v)((v)>1.0e-8 || (v)<-1.0e-8)) | ||||
4353 | nNonZeros++; | ||||
4354 | } | ||||
4355 | if (nNonZeros<nVals*3/4) { | ||||
4356 | icUInt32Number nMatrixBytes = CIccSparseMatrix::MemSize(nNonZeros, m_nRows, sizeof(icFloatNumber))+4*sizeof(icFloatNumber); | ||||
4357 | CIccPcsStepSparseMatrix *pMtx = new CIccPcsStepSparseMatrix(m_nRows, m_nCols, nMatrixBytes); | ||||
4358 | CIccSparseMatrix mtx(pMtx->data(), nMatrixBytes); | ||||
4359 | mtx.Init(m_nRows, m_nCols, true); | ||||
4360 | mtx.FillFromFullMatrix(m_vals); | ||||
4361 | return pMtx; | ||||
4362 | } | ||||
4363 | |||||
4364 | return (CIccPcsStep*)this; | ||||
4365 | } | ||||
4366 | |||||
4367 | |||||
4368 | |||||
4369 | /** | ||||
4370 | ************************************************************************** | ||||
4371 | * Name: CIccPcsStepMpe::CIccPcsStepMpe | ||||
4372 | * | ||||
4373 | * Purpose: | ||||
4374 | * Constructor | ||||
4375 | ************************************************************************** | ||||
4376 | */ | ||||
4377 | CIccPcsStepMpe::CIccPcsStepMpe(CIccTagMultiProcessElement *pMpe) | ||||
4378 | { | ||||
4379 | m_pMpe = pMpe; | ||||
4380 | } | ||||
4381 | |||||
4382 | |||||
4383 | /** | ||||
4384 | ************************************************************************** | ||||
4385 | * Name: CIccPcsStepMpe::~CIccPcsStepMpe | ||||
4386 | * | ||||
4387 | * Purpose: | ||||
4388 | * Destructor | ||||
4389 | ************************************************************************** | ||||
4390 | */ | ||||
4391 | CIccPcsStepMpe::~CIccPcsStepMpe() | ||||
4392 | { | ||||
4393 | if (m_pMpe) | ||||
4394 | delete m_pMpe; | ||||
4395 | } | ||||
4396 | |||||
4397 | |||||
4398 | /** | ||||
4399 | ************************************************************************** | ||||
4400 | * Name: CIccPcsStepMpe::GetNewApply | ||||
4401 | * | ||||
4402 | * Purpose: | ||||
4403 | * Allocates a new CIccApplyPcsStep to be used with processing. | ||||
4404 | ************************************************************************** | ||||
4405 | */ | ||||
4406 | CIccApplyPcsStep* CIccPcsStepMpe::GetNewApply() | ||||
4407 | { | ||||
4408 | CIccApplyPcsStepMpe *rv = new CIccApplyPcsStepMpe(this, m_pMpe->GetNewApply()); | ||||
4409 | |||||
4410 | return rv; | ||||
4411 | } | ||||
4412 | |||||
4413 | |||||
4414 | /** | ||||
4415 | ************************************************************************** | ||||
4416 | * Name: CIccPcsStepMpe::Apply | ||||
4417 | * | ||||
4418 | * Purpose: | ||||
4419 | * Applies a MultiProcessingElement to a Source vector to get a Dest vector | ||||
4420 | ************************************************************************** | ||||
4421 | */ | ||||
4422 | void CIccPcsStepMpe::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
4423 | { | ||||
4424 | CIccApplyPcsStepMpe *pMpeApply = (CIccApplyPcsStepMpe*)pApply; | ||||
4425 | |||||
4426 | m_pMpe->Apply(pMpeApply->m_pApply, pDst, pSrc); | ||||
4427 | } | ||||
4428 | |||||
4429 | |||||
4430 | /** | ||||
4431 | ************************************************************************** | ||||
4432 | * Name: CIccPcsStepMpe::dump | ||||
4433 | * | ||||
4434 | * Purpose: | ||||
4435 | * dumps the context of the step | ||||
4436 | ************************************************************************** | ||||
4437 | */ | ||||
4438 | void CIccPcsStepMpe::dump(std::string &str) const | ||||
4439 | { | ||||
4440 | str += "\nCIccPcsStepMpe\n\n"; | ||||
4441 | m_pMpe->Describe(str); | ||||
4442 | } | ||||
4443 | |||||
4444 | |||||
4445 | /** | ||||
4446 | ************************************************************************** | ||||
4447 | * Name: CIccPcsStepMpe::isIdentity | ||||
4448 | * | ||||
4449 | * Purpose: | ||||
4450 | * Determines if applying this step will obviously result in no change in data | ||||
4451 | ************************************************************************** | ||||
4452 | */ | ||||
4453 | bool CIccPcsStepMpe::isIdentity() const | ||||
4454 | { | ||||
4455 | if (!m_pMpe || !m_pMpe->NumElements()) | ||||
4456 | return true; | ||||
4457 | return false; | ||||
4458 | } | ||||
4459 | |||||
4460 | /** | ||||
4461 | ************************************************************************** | ||||
4462 | * Name: CIccPcsStepMpe::GetSrcChannels | ||||
4463 | * | ||||
4464 | * Purpose: | ||||
4465 | * Returns the number of channels of data required going into the multi- | ||||
4466 | * processing element | ||||
4467 | ************************************************************************** | ||||
4468 | */ | ||||
4469 | icUInt16Number CIccPcsStepMpe::GetSrcChannels() const | ||||
4470 | { | ||||
4471 | return m_pMpe->NumInputChannels(); | ||||
4472 | } | ||||
4473 | |||||
4474 | |||||
4475 | /** | ||||
4476 | ************************************************************************** | ||||
4477 | * Name: CIccPcsStepMpe::GetDstChannels | ||||
4478 | * | ||||
4479 | * Purpose: | ||||
4480 | * Returns the number of channels of data coming out of the multi- | ||||
4481 | * processing element | ||||
4482 | ************************************************************************** | ||||
4483 | */ | ||||
4484 | icUInt16Number CIccPcsStepMpe::GetDstChannels() const | ||||
4485 | { | ||||
4486 | return m_pMpe->NumOutputChannels(); | ||||
4487 | } | ||||
4488 | |||||
4489 | |||||
4490 | /** | ||||
4491 | ************************************************************************** | ||||
4492 | * Name: CIccPcsStepMpe::GetMatrix() | ||||
4493 | * | ||||
4494 | * Purpose: | ||||
4495 | * Returns single CIccMpeMatrix element associated with PCS step or | ||||
4496 | * NULL if the MPE is more complex | ||||
4497 | ************************************************************************** | ||||
4498 | */ | ||||
4499 | CIccMpeMatrix *CIccPcsStepMpe::GetMatrix() const | ||||
4500 | { | ||||
4501 | //Must be single element | ||||
4502 | if (m_pMpe->NumElements() == 1) { | ||||
4503 | CIccMultiProcessElement *pElem = m_pMpe->GetElement(0); | ||||
4504 | //Must be a matrix | ||||
4505 | if (pElem && pElem->GetType() == icSigMatrixElemType) { | ||||
4506 | CIccMpeMatrix *pMtx = (CIccMpeMatrix*)pElem; | ||||
4507 | |||||
4508 | //Should not apply any constants | ||||
4509 | if (!pMtx->GetConstants() || !pMtx->GetApplyConstants()) | ||||
4510 | return pMtx; | ||||
4511 | } | ||||
4512 | } | ||||
4513 | |||||
4514 | return NULL__null; | ||||
4515 | } | ||||
4516 | |||||
4517 | |||||
4518 | |||||
4519 | |||||
4520 | /** | ||||
4521 | ************************************************************************** | ||||
4522 | * Name: CIccPcsStepMpe::Begin | ||||
4523 | * | ||||
4524 | * Purpose: | ||||
4525 | * Initializes multi-processing element for processing. Must be called before | ||||
4526 | * Apply is called | ||||
4527 | ************************************************************************** | ||||
4528 | */ | ||||
4529 | bool CIccPcsStepMpe::Begin() | ||||
4530 | { | ||||
4531 | return m_pMpe->Begin(); | ||||
4532 | } | ||||
4533 | |||||
4534 | |||||
4535 | /** | ||||
4536 | ************************************************************************** | ||||
4537 | * Name: CIccPcsStepSrcMatrix::CIccPcsStepSrcMatrix | ||||
4538 | * | ||||
4539 | * Purpose: | ||||
4540 | * Constructor | ||||
4541 | ************************************************************************** | ||||
4542 | */ | ||||
4543 | CIccPcsStepSrcMatrix::CIccPcsStepSrcMatrix(icUInt16Number nRows, icUInt16Number nCols) | ||||
4544 | { | ||||
4545 | m_nRows = nRows; | ||||
4546 | m_nCols = nCols; | ||||
4547 | m_vals = new icFloatNumber[nCols]; | ||||
4548 | } | ||||
4549 | |||||
4550 | |||||
4551 | /** | ||||
4552 | ************************************************************************** | ||||
4553 | * Name: CIccPcsStepSrcMatrix::~CIccPcsStepSrcMatrix | ||||
4554 | * | ||||
4555 | * Purpose: | ||||
4556 | * Destructor | ||||
4557 | ************************************************************************** | ||||
4558 | */ | ||||
4559 | CIccPcsStepSrcMatrix::~CIccPcsStepSrcMatrix() | ||||
4560 | { | ||||
4561 | if (m_vals) | ||||
4562 | delete m_vals; | ||||
4563 | } | ||||
4564 | |||||
4565 | |||||
4566 | /** | ||||
4567 | ************************************************************************** | ||||
4568 | * Name: CIccPcsStepSrcMatrix::Apply | ||||
4569 | * | ||||
4570 | * Purpose: | ||||
4571 | * Multiplies illuminant stored in m_vals by pSrc matrix passed in resulting | ||||
4572 | * in a pDst vector | ||||
4573 | ************************************************************************** | ||||
4574 | */ | ||||
4575 | void CIccPcsStepSrcMatrix::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
4576 | { | ||||
4577 | int i, j; | ||||
4578 | const icFloatNumber *row = pSrc; | ||||
4579 | for (j=0; j<m_nRows; j++) { | ||||
4580 | pDst[j] = 0.0f; | ||||
4581 | for (i=0; i<m_nCols; i++) { | ||||
4582 | pDst[j] += row[i] * m_vals[i]; | ||||
4583 | } | ||||
4584 | row += m_nCols; | ||||
4585 | } | ||||
4586 | } | ||||
4587 | |||||
4588 | |||||
4589 | /** | ||||
4590 | ************************************************************************** | ||||
4591 | * Name: CIccPcsStepSrcMatrix::dump | ||||
4592 | * | ||||
4593 | * Purpose: | ||||
4594 | * dumps the context of the step | ||||
4595 | ************************************************************************** | ||||
4596 | */ | ||||
4597 | void CIccPcsStepSrcMatrix::dump(std::string &str) const | ||||
4598 | { | ||||
4599 | str += "\nCIccPcsStepSrcMatrix\n\n"; | ||||
4600 | char buf[80]; | ||||
4601 | for (int i=0; i<m_nCols; i++) { | ||||
4602 | sprintf(buf, ICCPCSSTEPDUMPFMT" %.8f", m_vals[i]); | ||||
4603 | str += buf; | ||||
4604 | } | ||||
4605 | str += "\n"; | ||||
4606 | } | ||||
4607 | |||||
4608 | |||||
4609 | /** | ||||
4610 | ************************************************************************** | ||||
4611 | * Name: CIccPcsStepSparseMatrix::CIccPcsStepSparseMatrix | ||||
4612 | * | ||||
4613 | * Purpose: | ||||
4614 | * Constructor | ||||
4615 | ************************************************************************** | ||||
4616 | */ | ||||
4617 | CIccPcsStepSparseMatrix::CIccPcsStepSparseMatrix(icUInt16Number nRows, icUInt16Number nCols, icUInt32Number nBytesPerMatrix) | ||||
4618 | { | ||||
4619 | m_nRows = nRows; | ||||
4620 | m_nCols = nCols; | ||||
4621 | m_nBytesPerMatrix = nBytesPerMatrix; | ||||
4622 | |||||
4623 | m_vals = new icFloatNumber[m_nBytesPerMatrix/sizeof(icFloatNumber)]; | ||||
4624 | } | ||||
4625 | |||||
4626 | |||||
4627 | /** | ||||
4628 | ************************************************************************** | ||||
4629 | * Name: CIccPcsStepSparseMatrix::~CIccPcsStepSparseMatrix | ||||
4630 | * | ||||
4631 | * Purpose: | ||||
4632 | * Destructor | ||||
4633 | ************************************************************************** | ||||
4634 | */ | ||||
4635 | CIccPcsStepSparseMatrix::~CIccPcsStepSparseMatrix() | ||||
4636 | { | ||||
4637 | if (m_vals) | ||||
4638 | delete [] m_vals; | ||||
4639 | } | ||||
4640 | |||||
4641 | |||||
4642 | /** | ||||
4643 | ************************************************************************** | ||||
4644 | * Name: CIccPcsStepSparseMatrix::Apply | ||||
4645 | * | ||||
4646 | * Purpose: | ||||
4647 | * Multiplies illuminant stored in m_vals by pSrc matrix passed in resulting | ||||
4648 | * in a pDst vector | ||||
4649 | ************************************************************************** | ||||
4650 | */ | ||||
4651 | void CIccPcsStepSparseMatrix::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
4652 | { | ||||
4653 | CIccSparseMatrix mtx((icUInt8Number*)m_vals, m_nBytesPerMatrix, icSparseMatrixFloatNum((icSparseMatrixType)0x0000), true); | ||||
4654 | |||||
4655 | mtx.MultiplyVector(pDst, pSrc); | ||||
4656 | } | ||||
4657 | |||||
4658 | |||||
4659 | /** | ||||
4660 | ************************************************************************** | ||||
4661 | * Name: CIccPcsStepSparseMatrix::dump | ||||
4662 | * | ||||
4663 | * Purpose: | ||||
4664 | * dumps the context of the step | ||||
4665 | ************************************************************************** | ||||
4666 | */ | ||||
4667 | void CIccPcsStepSparseMatrix::dump(std::string &str) const | ||||
4668 | { | ||||
4669 | str += "\nCIccPcsStepSparseMatrix\n\n"; | ||||
4670 | // char buf[80]; | ||||
4671 | // for (int i=0; i<m_nCols; i++) { | ||||
4672 | // sprintf(buf, ICCPCSSTEPDUMPFMT, m_vals[i]); | ||||
4673 | // str += buf; | ||||
4674 | // } | ||||
4675 | // str += "\n"; | ||||
4676 | } | ||||
4677 | |||||
4678 | |||||
4679 | /** | ||||
4680 | ************************************************************************** | ||||
4681 | * Name: CIccPcsStepSrcSparseMatrix::CIccPcsStepSrcSparseMatrix | ||||
4682 | * | ||||
4683 | * Purpose: | ||||
4684 | * Constructor | ||||
4685 | ************************************************************************** | ||||
4686 | */ | ||||
4687 | CIccPcsStepSrcSparseMatrix::CIccPcsStepSrcSparseMatrix(icUInt16Number nRows, icUInt16Number nCols, icUInt16Number nChannels) | ||||
4688 | { | ||||
4689 | m_nRows = nRows; | ||||
4690 | m_nCols = nCols; | ||||
4691 | m_nChannels = nChannels; | ||||
4692 | m_nBytesPerMatrix = nChannels * sizeof(icFloatNumber); | ||||
4693 | |||||
4694 | m_vals = new icFloatNumber[nCols]; | ||||
4695 | } | ||||
4696 | |||||
4697 | |||||
4698 | /** | ||||
4699 | ************************************************************************** | ||||
4700 | * Name: CIccPcsStepSrcSparseMatrix::~CIccPcsSrcStepSparseMatrix | ||||
4701 | * | ||||
4702 | * Purpose: | ||||
4703 | * Destructor | ||||
4704 | ************************************************************************** | ||||
4705 | */ | ||||
4706 | CIccPcsStepSrcSparseMatrix::~CIccPcsStepSrcSparseMatrix() | ||||
4707 | { | ||||
4708 | if (m_vals) | ||||
4709 | delete [] m_vals; | ||||
4710 | } | ||||
4711 | |||||
4712 | |||||
4713 | /** | ||||
4714 | ************************************************************************** | ||||
4715 | * Name: CIccPcsStepSrcSparseMatrix::Apply | ||||
4716 | * | ||||
4717 | * Purpose: | ||||
4718 | * Multiplies illuminant stored in m_vals by pSrc matrix passed in resulting | ||||
4719 | * in a pDst vector | ||||
4720 | ************************************************************************** | ||||
4721 | */ | ||||
4722 | void CIccPcsStepSrcSparseMatrix::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | ||||
4723 | { | ||||
4724 | CIccSparseMatrix mtx((icUInt8Number*)pSrc, m_nBytesPerMatrix, icSparseMatrixFloatNum((icSparseMatrixType)0x0000), true); | ||||
4725 | |||||
4726 | mtx.MultiplyVector(pDst, m_vals); | ||||
4727 | } | ||||
4728 | |||||
4729 | |||||
4730 | /** | ||||
4731 | ************************************************************************** | ||||
4732 | * Name: CIccPcsStepSrcSparseMatrix::dump | ||||
4733 | * | ||||
4734 | * Purpose: | ||||
4735 | * dumps the context of the step | ||||
4736 | ************************************************************************** | ||||
4737 | */ | ||||
4738 | void CIccPcsStepSrcSparseMatrix::dump(std::string &str) const | ||||
4739 | { | ||||
4740 | str += "\nCIccPcsStepSrcSparseMatrix\n\n"; | ||||
4741 | char buf[80]; | ||||
4742 | for (int i=0; i<m_nCols; i++) { | ||||
4743 | sprintf(buf, ICCPCSSTEPDUMPFMT" %.8f", m_vals[i]); | ||||
4744 | str += buf; | ||||
4745 | } | ||||
4746 | str += "\n"; | ||||
4747 | } | ||||
4748 | |||||
4749 | |||||
4750 | /** | ||||
4751 | ************************************************************************** | ||||
4752 | * Name: CIccXformMonochrome::CIccXformMonochrome | ||||
4753 | * | ||||
4754 | * Purpose: | ||||
4755 | * Constructor | ||||
4756 | ************************************************************************** | ||||
4757 | */ | ||||
4758 | CIccXformMonochrome::CIccXformMonochrome() | ||||
4759 | { | ||||
4760 | m_Curve = NULL__null; | ||||
4761 | m_ApplyCurvePtr = NULL__null; | ||||
4762 | m_bFreeCurve = false; | ||||
4763 | } | ||||
4764 | |||||
4765 | /** | ||||
4766 | ************************************************************************** | ||||
4767 | * Name: CIccXformMonochrome::~CIccXformMonochrome | ||||
4768 | * | ||||
4769 | * Purpose: | ||||
4770 | * Destructor | ||||
4771 | ************************************************************************** | ||||
4772 | */ | ||||
4773 | CIccXformMonochrome::~CIccXformMonochrome() | ||||
4774 | { | ||||
4775 | if (m_bFreeCurve && m_Curve) { | ||||
4776 | delete m_Curve; | ||||
4777 | } | ||||
4778 | } | ||||
4779 | |||||
4780 | /** | ||||
4781 | ************************************************************************** | ||||
4782 | * Name: CIccXformMonochrome::Begin | ||||
4783 | * | ||||
4784 | * Purpose: | ||||
4785 | * Does the initialization of the Xform before Apply() is called. | ||||
4786 | * Must be called before Apply(). | ||||
4787 | * | ||||
4788 | ************************************************************************** | ||||
4789 | */ | ||||
4790 | icStatusCMM CIccXformMonochrome::Begin() | ||||
4791 | { | ||||
4792 | icStatusCMM status; | ||||
4793 | |||||
4794 | status = CIccXform::Begin(); | ||||
4795 | if (status != icCmmStatOk) | ||||
4796 | return status; | ||||
4797 | |||||
4798 | m_ApplyCurvePtr = NULL__null; | ||||
4799 | |||||
4800 | if (m_bInput) { | ||||
4801 | m_Curve = GetCurve(icSigGrayTRCTag); | ||||
4802 | |||||
4803 | if (!m_Curve) { | ||||
4804 | return icCmmStatProfileMissingTag; | ||||
4805 | } | ||||
4806 | } | ||||
4807 | else { | ||||
4808 | m_Curve = GetInvCurve(icSigGrayTRCTag); | ||||
4809 | m_bFreeCurve = true; | ||||
4810 | |||||
4811 | if (!m_Curve) { | ||||
4812 | return icCmmStatProfileMissingTag; | ||||
4813 | } | ||||
4814 | } | ||||
4815 | |||||
4816 | m_Curve->Begin(); | ||||
4817 | if (!m_Curve->IsIdentity()) { | ||||
4818 | m_ApplyCurvePtr = m_Curve; | ||||
4819 | } | ||||
4820 | |||||
4821 | return icCmmStatOk; | ||||
4822 | } | ||||
4823 | |||||
4824 | /** | ||||
4825 | ************************************************************************** | ||||
4826 | * Name: CIccXformMonochrome::Apply | ||||
4827 | * | ||||
4828 | * Purpose: | ||||
4829 | * Does the actual application of the Xform. | ||||
4830 | * | ||||
4831 | * Args: | ||||
4832 | * pApply = ApplyXform object containing temporary storage used during Apply | ||||
4833 | * DstPixel = Destination pixel where the result is stored, | ||||
4834 | * SrcPixel = Source pixel which is to be applied. | ||||
4835 | ************************************************************************** | ||||
4836 | */ | ||||
4837 | void CIccXformMonochrome::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | ||||
4838 | { | ||||
4839 | icFloatNumber Pixel[3]; | ||||
4840 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | ||||
4841 | |||||
4842 | if (m_bInput) { | ||||
4843 | Pixel[0] = SrcPixel[0]; | ||||
4844 | |||||
4845 | if (m_ApplyCurvePtr) { | ||||
4846 | Pixel[0] = m_ApplyCurvePtr->Apply(Pixel[0]); | ||||
4847 | } | ||||
4848 | |||||
4849 | DstPixel[0] = icFloatNumber(icPerceptualRefWhiteX0.9642); | ||||
4850 | DstPixel[1] = icFloatNumber(icPerceptualRefWhiteY1.0000); | ||||
4851 | DstPixel[2] = icFloatNumber(icPerceptualRefWhiteZ0.8249); | ||||
4852 | |||||
4853 | icXyzToPcs(DstPixel); | ||||
4854 | |||||
4855 | if (m_pProfile->m_Header.pcs==icSigLabData) { | ||||
4856 | if (UseLegacyPCS()) { | ||||
4857 | CIccPCS::XyzToLab2(DstPixel, DstPixel, true); | ||||
4858 | } | ||||
4859 | else { | ||||
4860 | CIccPCS::XyzToLab(DstPixel, DstPixel, true); | ||||
4861 | } | ||||
4862 | } | ||||
4863 | |||||
4864 | DstPixel[0] *= Pixel[0]; | ||||
4865 | DstPixel[1] *= Pixel[0]; | ||||
4866 | DstPixel[2] *= Pixel[0]; | ||||
4867 | } | ||||
4868 | else { | ||||
4869 | Pixel[0] = icFloatNumber(icPerceptualRefWhiteX0.9642); | ||||
4870 | Pixel[1] = icFloatNumber(icPerceptualRefWhiteY1.0000); | ||||
4871 | Pixel[2] = icFloatNumber(icPerceptualRefWhiteZ0.8249); | ||||
4872 | |||||
4873 | icXyzToPcs(Pixel); | ||||
4874 | |||||
4875 | if (m_pProfile->m_Header.pcs==icSigLabData) { | ||||
4876 | if (UseLegacyPCS()) { | ||||
4877 | CIccPCS::XyzToLab2(Pixel, Pixel, true); | ||||
4878 | } | ||||
4879 | else { | ||||
4880 | CIccPCS::XyzToLab(Pixel, Pixel, true); | ||||
4881 | } | ||||
4882 | DstPixel[0] = SrcPixel[0]/Pixel[0]; | ||||
4883 | } | ||||
4884 | else { | ||||
4885 | DstPixel[0] = SrcPixel[1]/Pixel[1]; | ||||
4886 | } | ||||
4887 | |||||
4888 | if (m_ApplyCurvePtr) { | ||||
4889 | DstPixel[0] = m_ApplyCurvePtr->Apply(DstPixel[0]); | ||||
4890 | } | ||||
4891 | } | ||||
4892 | |||||
4893 | CheckDstAbs(DstPixel); | ||||
4894 | } | ||||
4895 | |||||
4896 | /** | ||||
4897 | ************************************************************************** | ||||
4898 | * Name: CIccXformMonochrome::GetCurve | ||||
4899 | * | ||||
4900 | * Purpose: | ||||
4901 | * Gets the curve having the passed signature, from the profile. | ||||
4902 | * | ||||
4903 | * Args: | ||||
4904 | * sig = signature of the curve to be found | ||||
4905 | * | ||||
4906 | * Return: | ||||
4907 | * Pointer to the curve. | ||||
4908 | ************************************************************************** | ||||
4909 | */ | ||||
4910 | CIccCurve *CIccXformMonochrome::GetCurve(icSignature sig) const | ||||
4911 | { | ||||
4912 | CIccTag *pTag = m_pProfile->FindTag(sig); | ||||
4913 | |||||
4914 | if (pTag && (pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType)) { | ||||
4915 | return (CIccCurve*)pTag; | ||||
4916 | } | ||||
4917 | |||||
4918 | return NULL__null; | ||||
4919 | } | ||||
4920 | |||||
4921 | /** | ||||
4922 | ************************************************************************** | ||||
4923 | * Name: CIccXformMonochrome::GetInvCurve | ||||
4924 | * | ||||
4925 | * Purpose: | ||||
4926 | * Gets the inverted curve having the passed signature, from the profile. | ||||
4927 | * | ||||
4928 | * Args: | ||||
4929 | * sig = signature of the curve to be inverted | ||||
4930 | * | ||||
4931 | * Return: | ||||
4932 | * Pointer to the inverted curve. | ||||
4933 | ************************************************************************** | ||||
4934 | */ | ||||
4935 | CIccCurve *CIccXformMonochrome::GetInvCurve(icSignature sig) const | ||||
4936 | { | ||||
4937 | CIccCurve *pCurve; | ||||
4938 | CIccTagCurve *pInvCurve; | ||||
4939 | |||||
4940 | if (!(pCurve = GetCurve(sig))) | ||||
4941 | return NULL__null; | ||||
4942 | |||||
4943 | pCurve->Begin(); | ||||
4944 | |||||
4945 | pInvCurve = new CIccTagCurve(2048); | ||||
4946 | |||||
4947 | int i; | ||||
4948 | icFloatNumber x; | ||||
4949 | icFloatNumber *Lut = &(*pInvCurve)[0]; | ||||
4950 | |||||
4951 | for (i=0; i<2048; i++) { | ||||
4952 | x=(icFloatNumber)i / 2047; | ||||
4953 | |||||
4954 | Lut[i] = pCurve->Find(x); | ||||
4955 | } | ||||
4956 | |||||
4957 | return pInvCurve; | ||||
4958 | } | ||||
4959 | |||||
4960 | /** | ||||
4961 | ************************************************************************** | ||||
4962 | * Name: CIccXformMonochrome::ExtractInputCurves | ||||
4963 | * | ||||
4964 | * Purpose: | ||||
4965 | * Gets the input curves. Should be called only after Begin() | ||||
4966 | * has been called. Once the curves are extracted, they will | ||||
4967 | * not be used by the Apply() function. | ||||
4968 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
4969 | * | ||||
4970 | * Return: | ||||
4971 | * Pointer to the input curves. | ||||
4972 | ************************************************************************** | ||||
4973 | */ | ||||
4974 | LPIccCurve* CIccXformMonochrome::ExtractInputCurves() | ||||
4975 | { | ||||
4976 | if (m_bInput) { | ||||
4977 | if (m_Curve) { | ||||
4978 | LPIccCurve* Curve = new LPIccCurve[1]; | ||||
4979 | Curve[0] = (LPIccCurve)(m_Curve->NewCopy()); | ||||
4980 | m_ApplyCurvePtr = NULL__null; | ||||
4981 | return Curve; | ||||
4982 | } | ||||
4983 | } | ||||
4984 | |||||
4985 | return NULL__null; | ||||
4986 | } | ||||
4987 | |||||
4988 | /** | ||||
4989 | ************************************************************************** | ||||
4990 | * Name: CIccXformMonochrome::ExtractOutputCurves | ||||
4991 | * | ||||
4992 | * Purpose: | ||||
4993 | * Gets the output curves. Should be called only after Begin() | ||||
4994 | * has been called. Once the curves are extracted, they will | ||||
4995 | * not be used by the Apply() function. | ||||
4996 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
4997 | * | ||||
4998 | * Return: | ||||
4999 | * Pointer to the output curves. | ||||
5000 | ************************************************************************** | ||||
5001 | */ | ||||
5002 | LPIccCurve* CIccXformMonochrome::ExtractOutputCurves() | ||||
5003 | { | ||||
5004 | if (!m_bInput) { | ||||
5005 | if (m_Curve) { | ||||
5006 | LPIccCurve* Curve = new LPIccCurve[1]; | ||||
5007 | Curve[0] = (LPIccCurve)(m_Curve->NewCopy()); | ||||
5008 | m_ApplyCurvePtr = NULL__null; | ||||
5009 | return Curve; | ||||
5010 | } | ||||
5011 | } | ||||
5012 | |||||
5013 | return NULL__null; | ||||
5014 | } | ||||
5015 | |||||
5016 | /** | ||||
5017 | ************************************************************************** | ||||
5018 | * Name: CIccXformMatrixTRC::CIccXformMatrixTRC | ||||
5019 | * | ||||
5020 | * Purpose: | ||||
5021 | * Constructor | ||||
5022 | ************************************************************************** | ||||
5023 | */ | ||||
5024 | CIccXformMatrixTRC::CIccXformMatrixTRC() | ||||
5025 | { | ||||
5026 | m_Curve[0] = m_Curve[1] = m_Curve[2] = NULL__null; | ||||
5027 | m_ApplyCurvePtr = NULL__null; | ||||
5028 | m_bFreeCurve = false; | ||||
5029 | } | ||||
5030 | |||||
5031 | /** | ||||
5032 | ************************************************************************** | ||||
5033 | * Name: CIccXformMatrixTRC::~CIccXformMatrixTRC | ||||
5034 | * | ||||
5035 | * Purpose: | ||||
5036 | * Destructor | ||||
5037 | ************************************************************************** | ||||
5038 | */ | ||||
5039 | CIccXformMatrixTRC::~CIccXformMatrixTRC() | ||||
5040 | { | ||||
5041 | if (m_bFreeCurve) { | ||||
5042 | if (m_Curve[0]) | ||||
5043 | delete m_Curve[0]; | ||||
5044 | if (m_Curve[1]) | ||||
5045 | delete m_Curve[1]; | ||||
5046 | if (m_Curve[2]) | ||||
5047 | delete m_Curve[2]; | ||||
5048 | } | ||||
5049 | } | ||||
5050 | |||||
5051 | /** | ||||
5052 | ************************************************************************** | ||||
5053 | * Name: CIccXformMatrixTRC::Begin | ||||
5054 | * | ||||
5055 | * Purpose: | ||||
5056 | * Does the initialization of the Xform before Apply() is called. | ||||
5057 | * Must be called before Apply(). | ||||
5058 | * | ||||
5059 | ************************************************************************** | ||||
5060 | */ | ||||
5061 | icStatusCMM CIccXformMatrixTRC::Begin() | ||||
5062 | { | ||||
5063 | icStatusCMM status; | ||||
5064 | const CIccTagXYZ *pXYZ; | ||||
5065 | |||||
5066 | status = CIccXform::Begin(); | ||||
5067 | if (status != icCmmStatOk) | ||||
5068 | return status; | ||||
5069 | |||||
5070 | pXYZ = GetColumn(icSigRedMatrixColumnTag); | ||||
5071 | if (!pXYZ) { | ||||
5072 | return icCmmStatProfileMissingTag; | ||||
5073 | } | ||||
5074 | |||||
5075 | m_e[0] = icFtoD((*pXYZ)[0].X); | ||||
5076 | m_e[3] = icFtoD((*pXYZ)[0].Y); | ||||
5077 | m_e[6] = icFtoD((*pXYZ)[0].Z); | ||||
5078 | |||||
5079 | pXYZ = GetColumn(icSigGreenMatrixColumnTag); | ||||
5080 | if (!pXYZ) { | ||||
5081 | return icCmmStatProfileMissingTag; | ||||
5082 | } | ||||
5083 | |||||
5084 | m_e[1] = icFtoD((*pXYZ)[0].X); | ||||
5085 | m_e[4] = icFtoD((*pXYZ)[0].Y); | ||||
5086 | m_e[7] = icFtoD((*pXYZ)[0].Z); | ||||
5087 | |||||
5088 | pXYZ = GetColumn(icSigBlueMatrixColumnTag); | ||||
5089 | if (!pXYZ) { | ||||
5090 | return icCmmStatProfileMissingTag; | ||||
5091 | } | ||||
5092 | |||||
5093 | m_e[2] = icFtoD((*pXYZ)[0].X); | ||||
5094 | m_e[5] = icFtoD((*pXYZ)[0].Y); | ||||
5095 | m_e[8] = icFtoD((*pXYZ)[0].Z); | ||||
5096 | |||||
5097 | m_ApplyCurvePtr = NULL__null; | ||||
5098 | |||||
5099 | if (m_bInput) { | ||||
5100 | m_Curve[0] = GetCurve(icSigRedTRCTag); | ||||
5101 | m_Curve[1] = GetCurve(icSigGreenTRCTag); | ||||
5102 | m_Curve[2] = GetCurve(icSigBlueTRCTag); | ||||
5103 | |||||
5104 | if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) { | ||||
5105 | return icCmmStatProfileMissingTag; | ||||
5106 | } | ||||
5107 | |||||
5108 | } | ||||
5109 | else { | ||||
5110 | if (m_pProfile->m_Header.pcs!=icSigXYZData) { | ||||
5111 | return icCmmStatBadSpaceLink; | ||||
5112 | } | ||||
5113 | |||||
5114 | m_Curve[0] = GetInvCurve(icSigRedTRCTag); | ||||
5115 | m_Curve[1] = GetInvCurve(icSigGreenTRCTag); | ||||
5116 | m_Curve[2] = GetInvCurve(icSigBlueTRCTag); | ||||
5117 | |||||
5118 | m_bFreeCurve = true; | ||||
5119 | |||||
5120 | if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) { | ||||
5121 | return icCmmStatProfileMissingTag; | ||||
5122 | } | ||||
5123 | |||||
5124 | if (!icMatrixInvert3x3(m_e)) { | ||||
5125 | return icCmmStatInvalidProfile; | ||||
5126 | } | ||||
5127 | } | ||||
5128 | |||||
5129 | m_Curve[0]->Begin(); | ||||
5130 | m_Curve[1]->Begin(); | ||||
5131 | m_Curve[2]->Begin(); | ||||
5132 | |||||
5133 | if (!m_Curve[0]->IsIdentity() || !m_Curve[1]->IsIdentity() || !m_Curve[2]->IsIdentity()) { | ||||
5134 | m_ApplyCurvePtr = m_Curve; | ||||
5135 | } | ||||
5136 | |||||
5137 | return icCmmStatOk; | ||||
5138 | } | ||||
5139 | |||||
5140 | |||||
5141 | static icFloatNumber XYZScale(icFloatNumber v) | ||||
5142 | { | ||||
5143 | v = (icFloatNumber)(v * 32768.0 / 65535.0); | ||||
5144 | return v; | ||||
5145 | } | ||||
5146 | |||||
5147 | static icFloatNumber XYZDescale(icFloatNumber v) | ||||
5148 | { | ||||
5149 | return (icFloatNumber)(v * 65535.0 / 32768.0); | ||||
5150 | } | ||||
5151 | |||||
5152 | static icFloatNumber RGBClip(icFloatNumber v, CIccCurve *pCurve) | ||||
5153 | { | ||||
5154 | if (v<=0) | ||||
5155 | return(pCurve->Apply(0)); | ||||
5156 | else if (v>=1.0) | ||||
5157 | return (pCurve->Apply(1.0)); | ||||
5158 | |||||
5159 | return pCurve->Apply(v); | ||||
5160 | } | ||||
5161 | |||||
5162 | /** | ||||
5163 | ************************************************************************** | ||||
5164 | * Name: CIccXformMatrixTRC::Apply | ||||
5165 | * | ||||
5166 | * Purpose: | ||||
5167 | * Does the actual application of the Xform. | ||||
5168 | * | ||||
5169 | * Args: | ||||
5170 | * pApply = ApplyXform object containging temporary storage used during Apply | ||||
5171 | * DstPixel = Destination pixel where the result is stored, | ||||
5172 | * SrcPixel = Source pixel which is to be applied. | ||||
5173 | ************************************************************************** | ||||
5174 | */ | ||||
5175 | void CIccXformMatrixTRC::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | ||||
5176 | { | ||||
5177 | icFloatNumber Pixel[3]; | ||||
5178 | |||||
5179 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | ||||
5180 | Pixel[0] = SrcPixel[0]; | ||||
5181 | Pixel[1] = SrcPixel[1]; | ||||
5182 | Pixel[2] = SrcPixel[2]; | ||||
5183 | |||||
5184 | if (m_bInput) { | ||||
5185 | |||||
5186 | double LinR, LinG, LinB; | ||||
5187 | if (m_ApplyCurvePtr) { | ||||
5188 | LinR = m_ApplyCurvePtr[0]->Apply(Pixel[0]); | ||||
5189 | LinG = m_ApplyCurvePtr[1]->Apply(Pixel[1]); | ||||
5190 | LinB = m_ApplyCurvePtr[2]->Apply(Pixel[2]); | ||||
5191 | } | ||||
5192 | else { | ||||
5193 | LinR = Pixel[0]; | ||||
5194 | LinG = Pixel[1]; | ||||
5195 | LinB = Pixel[2]; | ||||
5196 | } | ||||
5197 | |||||
5198 | DstPixel[0] = XYZScale((icFloatNumber)(m_e[0] * LinR + m_e[1] * LinG + m_e[2] * LinB)); | ||||
5199 | DstPixel[1] = XYZScale((icFloatNumber)(m_e[3] * LinR + m_e[4] * LinG + m_e[5] * LinB)); | ||||
5200 | DstPixel[2] = XYZScale((icFloatNumber)(m_e[6] * LinR + m_e[7] * LinG + m_e[8] * LinB)); | ||||
5201 | } | ||||
5202 | else { | ||||
5203 | double X = XYZDescale(Pixel[0]); | ||||
5204 | double Y = XYZDescale(Pixel[1]); | ||||
5205 | double Z = XYZDescale(Pixel[2]); | ||||
5206 | |||||
5207 | if (m_ApplyCurvePtr) { | ||||
5208 | DstPixel[0] = RGBClip((icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z), m_ApplyCurvePtr[0]); | ||||
5209 | DstPixel[1] = RGBClip((icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z), m_ApplyCurvePtr[1]); | ||||
5210 | DstPixel[2] = RGBClip((icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z), m_ApplyCurvePtr[2]); | ||||
5211 | } | ||||
5212 | else { | ||||
5213 | DstPixel[0] = (icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z); | ||||
5214 | DstPixel[1] = (icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z); | ||||
5215 | DstPixel[2] = (icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z); | ||||
5216 | } | ||||
5217 | } | ||||
5218 | |||||
5219 | CheckDstAbs(DstPixel); | ||||
5220 | } | ||||
5221 | |||||
5222 | /** | ||||
5223 | ************************************************************************** | ||||
5224 | * Name: CIccXformMatrixTRC::GetCurve | ||||
5225 | * | ||||
5226 | * Purpose: | ||||
5227 | * Gets the curve having the passed signature, from the profile. | ||||
5228 | * | ||||
5229 | * Args: | ||||
5230 | * sig = signature of the curve to be found | ||||
5231 | * | ||||
5232 | * Return: | ||||
5233 | * Pointer to the curve. | ||||
5234 | ************************************************************************** | ||||
5235 | */ | ||||
5236 | CIccCurve *CIccXformMatrixTRC::GetCurve(icSignature sig) const | ||||
5237 | { | ||||
5238 | CIccTag *pTag = m_pProfile->FindTag(sig); | ||||
5239 | |||||
5240 | if (pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType) { | ||||
5241 | return (CIccCurve*)pTag; | ||||
5242 | } | ||||
5243 | |||||
5244 | return NULL__null; | ||||
5245 | } | ||||
5246 | |||||
5247 | /** | ||||
5248 | ************************************************************************** | ||||
5249 | * Name: CIccXformMatrixTRC::GetColumn | ||||
5250 | * | ||||
5251 | * Purpose: | ||||
5252 | * Gets the XYZ tag from the profile. | ||||
5253 | * | ||||
5254 | * Args: | ||||
5255 | * sig = signature of the XYZ tag to be found. | ||||
5256 | * | ||||
5257 | * Return: | ||||
5258 | * Pointer to the XYZ tag. | ||||
5259 | ************************************************************************** | ||||
5260 | */ | ||||
5261 | CIccTagXYZ *CIccXformMatrixTRC::GetColumn(icSignature sig) const | ||||
5262 | { | ||||
5263 | CIccTag *pTag = m_pProfile->FindTag(sig); | ||||
5264 | |||||
5265 | if (!pTag || pTag->GetType()!=icSigXYZType) { | ||||
5266 | return NULL__null; | ||||
5267 | } | ||||
5268 | |||||
5269 | return (CIccTagXYZ*)pTag; | ||||
5270 | } | ||||
5271 | |||||
5272 | /** | ||||
5273 | ************************************************************************** | ||||
5274 | * Name: CIccXformMatrixTRC::GetInvCurve | ||||
5275 | * | ||||
5276 | * Purpose: | ||||
5277 | * Gets the inverted curve having the passed signature, from the profile. | ||||
5278 | * | ||||
5279 | * Args: | ||||
5280 | * sig = signature of the curve to be inverted | ||||
5281 | * | ||||
5282 | * Return: | ||||
5283 | * Pointer to the inverted curve. | ||||
5284 | ************************************************************************** | ||||
5285 | */ | ||||
5286 | CIccCurve *CIccXformMatrixTRC::GetInvCurve(icSignature sig) const | ||||
5287 | { | ||||
5288 | CIccCurve *pCurve; | ||||
5289 | CIccTagCurve *pInvCurve; | ||||
5290 | |||||
5291 | if (!(pCurve = GetCurve(sig))) | ||||
5292 | return NULL__null; | ||||
5293 | |||||
5294 | pCurve->Begin(); | ||||
5295 | |||||
5296 | pInvCurve = new CIccTagCurve(2048); | ||||
5297 | |||||
5298 | int i; | ||||
5299 | icFloatNumber x; | ||||
5300 | icFloatNumber *Lut = &(*pInvCurve)[0]; | ||||
5301 | |||||
5302 | for (i=0; i<2048; i++) { | ||||
5303 | x=(icFloatNumber)i / 2047; | ||||
5304 | |||||
5305 | Lut[i] = pCurve->Find(x); | ||||
5306 | } | ||||
5307 | |||||
5308 | return pInvCurve; | ||||
5309 | } | ||||
5310 | |||||
5311 | /** | ||||
5312 | ************************************************************************** | ||||
5313 | * Name: CIccXformMatrixTRC::ExtractInputCurves | ||||
5314 | * | ||||
5315 | * Purpose: | ||||
5316 | * Gets the input curves. Should be called only after Begin() | ||||
5317 | * has been called. Once the curves are extracted, they will | ||||
5318 | * not be used by the Apply() function. | ||||
5319 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
5320 | * | ||||
5321 | * Return: | ||||
5322 | * Pointer to the input curves. | ||||
5323 | ************************************************************************** | ||||
5324 | */ | ||||
5325 | LPIccCurve* CIccXformMatrixTRC::ExtractInputCurves() | ||||
5326 | { | ||||
5327 | if (m_bInput) { | ||||
5328 | if (m_Curve[0]) { | ||||
5329 | LPIccCurve* Curve = new LPIccCurve[3]; | ||||
5330 | Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy()); | ||||
5331 | Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy()); | ||||
5332 | Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy()); | ||||
5333 | m_ApplyCurvePtr = NULL__null; | ||||
5334 | return Curve; | ||||
5335 | } | ||||
5336 | } | ||||
5337 | |||||
5338 | return NULL__null; | ||||
5339 | } | ||||
5340 | |||||
5341 | /** | ||||
5342 | ************************************************************************** | ||||
5343 | * Name: CIccXformMatrixTRC::ExtractOutputCurves | ||||
5344 | * | ||||
5345 | * Purpose: | ||||
5346 | * Gets the output curves. Should be called only after Begin() | ||||
5347 | * has been called. Once the curves are extracted, they will | ||||
5348 | * not be used by the Apply() function. | ||||
5349 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
5350 | * | ||||
5351 | * Return: | ||||
5352 | * Pointer to the output curves. | ||||
5353 | ************************************************************************** | ||||
5354 | */ | ||||
5355 | LPIccCurve* CIccXformMatrixTRC::ExtractOutputCurves() | ||||
5356 | { | ||||
5357 | if (!m_bInput) { | ||||
5358 | if (m_Curve[0]) { | ||||
5359 | LPIccCurve* Curve = new LPIccCurve[3]; | ||||
5360 | Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy()); | ||||
5361 | Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy()); | ||||
5362 | Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy()); | ||||
5363 | m_ApplyCurvePtr = NULL__null; | ||||
5364 | return Curve; | ||||
5365 | } | ||||
5366 | } | ||||
5367 | |||||
5368 | return NULL__null; | ||||
5369 | } | ||||
5370 | |||||
5371 | /** | ||||
5372 | ************************************************************************** | ||||
5373 | * Name: CIccXform3DLut::CIccXform3DLut | ||||
5374 | * | ||||
5375 | * Purpose: | ||||
5376 | * Constructor | ||||
5377 | * | ||||
5378 | * Args: | ||||
5379 | * pTag = Pointer to the tag of type CIccMBB | ||||
5380 | ************************************************************************** | ||||
5381 | */ | ||||
5382 | CIccXform3DLut::CIccXform3DLut(CIccTag *pTag) | ||||
5383 | { | ||||
5384 | if (pTag && pTag->IsMBBType()) { | ||||
5385 | m_pTag = (CIccMBB*)pTag; | ||||
5386 | } | ||||
5387 | else | ||||
5388 | m_pTag = NULL__null; | ||||
5389 | |||||
5390 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | ||||
5391 | m_ApplyMatrixPtr = NULL__null; | ||||
5392 | } | ||||
5393 | |||||
5394 | /** | ||||
5395 | ************************************************************************** | ||||
5396 | * Name: CIccXform3DLut::~CIccXform3DLut | ||||
5397 | * | ||||
5398 | * Purpose: | ||||
5399 | * Destructor | ||||
5400 | ************************************************************************** | ||||
5401 | */ | ||||
5402 | CIccXform3DLut::~CIccXform3DLut() | ||||
5403 | { | ||||
5404 | } | ||||
5405 | |||||
5406 | /** | ||||
5407 | ************************************************************************** | ||||
5408 | * Name: CIccXform3DLut::Begin | ||||
5409 | * | ||||
5410 | * Purpose: | ||||
5411 | * Does the initialization of the Xform before Apply() is called. | ||||
5412 | * Must be called before Apply(). | ||||
5413 | * | ||||
5414 | ************************************************************************** | ||||
5415 | */ | ||||
5416 | icStatusCMM CIccXform3DLut::Begin() | ||||
5417 | { | ||||
5418 | icStatusCMM status; | ||||
5419 | CIccCurve **Curve; | ||||
5420 | int i; | ||||
5421 | |||||
5422 | status = CIccXform::Begin(); | ||||
5423 | if (status != icCmmStatOk) | ||||
5424 | return status; | ||||
5425 | |||||
5426 | if (!m_pTag || | ||||
5427 | m_pTag->InputChannels()!=3) { | ||||
5428 | return icCmmStatInvalidLut; | ||||
5429 | } | ||||
5430 | |||||
5431 | m_ApplyCurvePtrA = NULL__null; | ||||
5432 | m_ApplyCurvePtrB = NULL__null; | ||||
5433 | m_ApplyCurvePtrM = NULL__null; | ||||
5434 | |||||
5435 | if (m_pTag->m_bInputMatrix) { | ||||
5436 | if (m_pTag->m_CurvesB) { | ||||
5437 | Curve = m_pTag->m_CurvesB; | ||||
5438 | |||||
5439 | Curve[0]->Begin(); | ||||
5440 | Curve[1]->Begin(); | ||||
5441 | Curve[2]->Begin(); | ||||
5442 | |||||
5443 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) { | ||||
5444 | m_ApplyCurvePtrB = Curve; | ||||
5445 | } | ||||
5446 | } | ||||
5447 | |||||
5448 | if (m_pTag->m_CurvesM) { | ||||
5449 | Curve = m_pTag->m_CurvesM; | ||||
5450 | |||||
5451 | Curve[0]->Begin(); | ||||
5452 | Curve[1]->Begin(); | ||||
5453 | Curve[2]->Begin(); | ||||
5454 | |||||
5455 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) { | ||||
5456 | m_ApplyCurvePtrM = Curve; | ||||
5457 | } | ||||
5458 | } | ||||
5459 | |||||
5460 | if (m_pTag->m_CLUT) { | ||||
5461 | m_pTag->m_CLUT->Begin(); | ||||
5462 | } | ||||
5463 | |||||
5464 | if (m_pTag->m_CurvesA) { | ||||
5465 | Curve = m_pTag->m_CurvesA; | ||||
5466 | |||||
5467 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5468 | Curve[i]->Begin(); | ||||
5469 | } | ||||
5470 | |||||
5471 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5472 | if (!Curve[i]->IsIdentity()) { | ||||
5473 | m_ApplyCurvePtrA = Curve; | ||||
5474 | break; | ||||
5475 | } | ||||
5476 | } | ||||
5477 | } | ||||
5478 | |||||
5479 | } | ||||
5480 | else { | ||||
5481 | if (m_pTag->m_CurvesA) { | ||||
5482 | Curve = m_pTag->m_CurvesA; | ||||
5483 | |||||
5484 | Curve[0]->Begin(); | ||||
5485 | Curve[1]->Begin(); | ||||
5486 | Curve[2]->Begin(); | ||||
5487 | |||||
5488 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) { | ||||
5489 | m_ApplyCurvePtrA = Curve; | ||||
5490 | } | ||||
5491 | } | ||||
5492 | |||||
5493 | if (m_pTag->m_CLUT) { | ||||
5494 | m_pTag->m_CLUT->Begin(); | ||||
5495 | } | ||||
5496 | |||||
5497 | if (m_pTag->m_CurvesM) { | ||||
5498 | Curve = m_pTag->m_CurvesM; | ||||
5499 | |||||
5500 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5501 | Curve[i]->Begin(); | ||||
5502 | } | ||||
5503 | |||||
5504 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5505 | if (!Curve[i]->IsIdentity()) { | ||||
5506 | m_ApplyCurvePtrM = Curve; | ||||
5507 | break; | ||||
5508 | } | ||||
5509 | } | ||||
5510 | } | ||||
5511 | |||||
5512 | if (m_pTag->m_CurvesB) { | ||||
5513 | Curve = m_pTag->m_CurvesB; | ||||
5514 | |||||
5515 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5516 | Curve[i]->Begin(); | ||||
5517 | } | ||||
5518 | |||||
5519 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5520 | if (!Curve[i]->IsIdentity()) { | ||||
5521 | m_ApplyCurvePtrB = Curve; | ||||
5522 | break; | ||||
5523 | } | ||||
5524 | } | ||||
5525 | } | ||||
5526 | } | ||||
5527 | |||||
5528 | m_ApplyMatrixPtr = NULL__null; | ||||
5529 | if (m_pTag->m_Matrix) { | ||||
5530 | if (m_pTag->m_bInputMatrix) { | ||||
5531 | if (m_pTag->m_nInput!=3) { | ||||
5532 | return icCmmStatInvalidProfile; | ||||
5533 | } | ||||
5534 | } | ||||
5535 | else { | ||||
5536 | if (m_pTag->m_nOutput!=3) { | ||||
5537 | return icCmmStatInvalidProfile; | ||||
5538 | } | ||||
5539 | } | ||||
5540 | |||||
5541 | if (!m_pTag->m_Matrix->IsIdentity()) { | ||||
5542 | m_ApplyMatrixPtr = m_pTag->m_Matrix; | ||||
5543 | } | ||||
5544 | } | ||||
5545 | |||||
5546 | return icCmmStatOk; | ||||
5547 | } | ||||
5548 | |||||
5549 | /** | ||||
5550 | ************************************************************************** | ||||
5551 | * Name: CIccXform3DLut::Apply | ||||
5552 | * | ||||
5553 | * Purpose: | ||||
5554 | * Does the actual application of the Xform. | ||||
5555 | * | ||||
5556 | * Args: | ||||
5557 | * pApply = ApplyXform object containing temporary storage used during Apply | ||||
5558 | * DstPixel = Destination pixel where the result is stored, | ||||
5559 | * SrcPixel = Source pixel which is to be applied. | ||||
5560 | ************************************************************************** | ||||
5561 | */ | ||||
5562 | void CIccXform3DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | ||||
5563 | { | ||||
5564 | icFloatNumber Pixel[16]; | ||||
5565 | int i; | ||||
5566 | |||||
5567 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | ||||
5568 | Pixel[0] = SrcPixel[0]; | ||||
5569 | Pixel[1] = SrcPixel[1]; | ||||
5570 | Pixel[2] = SrcPixel[2]; | ||||
5571 | |||||
5572 | if (m_pTag->m_bInputMatrix) { | ||||
5573 | if (m_ApplyCurvePtrB) { | ||||
5574 | Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]); | ||||
5575 | Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]); | ||||
5576 | Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]); | ||||
5577 | } | ||||
5578 | |||||
5579 | if (m_ApplyMatrixPtr) { | ||||
5580 | m_ApplyMatrixPtr->Apply(Pixel); | ||||
5581 | } | ||||
5582 | |||||
5583 | if (m_ApplyCurvePtrM) { | ||||
5584 | Pixel[0] = m_ApplyCurvePtrM[0]->Apply(Pixel[0]); | ||||
5585 | Pixel[1] = m_ApplyCurvePtrM[1]->Apply(Pixel[1]); | ||||
5586 | Pixel[2] = m_ApplyCurvePtrM[2]->Apply(Pixel[2]); | ||||
5587 | } | ||||
5588 | |||||
5589 | if (m_pTag->m_CLUT) { | ||||
5590 | if (m_nInterp==icInterpLinear) | ||||
5591 | m_pTag->m_CLUT->Interp3d(Pixel, Pixel); | ||||
5592 | else | ||||
5593 | m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel); | ||||
5594 | } | ||||
5595 | |||||
5596 | if (m_ApplyCurvePtrA) { | ||||
5597 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5598 | Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); | ||||
5599 | } | ||||
5600 | } | ||||
5601 | |||||
5602 | } | ||||
5603 | else { | ||||
5604 | if (m_ApplyCurvePtrA) { | ||||
5605 | Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]); | ||||
5606 | Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]); | ||||
5607 | Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]); | ||||
5608 | } | ||||
5609 | |||||
5610 | if (m_pTag->m_CLUT) { | ||||
5611 | if (m_nInterp==icInterpLinear) | ||||
5612 | m_pTag->m_CLUT->Interp3d(Pixel, Pixel); | ||||
5613 | else | ||||
5614 | m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel); | ||||
5615 | } | ||||
5616 | |||||
5617 | if (m_ApplyCurvePtrM) { | ||||
5618 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5619 | Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]); | ||||
5620 | } | ||||
5621 | } | ||||
5622 | |||||
5623 | if (m_ApplyMatrixPtr) { | ||||
5624 | m_ApplyMatrixPtr->Apply(Pixel); | ||||
5625 | } | ||||
5626 | |||||
5627 | if (m_ApplyCurvePtrB) { | ||||
5628 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5629 | Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); | ||||
5630 | } | ||||
5631 | } | ||||
5632 | } | ||||
5633 | |||||
5634 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5635 | DstPixel[i] = Pixel[i]; | ||||
5636 | } | ||||
5637 | |||||
5638 | CheckDstAbs(DstPixel); | ||||
5639 | } | ||||
5640 | |||||
5641 | /** | ||||
5642 | ************************************************************************** | ||||
5643 | * Name: CIccXform3DLut::ExtractInputCurves | ||||
5644 | * | ||||
5645 | * Purpose: | ||||
5646 | * Gets the input curves. Should be called only after Begin() | ||||
5647 | * has been called. Once the curves are extracted, they will | ||||
5648 | * not be used by the Apply() function. | ||||
5649 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
5650 | * | ||||
5651 | * Return: | ||||
5652 | * Pointer to the input curves. | ||||
5653 | ************************************************************************** | ||||
5654 | */ | ||||
5655 | LPIccCurve* CIccXform3DLut::ExtractInputCurves() | ||||
5656 | { | ||||
5657 | if (m_bInput) { | ||||
5658 | if (m_pTag->m_bInputMatrix) { | ||||
5659 | if (m_pTag->m_CurvesB) { | ||||
5660 | LPIccCurve* Curve = new LPIccCurve[3]; | ||||
5661 | Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy()); | ||||
5662 | Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy()); | ||||
5663 | Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy()); | ||||
5664 | m_ApplyCurvePtrB = NULL__null; | ||||
5665 | return Curve; | ||||
5666 | } | ||||
5667 | } | ||||
5668 | else { | ||||
5669 | if (m_pTag->m_CurvesA) { | ||||
5670 | LPIccCurve* Curve = new LPIccCurve[3]; | ||||
5671 | Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy()); | ||||
5672 | Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy()); | ||||
5673 | Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy()); | ||||
5674 | m_ApplyCurvePtrA = NULL__null; | ||||
5675 | return Curve; | ||||
5676 | } | ||||
5677 | } | ||||
5678 | } | ||||
5679 | |||||
5680 | return NULL__null; | ||||
5681 | } | ||||
5682 | |||||
5683 | /** | ||||
5684 | ************************************************************************** | ||||
5685 | * Name: CIccXform3DLut::ExtractOutputCurves | ||||
5686 | * | ||||
5687 | * Purpose: | ||||
5688 | * Gets the output curves. Should be called only after Begin() | ||||
5689 | * has been called. Once the curves are extracted, they will | ||||
5690 | * not be used by the Apply() function. | ||||
5691 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
5692 | * | ||||
5693 | * Return: | ||||
5694 | * Pointer to the output curves. | ||||
5695 | ************************************************************************** | ||||
5696 | */ | ||||
5697 | LPIccCurve* CIccXform3DLut::ExtractOutputCurves() | ||||
5698 | { | ||||
5699 | if (!m_bInput) { | ||||
5700 | if (m_pTag->m_bInputMatrix) { | ||||
5701 | if (m_pTag->m_CurvesA) { | ||||
5702 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | ||||
5703 | for (int i=0; i<m_pTag->m_nOutput; i++) { | ||||
5704 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); | ||||
5705 | } | ||||
5706 | m_ApplyCurvePtrA = NULL__null; | ||||
5707 | return Curve; | ||||
5708 | } | ||||
5709 | } | ||||
5710 | else { | ||||
5711 | if (m_pTag->m_CurvesB) { | ||||
5712 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | ||||
5713 | for (int i=0; i<m_pTag->m_nOutput; i++) { | ||||
5714 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); | ||||
5715 | } | ||||
5716 | m_ApplyCurvePtrB = NULL__null; | ||||
5717 | return Curve; | ||||
5718 | } | ||||
5719 | } | ||||
5720 | } | ||||
5721 | |||||
5722 | return NULL__null; | ||||
5723 | } | ||||
5724 | |||||
5725 | /** | ||||
5726 | ************************************************************************** | ||||
5727 | * Name: CIccXform4DLut::CIccXform4DLut | ||||
5728 | * | ||||
5729 | * Purpose: | ||||
5730 | * Constructor | ||||
5731 | * | ||||
5732 | * Args: | ||||
5733 | * pTag = Pointer to the tag of type CIccMBB | ||||
5734 | ************************************************************************** | ||||
5735 | */ | ||||
5736 | CIccXform4DLut::CIccXform4DLut(CIccTag *pTag) | ||||
5737 | { | ||||
5738 | if (pTag && pTag->IsMBBType()) { | ||||
5739 | m_pTag = (CIccMBB*)pTag; | ||||
5740 | } | ||||
5741 | else | ||||
5742 | m_pTag = NULL__null; | ||||
5743 | |||||
5744 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | ||||
5745 | m_ApplyMatrixPtr = NULL__null; | ||||
5746 | } | ||||
5747 | |||||
5748 | |||||
5749 | /** | ||||
5750 | ************************************************************************** | ||||
5751 | * Name: CIccXform4DLut::~CIccXform4DLut | ||||
5752 | * | ||||
5753 | * Purpose: | ||||
5754 | * Destructor | ||||
5755 | ************************************************************************** | ||||
5756 | */ | ||||
5757 | CIccXform4DLut::~CIccXform4DLut() | ||||
5758 | { | ||||
5759 | } | ||||
5760 | |||||
5761 | |||||
5762 | /** | ||||
5763 | ************************************************************************** | ||||
5764 | * Name: CIccXform4DLut::Begin | ||||
5765 | * | ||||
5766 | * Purpose: | ||||
5767 | * Does the initialization of the Xform before Apply() is called. | ||||
5768 | * Must be called before Apply(). | ||||
5769 | * | ||||
5770 | ************************************************************************** | ||||
5771 | */ | ||||
5772 | icStatusCMM CIccXform4DLut::Begin() | ||||
5773 | { | ||||
5774 | icStatusCMM status; | ||||
5775 | CIccCurve **Curve; | ||||
5776 | int i; | ||||
5777 | |||||
5778 | status = CIccXform::Begin(); | ||||
5779 | if (status != icCmmStatOk) { | ||||
5780 | return status; | ||||
5781 | } | ||||
5782 | |||||
5783 | if (!m_pTag || | ||||
5784 | m_pTag->InputChannels()!=4) { | ||||
5785 | return icCmmStatInvalidLut; | ||||
5786 | } | ||||
5787 | |||||
5788 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | ||||
5789 | |||||
5790 | if (m_pTag->m_bInputMatrix) { | ||||
5791 | if (m_pTag->m_CurvesB) { | ||||
5792 | Curve = m_pTag->m_CurvesB; | ||||
5793 | |||||
5794 | Curve[0]->Begin(); | ||||
5795 | Curve[1]->Begin(); | ||||
5796 | Curve[2]->Begin(); | ||||
5797 | Curve[3]->Begin(); | ||||
5798 | |||||
5799 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || | ||||
5800 | !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity()) | ||||
5801 | { | ||||
5802 | m_ApplyCurvePtrB = Curve; | ||||
5803 | } | ||||
5804 | } | ||||
5805 | |||||
5806 | if (m_pTag->m_CLUT) { | ||||
5807 | m_pTag->m_CLUT->Begin(); | ||||
5808 | } | ||||
5809 | |||||
5810 | if (m_pTag->m_CurvesA) { | ||||
5811 | Curve = m_pTag->m_CurvesA; | ||||
5812 | |||||
5813 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5814 | Curve[i]->Begin(); | ||||
5815 | } | ||||
5816 | |||||
5817 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5818 | if (!Curve[i]->IsIdentity()) { | ||||
5819 | m_ApplyCurvePtrA = Curve; | ||||
5820 | break; | ||||
5821 | } | ||||
5822 | } | ||||
5823 | } | ||||
5824 | |||||
5825 | } | ||||
5826 | else { | ||||
5827 | if (m_pTag->m_CurvesA) { | ||||
5828 | Curve = m_pTag->m_CurvesA; | ||||
5829 | |||||
5830 | Curve[0]->Begin(); | ||||
5831 | Curve[1]->Begin(); | ||||
5832 | Curve[2]->Begin(); | ||||
5833 | Curve[3]->Begin(); | ||||
5834 | |||||
5835 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || | ||||
5836 | !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity()) | ||||
5837 | { | ||||
5838 | m_ApplyCurvePtrA = Curve; | ||||
5839 | } | ||||
5840 | } | ||||
5841 | |||||
5842 | if (m_pTag->m_CLUT) { | ||||
5843 | m_pTag->m_CLUT->Begin(); | ||||
5844 | } | ||||
5845 | |||||
5846 | if (m_pTag->m_CurvesM) { | ||||
5847 | Curve = m_pTag->m_CurvesM; | ||||
5848 | |||||
5849 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5850 | Curve[i]->Begin(); | ||||
5851 | } | ||||
5852 | |||||
5853 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5854 | if (!Curve[i]->IsIdentity()) { | ||||
5855 | m_ApplyCurvePtrM = Curve; | ||||
5856 | break; | ||||
5857 | } | ||||
5858 | } | ||||
5859 | } | ||||
5860 | |||||
5861 | if (m_pTag->m_CurvesB) { | ||||
5862 | Curve = m_pTag->m_CurvesB; | ||||
5863 | |||||
5864 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5865 | Curve[i]->Begin(); | ||||
5866 | } | ||||
5867 | |||||
5868 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5869 | if (!Curve[i]->IsIdentity()) { | ||||
5870 | m_ApplyCurvePtrB = Curve; | ||||
5871 | break; | ||||
5872 | } | ||||
5873 | } | ||||
5874 | } | ||||
5875 | } | ||||
5876 | |||||
5877 | m_ApplyMatrixPtr = NULL__null; | ||||
5878 | if (m_pTag->m_Matrix) { | ||||
5879 | if (m_pTag->m_bInputMatrix) { | ||||
5880 | return icCmmStatInvalidProfile; | ||||
5881 | } | ||||
5882 | else { | ||||
5883 | if (m_pTag->m_nOutput!=3) { | ||||
5884 | return icCmmStatInvalidProfile; | ||||
5885 | } | ||||
5886 | } | ||||
5887 | |||||
5888 | if (!m_pTag->m_Matrix->IsIdentity()) { | ||||
5889 | m_ApplyMatrixPtr = m_pTag->m_Matrix; | ||||
5890 | } | ||||
5891 | } | ||||
5892 | |||||
5893 | return icCmmStatOk; | ||||
5894 | } | ||||
5895 | |||||
5896 | |||||
5897 | /** | ||||
5898 | ************************************************************************** | ||||
5899 | * Name: CIccXform4DLut::Apply | ||||
5900 | * | ||||
5901 | * Purpose: | ||||
5902 | * Does the actual application of the Xform. | ||||
5903 | * | ||||
5904 | * Args: | ||||
5905 | * pApply = ApplyXform object containging temporary storage used during Apply | ||||
5906 | * DstPixel = Destination pixel where the result is stored, | ||||
5907 | * SrcPixel = Source pixel which is to be applied. | ||||
5908 | ************************************************************************** | ||||
5909 | */ | ||||
5910 | void CIccXform4DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | ||||
5911 | { | ||||
5912 | icFloatNumber Pixel[16]; | ||||
5913 | int i; | ||||
5914 | |||||
5915 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | ||||
5916 | Pixel[0] = SrcPixel[0]; | ||||
5917 | Pixel[1] = SrcPixel[1]; | ||||
5918 | Pixel[2] = SrcPixel[2]; | ||||
5919 | Pixel[3] = SrcPixel[3]; | ||||
5920 | |||||
5921 | if (m_pTag->m_bInputMatrix) { | ||||
5922 | if (m_ApplyCurvePtrB) { | ||||
5923 | Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]); | ||||
5924 | Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]); | ||||
5925 | Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]); | ||||
5926 | Pixel[3] = m_ApplyCurvePtrB[3]->Apply(Pixel[3]); | ||||
5927 | } | ||||
5928 | |||||
5929 | if (m_pTag->m_CLUT) { | ||||
5930 | m_pTag->m_CLUT->Interp4d(Pixel, Pixel); | ||||
5931 | } | ||||
5932 | |||||
5933 | if (m_ApplyCurvePtrA) { | ||||
5934 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5935 | Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); | ||||
5936 | } | ||||
5937 | } | ||||
5938 | |||||
5939 | } | ||||
5940 | else { | ||||
5941 | if (m_ApplyCurvePtrA) { | ||||
5942 | Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]); | ||||
5943 | Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]); | ||||
5944 | Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]); | ||||
5945 | Pixel[3] = m_ApplyCurvePtrA[3]->Apply(Pixel[3]); | ||||
5946 | } | ||||
5947 | |||||
5948 | if (m_pTag->m_CLUT) { | ||||
5949 | m_pTag->m_CLUT->Interp4d(Pixel, Pixel); | ||||
5950 | } | ||||
5951 | |||||
5952 | if (m_ApplyCurvePtrM) { | ||||
5953 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5954 | Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]); | ||||
5955 | } | ||||
5956 | } | ||||
5957 | |||||
5958 | if (m_ApplyMatrixPtr) { | ||||
5959 | m_ApplyMatrixPtr->Apply(Pixel); | ||||
5960 | } | ||||
5961 | |||||
5962 | if (m_ApplyCurvePtrB) { | ||||
5963 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5964 | Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); | ||||
5965 | } | ||||
5966 | } | ||||
5967 | } | ||||
5968 | |||||
5969 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
5970 | DstPixel[i] = Pixel[i]; | ||||
5971 | } | ||||
5972 | |||||
5973 | CheckDstAbs(DstPixel); | ||||
5974 | } | ||||
5975 | |||||
5976 | /** | ||||
5977 | ************************************************************************** | ||||
5978 | * Name: CIccXform4DLut::ExtractInputCurves | ||||
5979 | * | ||||
5980 | * Purpose: | ||||
5981 | * Gets the input curves. Should be called only after Begin() | ||||
5982 | * has been called. Once the curves are extracted, they will | ||||
5983 | * not be used by the Apply() function. | ||||
5984 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
5985 | * | ||||
5986 | * Return: | ||||
5987 | * Pointer to the input curves. | ||||
5988 | ************************************************************************** | ||||
5989 | */ | ||||
5990 | LPIccCurve* CIccXform4DLut::ExtractInputCurves() | ||||
5991 | { | ||||
5992 | if (m_bInput) { | ||||
5993 | if (m_pTag->m_bInputMatrix) { | ||||
5994 | if (m_pTag->m_CurvesB) { | ||||
5995 | LPIccCurve* Curve = new LPIccCurve[4]; | ||||
5996 | Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy()); | ||||
5997 | Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy()); | ||||
5998 | Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy()); | ||||
5999 | Curve[3] = (LPIccCurve)(m_pTag->m_CurvesB[3]->NewCopy()); | ||||
6000 | m_ApplyCurvePtrB = NULL__null; | ||||
6001 | return Curve; | ||||
6002 | } | ||||
6003 | } | ||||
6004 | else { | ||||
6005 | if (m_pTag->m_CurvesA) { | ||||
6006 | LPIccCurve* Curve = new LPIccCurve[4]; | ||||
6007 | Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy()); | ||||
6008 | Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy()); | ||||
6009 | Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy()); | ||||
6010 | Curve[3] = (LPIccCurve)(m_pTag->m_CurvesA[3]->NewCopy()); | ||||
6011 | m_ApplyCurvePtrA = NULL__null; | ||||
6012 | return Curve; | ||||
6013 | } | ||||
6014 | } | ||||
6015 | } | ||||
6016 | |||||
6017 | return NULL__null; | ||||
6018 | } | ||||
6019 | |||||
6020 | /** | ||||
6021 | ************************************************************************** | ||||
6022 | * Name: CIccXform4DLut::ExtractOutputCurves | ||||
6023 | * | ||||
6024 | * Purpose: | ||||
6025 | * Gets the output curves. Should be called only after Begin() | ||||
6026 | * has been called. Once the curves are extracted, they will | ||||
6027 | * not be used by the Apply() function. | ||||
6028 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
6029 | * | ||||
6030 | * Return: | ||||
6031 | * Pointer to the output curves. | ||||
6032 | ************************************************************************** | ||||
6033 | */ | ||||
6034 | LPIccCurve* CIccXform4DLut::ExtractOutputCurves() | ||||
6035 | { | ||||
6036 | if (!m_bInput) { | ||||
6037 | if (m_pTag->m_bInputMatrix) { | ||||
6038 | if (m_pTag->m_CurvesA) { | ||||
6039 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | ||||
6040 | for (int i=0; i<m_pTag->m_nOutput; i++) { | ||||
6041 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); | ||||
6042 | } | ||||
6043 | m_ApplyCurvePtrA = NULL__null; | ||||
6044 | return Curve; | ||||
6045 | } | ||||
6046 | } | ||||
6047 | else { | ||||
6048 | if (m_pTag->m_CurvesB) { | ||||
6049 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | ||||
6050 | for (int i=0; i<m_pTag->m_nOutput; i++) { | ||||
6051 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); | ||||
6052 | } | ||||
6053 | m_ApplyCurvePtrB = NULL__null; | ||||
6054 | return Curve; | ||||
6055 | } | ||||
6056 | } | ||||
6057 | } | ||||
6058 | |||||
6059 | return NULL__null; | ||||
6060 | } | ||||
6061 | |||||
6062 | |||||
6063 | /** | ||||
6064 | ************************************************************************** | ||||
6065 | * Name: CIccXformNDLut::CIccXformNDLut | ||||
6066 | * | ||||
6067 | * Purpose: | ||||
6068 | * Constructor | ||||
6069 | * | ||||
6070 | * Args: | ||||
6071 | * pTag = Pointer to the tag of type CIccMBB | ||||
6072 | ************************************************************************** | ||||
6073 | */ | ||||
6074 | CIccXformNDLut::CIccXformNDLut(CIccTag *pTag) | ||||
6075 | { | ||||
6076 | if (pTag && pTag->IsMBBType()) { | ||||
6077 | m_pTag = (CIccMBB*)pTag; | ||||
6078 | } | ||||
6079 | else | ||||
6080 | m_pTag = NULL__null; | ||||
6081 | |||||
6082 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | ||||
6083 | m_ApplyMatrixPtr = NULL__null; | ||||
6084 | } | ||||
6085 | |||||
6086 | |||||
6087 | /** | ||||
6088 | ************************************************************************** | ||||
6089 | * Name: CIccXformNDLut::~CIccXformNDLut | ||||
6090 | * | ||||
6091 | * Purpose: | ||||
6092 | * Destructor | ||||
6093 | ************************************************************************** | ||||
6094 | */ | ||||
6095 | CIccXformNDLut::~CIccXformNDLut() | ||||
6096 | { | ||||
6097 | } | ||||
6098 | |||||
6099 | |||||
6100 | /** | ||||
6101 | ************************************************************************** | ||||
6102 | * Name: CIccXformNDLut::Begin | ||||
6103 | * | ||||
6104 | * Purpose: | ||||
6105 | * Does the initialization of the Xform before Apply() is called. | ||||
6106 | * Must be called before Apply(). | ||||
6107 | * | ||||
6108 | ************************************************************************** | ||||
6109 | */ | ||||
6110 | icStatusCMM CIccXformNDLut::Begin() | ||||
6111 | { | ||||
6112 | icStatusCMM status; | ||||
6113 | CIccCurve **Curve; | ||||
6114 | int i; | ||||
6115 | |||||
6116 | status = CIccXform::Begin(); | ||||
6117 | if (status != icCmmStatOk) { | ||||
6118 | return status; | ||||
6119 | } | ||||
6120 | |||||
6121 | if (!m_pTag || (m_pTag->InputChannels()>2 && m_pTag->InputChannels()<5)) { | ||||
6122 | return icCmmStatInvalidLut; | ||||
6123 | } | ||||
6124 | |||||
6125 | m_nNumInput = m_pTag->m_nInput; | ||||
6126 | |||||
6127 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | ||||
6128 | |||||
6129 | if (m_pTag->m_bInputMatrix) { | ||||
6130 | if (m_pTag->m_CurvesB) { | ||||
6131 | Curve = m_pTag->m_CurvesB; | ||||
6132 | |||||
6133 | for (i=0; i<m_nNumInput; i++) | ||||
6134 | Curve[i]->Begin(); | ||||
6135 | |||||
6136 | for (i=0; i<m_nNumInput; i++) { | ||||
6137 | if (!Curve[i]->IsIdentity()) { | ||||
6138 | m_ApplyCurvePtrB = Curve; | ||||
6139 | break; | ||||
6140 | } | ||||
6141 | } | ||||
6142 | } | ||||
6143 | |||||
6144 | if (m_pTag->m_CLUT) { | ||||
6145 | m_pTag->m_CLUT->Begin(); | ||||
6146 | } | ||||
6147 | |||||
6148 | if (m_pTag->m_CurvesA) { | ||||
6149 | Curve = m_pTag->m_CurvesA; | ||||
6150 | |||||
6151 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6152 | Curve[i]->Begin(); | ||||
6153 | } | ||||
6154 | |||||
6155 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6156 | if (!Curve[i]->IsIdentity()) { | ||||
6157 | m_ApplyCurvePtrA = Curve; | ||||
6158 | break; | ||||
6159 | } | ||||
6160 | } | ||||
6161 | } | ||||
6162 | |||||
6163 | } | ||||
6164 | else { | ||||
6165 | if (m_pTag->m_CurvesA) { | ||||
6166 | Curve = m_pTag->m_CurvesA; | ||||
6167 | |||||
6168 | for (i=0; i<m_nNumInput; i++) | ||||
6169 | Curve[i]->Begin(); | ||||
6170 | |||||
6171 | for (i=0; i<m_nNumInput; i++) { | ||||
6172 | if (!Curve[i]->IsIdentity()) { | ||||
6173 | m_ApplyCurvePtrA = Curve; | ||||
6174 | break; | ||||
6175 | } | ||||
6176 | } | ||||
6177 | } | ||||
6178 | |||||
6179 | if (m_pTag->m_CLUT) { | ||||
6180 | m_pTag->m_CLUT->Begin(); | ||||
6181 | } | ||||
6182 | |||||
6183 | if (m_pTag->m_CurvesM) { | ||||
6184 | Curve = m_pTag->m_CurvesM; | ||||
6185 | |||||
6186 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6187 | Curve[i]->Begin(); | ||||
6188 | } | ||||
6189 | |||||
6190 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6191 | if (!Curve[i]->IsIdentity()) { | ||||
6192 | m_ApplyCurvePtrM = Curve; | ||||
6193 | break; | ||||
6194 | } | ||||
6195 | } | ||||
6196 | } | ||||
6197 | |||||
6198 | if (m_pTag->m_CurvesB) { | ||||
6199 | Curve = m_pTag->m_CurvesB; | ||||
6200 | |||||
6201 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6202 | Curve[i]->Begin(); | ||||
6203 | } | ||||
6204 | |||||
6205 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6206 | if (!Curve[i]->IsIdentity()) { | ||||
6207 | m_ApplyCurvePtrB = Curve; | ||||
6208 | break; | ||||
6209 | } | ||||
6210 | } | ||||
6211 | } | ||||
6212 | } | ||||
6213 | |||||
6214 | m_ApplyMatrixPtr = NULL__null; | ||||
6215 | if (m_pTag->m_Matrix) { | ||||
6216 | if (m_pTag->m_bInputMatrix) { | ||||
6217 | return icCmmStatInvalidProfile; | ||||
6218 | } | ||||
6219 | else { | ||||
6220 | if (m_pTag->m_nOutput!=3) { | ||||
6221 | return icCmmStatInvalidProfile; | ||||
6222 | } | ||||
6223 | } | ||||
6224 | |||||
6225 | if (!m_pTag->m_Matrix->IsIdentity()) { | ||||
6226 | m_ApplyMatrixPtr = m_pTag->m_Matrix; | ||||
6227 | } | ||||
6228 | } | ||||
6229 | |||||
6230 | return icCmmStatOk; | ||||
6231 | } | ||||
6232 | |||||
6233 | |||||
6234 | /** | ||||
6235 | ************************************************************************** | ||||
6236 | * Name: CIccXformNDLut::Apply | ||||
6237 | * | ||||
6238 | * Purpose: | ||||
6239 | * Does the actual application of the Xform. | ||||
6240 | * | ||||
6241 | * Args: | ||||
6242 | * pApply = ApplyXform object containging temporary storage used during Apply | ||||
6243 | * DstPixel = Destination pixel where the result is stored, | ||||
6244 | * SrcPixel = Source pixel which is to be applied. | ||||
6245 | ************************************************************************** | ||||
6246 | */ | ||||
6247 | void CIccXformNDLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | ||||
6248 | { | ||||
6249 | icFloatNumber Pixel[16]; | ||||
6250 | int i; | ||||
6251 | |||||
6252 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | ||||
6253 | for (i=0; i<m_nNumInput; i++) | ||||
6254 | Pixel[i] = SrcPixel[i]; | ||||
6255 | |||||
6256 | if (m_pTag->m_bInputMatrix) { | ||||
6257 | if (m_ApplyCurvePtrB) { | ||||
6258 | for (i=0; i<m_nNumInput; i++) | ||||
6259 | Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); | ||||
6260 | } | ||||
6261 | |||||
6262 | if (m_pTag->m_CLUT) { | ||||
6263 | switch(m_nNumInput) { | ||||
6264 | case 5: | ||||
6265 | m_pTag->m_CLUT->Interp5d(Pixel, Pixel); | ||||
6266 | break; | ||||
6267 | case 6: | ||||
6268 | m_pTag->m_CLUT->Interp6d(Pixel, Pixel); | ||||
6269 | break; | ||||
6270 | default: | ||||
6271 | m_pTag->m_CLUT->InterpND(Pixel, Pixel); | ||||
6272 | break; | ||||
6273 | } | ||||
6274 | } | ||||
6275 | |||||
6276 | if (m_ApplyCurvePtrA) { | ||||
6277 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6278 | Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); | ||||
6279 | } | ||||
6280 | } | ||||
6281 | |||||
6282 | } | ||||
6283 | else { | ||||
6284 | if (m_ApplyCurvePtrA) { | ||||
6285 | for (i=0; i<m_nNumInput; i++) | ||||
6286 | Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); | ||||
6287 | } | ||||
6288 | |||||
6289 | if (m_pTag->m_CLUT) { | ||||
6290 | switch(m_nNumInput) { | ||||
6291 | case 5: | ||||
6292 | m_pTag->m_CLUT->Interp5d(Pixel, Pixel); | ||||
6293 | break; | ||||
6294 | case 6: | ||||
6295 | m_pTag->m_CLUT->Interp6d(Pixel, Pixel); | ||||
6296 | break; | ||||
6297 | default: | ||||
6298 | m_pTag->m_CLUT->InterpND(Pixel, Pixel); | ||||
6299 | break; | ||||
6300 | } | ||||
6301 | } | ||||
6302 | |||||
6303 | if (m_ApplyCurvePtrM) { | ||||
6304 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6305 | Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]); | ||||
6306 | } | ||||
6307 | } | ||||
6308 | |||||
6309 | if (m_ApplyMatrixPtr) { | ||||
6310 | m_ApplyMatrixPtr->Apply(Pixel); | ||||
6311 | } | ||||
6312 | |||||
6313 | if (m_ApplyCurvePtrB) { | ||||
6314 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6315 | Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); | ||||
6316 | } | ||||
6317 | } | ||||
6318 | } | ||||
6319 | |||||
6320 | for (i=0; i<m_pTag->m_nOutput; i++) { | ||||
6321 | DstPixel[i] = Pixel[i]; | ||||
6322 | } | ||||
6323 | |||||
6324 | CheckDstAbs(DstPixel); | ||||
6325 | } | ||||
6326 | |||||
6327 | /** | ||||
6328 | ************************************************************************** | ||||
6329 | * Name: CIccXformNDLut::ExtractInputCurves | ||||
6330 | * | ||||
6331 | * Purpose: | ||||
6332 | * Gets the input curves. Should be called only after Begin() | ||||
6333 | * has been called. Once the curves are extracted, they will | ||||
6334 | * not be used by the Apply() function. | ||||
6335 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
6336 | * | ||||
6337 | * Return: | ||||
6338 | * Pointer to the input curves. | ||||
6339 | ************************************************************************** | ||||
6340 | */ | ||||
6341 | LPIccCurve* CIccXformNDLut::ExtractInputCurves() | ||||
6342 | { | ||||
6343 | if (m_bInput) { | ||||
6344 | if (m_pTag->m_bInputMatrix) { | ||||
6345 | if (m_pTag->m_CurvesB) { | ||||
6346 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput]; | ||||
6347 | for (int i=0; i<m_pTag->m_nInput; i++) { | ||||
6348 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); | ||||
6349 | } | ||||
6350 | m_ApplyCurvePtrB = NULL__null; | ||||
6351 | return Curve; | ||||
6352 | } | ||||
6353 | } | ||||
6354 | else { | ||||
6355 | if (m_pTag->m_CurvesA) { | ||||
6356 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput]; | ||||
6357 | for (int i=0; i<m_pTag->m_nInput; i++) { | ||||
6358 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); | ||||
6359 | } | ||||
6360 | m_ApplyCurvePtrA = NULL__null; | ||||
6361 | return Curve; | ||||
6362 | } | ||||
6363 | } | ||||
6364 | } | ||||
6365 | |||||
6366 | return NULL__null; | ||||
6367 | } | ||||
6368 | |||||
6369 | /** | ||||
6370 | ************************************************************************** | ||||
6371 | * Name: CIccXformNDLut::ExtractOutputCurves | ||||
6372 | * | ||||
6373 | * Purpose: | ||||
6374 | * Gets the output curves. Should be called only after Begin() | ||||
6375 | * has been called. Once the curves are extracted, they will | ||||
6376 | * not be used by the Apply() function. | ||||
6377 | * WARNING: caller owns the curves and must be deleted by the caller. | ||||
6378 | * | ||||
6379 | * Return: | ||||
6380 | * Pointer to the output curves. | ||||
6381 | ************************************************************************** | ||||
6382 | */ | ||||
6383 | LPIccCurve* CIccXformNDLut::ExtractOutputCurves() | ||||
6384 | { | ||||
6385 | if (!m_bInput) { | ||||
6386 | if (m_pTag->m_bInputMatrix) { | ||||
6387 | if (m_pTag->m_CurvesA) { | ||||
6388 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | ||||
6389 | for (int i=0; i<m_pTag->m_nOutput; i++) { | ||||
6390 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); | ||||
6391 | } | ||||
6392 | m_ApplyCurvePtrA = NULL__null; | ||||
6393 | return Curve; | ||||
6394 | } | ||||
6395 | } | ||||
6396 | else { | ||||
6397 | if (m_pTag->m_CurvesB) { | ||||
6398 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | ||||
6399 | for (int i=0; i<m_pTag->m_nOutput; i++) { | ||||
6400 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); | ||||
6401 | } | ||||
6402 | m_ApplyCurvePtrB = NULL__null; | ||||
6403 | return Curve; | ||||
6404 | } | ||||
6405 | } | ||||
6406 | } | ||||
6407 | |||||
6408 | return NULL__null; | ||||
6409 | } | ||||
6410 | |||||
6411 | /** | ||||
6412 | ************************************************************************** | ||||
6413 | * Name: CIccXformNamedColor::CIccXformNamedColor | ||||
6414 | * | ||||
6415 | * Purpose: | ||||
6416 | * Constructor | ||||
6417 | * | ||||
6418 | * Args: | ||||
6419 | * pTag = Pointer to the tag of type CIccTagNamedColor2, | ||||
6420 | * csPCS = PCS color space, | ||||
6421 | * csDevice = Device color space | ||||
6422 | ************************************************************************** | ||||
6423 | */ | ||||
6424 | CIccXformNamedColor::CIccXformNamedColor(CIccTag *pTag, icColorSpaceSignature csPcs, icColorSpaceSignature csDevice, | ||||
6425 | icSpectralColorSignature csSpectralPcs/* =icSigNoSpectralData */, | ||||
6426 | const icSpectralRange *pSpectralRange /* = NULL */, | ||||
6427 | const icSpectralRange *pBiSpectralRange /* = NULL */) | ||||
6428 | { | ||||
6429 | if (pTag) { | ||||
6430 | if (pTag->GetType()==icSigNamedColor2Type) { | ||||
6431 | m_pTag = (CIccTagNamedColor2*)pTag; | ||||
6432 | m_pArray = NULL__null; | ||||
6433 | |||||
6434 | m_pTag->SetColorSpaces(csPcs, csDevice); | ||||
6435 | } | ||||
6436 | else if (pTag->GetTagArrayType()==icSigNamedColorArray) { | ||||
6437 | CIccTagArray *pArray = (CIccTagArray*)pTag; | ||||
6438 | CIccArrayNamedColor *pNamed = (CIccArrayNamedColor*)pArray->GetArrayHandler(); | ||||
6439 | |||||
6440 | if (pNamed) { | ||||
6441 | m_pTag = NULL__null; | ||||
6442 | m_pArray = pNamed; | ||||
6443 | pNamed->SetColorSpaces(csPcs, csDevice, csSpectralPcs, pSpectralRange, pBiSpectralRange); | ||||
6444 | } | ||||
6445 | } | ||||
6446 | } | ||||
6447 | |||||
6448 | m_nSrcSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | ||||
6449 | m_nDestSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | ||||
6450 | } | ||||
6451 | |||||
6452 | |||||
6453 | /** | ||||
6454 | ************************************************************************** | ||||
6455 | * Name: CIccXformNamedColor::CIccXformNamedColor | ||||
6456 | * | ||||
6457 | * Purpose: | ||||
6458 | * Destructor | ||||
6459 | ************************************************************************** | ||||
6460 | */ | ||||
6461 | CIccXformNamedColor::~CIccXformNamedColor() | ||||
6462 | { | ||||
6463 | } | ||||
6464 | |||||
6465 | /** | ||||
6466 | ************************************************************************** | ||||
6467 | * Name: CIccXformNamedColor::Begin | ||||
6468 | * | ||||
6469 | * Purpose: | ||||
6470 | * Does the initialization of the Xform before Apply() is called. | ||||
6471 | * Must be called before Apply(). | ||||
6472 | * | ||||
6473 | ************************************************************************** | ||||
6474 | */ | ||||
6475 | icStatusCMM CIccXformNamedColor::Begin() | ||||
6476 | { | ||||
6477 | icStatusCMM status; | ||||
6478 | |||||
6479 | status = CIccXform::Begin(); | ||||
6480 | if (status != icCmmStatOk) | ||||
6481 | return status; | ||||
6482 | |||||
6483 | if (m_pTag==NULL__null && m_pArray==NULL__null) { | ||||
6484 | return icCmmStatProfileMissingTag; | ||||
6485 | } | ||||
6486 | |||||
6487 | if (m_nSrcSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f) || | ||||
6488 | m_nDestSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | ||||
6489 | return icCmmStatIncorrectApply; | ||||
6490 | } | ||||
6491 | |||||
6492 | if (m_nSrcSpace != icSigNamedData) { | ||||
6493 | if (m_nDestSpace != icSigNamedData) { | ||||
6494 | m_nApplyInterface = icApplyPixel2Pixel; | ||||
6495 | } | ||||
6496 | else { | ||||
6497 | m_nApplyInterface = icApplyPixel2Named; | ||||
6498 | } | ||||
6499 | } | ||||
6500 | else { | ||||
6501 | if (m_nDestSpace != icSigNamedData) { | ||||
6502 | m_nApplyInterface = icApplyNamed2Pixel; | ||||
6503 | } | ||||
6504 | else { | ||||
6505 | return icCmmStatIncorrectApply; | ||||
6506 | } | ||||
6507 | } | ||||
6508 | |||||
6509 | if (m_pTag && !m_pTag->InitFindCachedPCSColor()) | ||||
6510 | return icCmmStatAllocErr; | ||||
6511 | else if (m_pArray && !m_pArray->Begin()) | ||||
6512 | return icCmmStatAllocErr; | ||||
6513 | |||||
6514 | return icCmmStatOk; | ||||
6515 | } | ||||
6516 | |||||
6517 | |||||
6518 | |||||
6519 | /** | ||||
6520 | ************************************************************************** | ||||
6521 | * Name: CIccXformNamedColor::Apply | ||||
6522 | * | ||||
6523 | * Purpose: | ||||
6524 | * Does the actual application of the Xform. | ||||
6525 | * | ||||
6526 | * Args: | ||||
6527 | * pApply = ApplyXform object containging temporary storage used during Apply | ||||
6528 | * DstColorName = Destination string where the color name result is stored, | ||||
6529 | * SrcPixel = Source pixel which is to be applied. | ||||
6530 | ************************************************************************** | ||||
6531 | */ | ||||
6532 | icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icChar *DstColorName, const icFloatNumber *SrcPixel) const | ||||
6533 | { | ||||
6534 | |||||
6535 | if (m_pArray) { | ||||
6536 | const CIccArrayNamedColor *pArray = m_pArray; | ||||
6537 | CIccStructNamedColor *pColor; | ||||
6538 | |||||
6539 | std::string NamedColor; | ||||
6540 | |||||
6541 | if (IsSrcPCS()) { | ||||
6542 | if (IsSpaceSpectralPCS(m_nSrcSpace)) { | ||||
6543 | pColor = pArray->FindSpectralColor(SrcPixel); | ||||
6544 | if (pColor) | ||||
6545 | NamedColor = pColor->getName(); | ||||
6546 | else | ||||
6547 | return icCmmStatColorNotFound; | ||||
6548 | } | ||||
6549 | else { | ||||
6550 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | ||||
6551 | icFloatNumber pix[3]; | ||||
6552 | memcpy(pix, SrcPixel, 3*sizeof(icFloatNumber)); | ||||
6553 | |||||
6554 | if (m_nSrcSpace == icSigLabPcsDataicSigLabData) | ||||
6555 | icLabFromPcs(pix); | ||||
6556 | else { | ||||
6557 | icXyzFromPcs(pix); | ||||
6558 | icXYZtoLab(pix, pix); | ||||
6559 | } | ||||
6560 | |||||
6561 | pColor = pArray->FindPcsColor(pix); | ||||
6562 | if (pColor) | ||||
6563 | NamedColor = pColor->getName(); | ||||
6564 | else | ||||
6565 | return icCmmStatColorNotFound; | ||||
6566 | } | ||||
6567 | } | ||||
6568 | else { | ||||
6569 | pColor = pArray->FindDeviceColor(SrcPixel); | ||||
6570 | if (pColor) | ||||
6571 | NamedColor = pColor->getName(); | ||||
6572 | else | ||||
6573 | return icCmmStatColorNotFound; | ||||
6574 | } | ||||
6575 | |||||
6576 | sprintf(DstColorName, "%s", NamedColor.c_str()); | ||||
6577 | } | ||||
6578 | else if (m_pTag) { | ||||
6579 | const CIccTagNamedColor2 *pTag = m_pTag; | ||||
6580 | |||||
6581 | icFloatNumber DevicePix[16], PCSPix[3]; | ||||
6582 | std::string NamedColor; | ||||
6583 | icUInt32Number i, j; | ||||
6584 | |||||
6585 | if (IsSrcPCS()) { | ||||
6586 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | ||||
6587 | for(i=0; i<3; i++) | ||||
6588 | PCSPix[i] = SrcPixel[i]; | ||||
6589 | |||||
6590 | j = pTag->FindCachedPCSColor(PCSPix); | ||||
6591 | pTag->GetColorName(NamedColor, j); | ||||
6592 | } | ||||
6593 | else { | ||||
6594 | for(i=0; i<m_pTag->GetDeviceCoords(); i++) | ||||
6595 | DevicePix[i] = SrcPixel[i]; | ||||
6596 | |||||
6597 | j = pTag->FindDeviceColor(DevicePix); | ||||
6598 | pTag->GetColorName(NamedColor, j); | ||||
6599 | } | ||||
6600 | |||||
6601 | sprintf(DstColorName, "%s", NamedColor.c_str()); | ||||
6602 | } | ||||
6603 | else | ||||
6604 | return icCmmStatBadXform; | ||||
6605 | |||||
6606 | return icCmmStatOk; | ||||
6607 | } | ||||
6608 | |||||
6609 | |||||
6610 | /** | ||||
6611 | ************************************************************************** | ||||
6612 | * Name: CIccXformNamedColor::Apply | ||||
6613 | * | ||||
6614 | * Purpose: | ||||
6615 | * Does the actual application of the Xform. | ||||
6616 | * | ||||
6617 | * Args: | ||||
6618 | * pApply = ApplyXform object containing temporary storage used during Apply | ||||
6619 | * DstPixel = Destination pixel where the result is stored, | ||||
6620 | * SrcColorName = Source color name which is to be applied. | ||||
6621 | ************************************************************************** | ||||
6622 | */ | ||||
6623 | icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint) const | ||||
6624 | { | ||||
6625 | |||||
6626 | if (m_pArray) { | ||||
6627 | const CIccArrayNamedColor *pArray = m_pArray; | ||||
6628 | |||||
6629 | CIccStructNamedColor *pColor; | ||||
6630 | |||||
6631 | if (m_nSrcSpace != icSigNamedData) | ||||
6632 | return icCmmStatBadSpaceLink; | ||||
6633 | |||||
6634 | pColor = pArray->FindColor(SrcColorName); | ||||
6635 | if (!pColor) | ||||
6636 | return icCmmStatColorNotFound; | ||||
6637 | |||||
6638 | if (IsDestPCS()) { | ||||
6639 | if (IsSpaceSpectralPCS(m_nDestSpace)) { | ||||
6640 | if (!pArray->GetSpectralTint(DstPixel, pColor, tint)) | ||||
6641 | return icCmmStatBadTintXform; | ||||
6642 | } | ||||
6643 | else { | ||||
6644 | if (!pArray->GetPcsTint(DstPixel, pColor, tint)) | ||||
6645 | return icCmmStatBadTintXform; | ||||
6646 | |||||
6647 | if (m_nDestSpace == icSigLabData) { | ||||
6648 | icLabToPcs(DstPixel); | ||||
6649 | } | ||||
6650 | else { | ||||
6651 | icXyzToPcs(DstPixel); | ||||
6652 | } | ||||
6653 | CheckDstAbs(DstPixel); | ||||
6654 | } | ||||
6655 | } | ||||
6656 | else { | ||||
6657 | if (!pArray->GetDeviceTint(DstPixel, pColor, tint)) | ||||
6658 | return icCmmStatBadTintXform; | ||||
6659 | } | ||||
6660 | } | ||||
6661 | else if (m_pTag) { | ||||
6662 | const CIccTagNamedColor2 *pTag = m_pTag; | ||||
6663 | |||||
6664 | icInt32Number j; | ||||
6665 | |||||
6666 | if (m_nSrcSpace != icSigNamedData) | ||||
6667 | return icCmmStatBadSpaceLink; | ||||
6668 | |||||
6669 | if (IsDestPCS()) { | ||||
6670 | |||||
6671 | j = pTag->FindColor(SrcColorName); | ||||
6672 | if (j<0) | ||||
6673 | return icCmmStatColorNotFound; | ||||
6674 | |||||
6675 | if (m_nDestSpace == icSigLabData) { | ||||
6676 | memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber)); | ||||
6677 | } | ||||
6678 | else { | ||||
6679 | memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber)); | ||||
6680 | } | ||||
6681 | CheckDstAbs(DstPixel); | ||||
6682 | } | ||||
6683 | else { | ||||
6684 | j = pTag->FindColor(SrcColorName); | ||||
6685 | if (j<0) | ||||
6686 | return icCmmStatColorNotFound; | ||||
6687 | memcpy(DstPixel, pTag->GetEntry(j)->deviceCoords, pTag->GetDeviceCoords()*sizeof(icFloatNumber)); | ||||
6688 | } | ||||
6689 | } | ||||
6690 | |||||
6691 | return icCmmStatOk; | ||||
6692 | } | ||||
6693 | |||||
6694 | /** | ||||
6695 | ************************************************************************** | ||||
6696 | * Name: CIccXformNamedColor::SetSrcSpace | ||||
6697 | * | ||||
6698 | * Purpose: | ||||
6699 | * Sets the source space of the Xform | ||||
6700 | * | ||||
6701 | * Args: | ||||
6702 | * nSrcSpace = signature of the color space to be set | ||||
6703 | ************************************************************************** | ||||
6704 | */ | ||||
6705 | icStatusCMM CIccXformNamedColor::SetSrcSpace(icColorSpaceSignature nSrcSpace) | ||||
6706 | { | ||||
6707 | if (m_pArray) { | ||||
6708 | |||||
6709 | } | ||||
6710 | else if (m_pTag) { | ||||
6711 | CIccTagNamedColor2 *pTag = m_pTag; | ||||
6712 | |||||
6713 | if (nSrcSpace!=pTag->GetPCS()) | ||||
6714 | if (nSrcSpace!=pTag->GetDeviceSpace()) | ||||
6715 | if (nSrcSpace!=icSigNamedData) | ||||
6716 | return icCmmStatBadSpaceLink; | ||||
6717 | } | ||||
6718 | |||||
6719 | m_nSrcSpace = nSrcSpace; | ||||
6720 | |||||
6721 | return icCmmStatOk; | ||||
6722 | } | ||||
6723 | |||||
6724 | /** | ||||
6725 | ************************************************************************** | ||||
6726 | * Name: CIccXformNamedColor::SetDestSpace | ||||
6727 | * | ||||
6728 | * Purpose: | ||||
6729 | * Sets the destination space of the Xform | ||||
6730 | * | ||||
6731 | * Args: | ||||
6732 | * nDestSpace = signature of the color space to be set | ||||
6733 | ************************************************************************** | ||||
6734 | */ | ||||
6735 | icStatusCMM CIccXformNamedColor::SetDestSpace(icColorSpaceSignature nDestSpace) | ||||
6736 | { | ||||
6737 | if (m_nSrcSpace == nDestSpace) | ||||
6738 | return icCmmStatBadSpaceLink; | ||||
6739 | |||||
6740 | if (m_pArray) { | ||||
6741 | |||||
6742 | } | ||||
6743 | else if (m_pTag) { | ||||
6744 | CIccTagNamedColor2 *pTag = (CIccTagNamedColor2*)m_pTag; | ||||
6745 | |||||
6746 | if (nDestSpace!=pTag->GetPCS()) | ||||
6747 | if (nDestSpace!=pTag->GetDeviceSpace()) | ||||
6748 | if (nDestSpace!=icSigNamedData) | ||||
6749 | return icCmmStatBadSpaceLink; | ||||
6750 | } | ||||
6751 | |||||
6752 | m_nDestSpace = nDestSpace; | ||||
6753 | |||||
6754 | return icCmmStatOk; | ||||
6755 | } | ||||
6756 | |||||
6757 | /** | ||||
6758 | ************************************************************************** | ||||
6759 | * Name: CIccXformNamedColor::IsSrcPCS | ||||
6760 | * | ||||
6761 | * Purpose: | ||||
6762 | * Sets the source space is a PCS space | ||||
6763 | ************************************************************************** | ||||
6764 | */ | ||||
6765 | bool CIccXformNamedColor::IsSrcPCS() const | ||||
6766 | { | ||||
6767 | if (m_pTag) { | ||||
6768 | return m_nSrcSpace == m_pTag->GetPCS(); | ||||
6769 | } | ||||
6770 | else if (m_pArray) { | ||||
6771 | return IsSpacePCS(m_nSrcSpace)(((m_nSrcSpace)==icSigXYZData || (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace)); | ||||
6772 | } | ||||
6773 | else | ||||
6774 | return false; | ||||
6775 | } | ||||
6776 | |||||
6777 | |||||
6778 | /** | ||||
6779 | ************************************************************************** | ||||
6780 | * Name: CIccXformNamedColor::IsDestPCS | ||||
6781 | * | ||||
6782 | * Purpose: | ||||
6783 | * Sets the destination space is a PCS space | ||||
6784 | ************************************************************************** | ||||
6785 | */ | ||||
6786 | bool CIccXformNamedColor::IsDestPCS() const | ||||
6787 | { | ||||
6788 | if (m_pTag) { | ||||
6789 | return m_nDestSpace == m_pTag->GetPCS(); | ||||
6790 | } | ||||
6791 | else if (m_pArray) { | ||||
6792 | return IsSpacePCS(m_nDestSpace)(((m_nDestSpace)==icSigXYZData || (m_nDestSpace)==icSigLabData ) || IsSpaceSpectralPCS(m_nDestSpace)); | ||||
6793 | } | ||||
6794 | else | ||||
6795 | return false; | ||||
6796 | } | ||||
6797 | |||||
6798 | |||||
6799 | /** | ||||
6800 | ************************************************************************** | ||||
6801 | * Name: CIccXformMPE::CIccXformMPE | ||||
6802 | * | ||||
6803 | * Purpose: | ||||
6804 | * Constructor | ||||
6805 | ************************************************************************** | ||||
6806 | */ | ||||
6807 | CIccXformMpe::CIccXformMpe(CIccTag *pTag) | ||||
6808 | { | ||||
6809 | if (pTag && pTag->GetType()==icSigMultiProcessElementType) | ||||
6810 | m_pTag = (CIccTagMultiProcessElement*)pTag; | ||||
6811 | else | ||||
6812 | m_pTag = NULL__null; | ||||
6813 | |||||
6814 | m_bUsingAcs = false; | ||||
6815 | m_pAppliedPCC = NULL__null; | ||||
6816 | m_bDeleteAppliedPCC = false; | ||||
6817 | } | ||||
6818 | |||||
6819 | /** | ||||
6820 | ************************************************************************** | ||||
6821 | * Name: CIccXformMPE::~CIccXformMPE | ||||
6822 | * | ||||
6823 | * Purpose: | ||||
6824 | * Destructor | ||||
6825 | ************************************************************************** | ||||
6826 | */ | ||||
6827 | CIccXformMpe::~CIccXformMpe() | ||||
6828 | { | ||||
6829 | if (m_pAppliedPCC && m_bDeleteAppliedPCC) | ||||
6830 | delete m_pAppliedPCC; | ||||
6831 | } | ||||
6832 | |||||
6833 | /** | ||||
6834 | ************************************************************************** | ||||
6835 | * Name: CIccXformMPE::Create | ||||
6836 | * | ||||
6837 | * Purpose: | ||||
6838 | * This is a static Creation function that creates derived CIccXform objects and | ||||
6839 | * initializes them. | ||||
6840 | * | ||||
6841 | * Args: | ||||
6842 | * pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will | ||||
6843 | * be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile | ||||
6844 | * object needs to be allocated on the heap. | ||||
6845 | * bInput = flag to indicate whether to use the input or output side of the profile, | ||||
6846 | * nIntent = the rendering intent to apply to the profile, | ||||
6847 | * nInterp = the interpolation algorithm to use for N-D luts. | ||||
6848 | * nLutType = selection of which transform lut to use | ||||
6849 | * pHintManager = hints for creating the xform | ||||
6850 | * | ||||
6851 | * Return: | ||||
6852 | * A suitable pXform object | ||||
6853 | ************************************************************************** | ||||
6854 | */ | ||||
6855 | CIccXform *CIccXformMpe::Create(CIccProfile *pProfile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */, | ||||
6856 | icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */, | ||||
6857 | CIccCreateXformHintManager *pHintManager/* =NULL */) | ||||
6858 | { | ||||
6859 | CIccXform *rv = NULL__null; | ||||
6860 | icRenderingIntent nTagIntent = nIntent; | ||||
6861 | bool bUseSpectralPCS = false; | ||||
6862 | bool bAbsToRel = false; | ||||
6863 | icXformLutType nUseLutType = nLutType; | ||||
6864 | bool bUseColorimeticTags = true; | ||||
6865 | bool bUseDToB = true; | ||||
6866 | |||||
6867 | if (nLutType == icXformLutSpectral) { | ||||
6868 | nUseLutType = icXformLutColor; | ||||
6869 | bUseColorimeticTags = false; | ||||
6870 | } | ||||
6871 | else if (nLutType == icXformLutColorimetric) { | ||||
6872 | nUseLutType = icXformLutColor; | ||||
6873 | bUseDToB = false; | ||||
6874 | } | ||||
6875 | |||||
6876 | if (nTagIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | ||||
6877 | nTagIntent = icPerceptual; | ||||
6878 | |||||
6879 | switch (nUseLutType) { | ||||
6880 | case icXformLutColor: | ||||
6881 | if (bInput) { | ||||
6882 | CIccTag *pTag = NULL__null; | ||||
6883 | if (bUseDToB) { | ||||
6884 | pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent); | ||||
6885 | |||||
6886 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | ||||
6887 | pTag = pProfile->FindTag(icSigDToB1Tag); | ||||
6888 | if (pTag) | ||||
6889 | nTagIntent = icRelativeColorimetric; | ||||
6890 | } | ||||
6891 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | ||||
6892 | pTag = pProfile->FindTag(icSigDToB3Tag); | ||||
6893 | if (pTag) { | ||||
6894 | nTagIntent = icAbsoluteColorimetric; | ||||
6895 | bAbsToRel = true; | ||||
6896 | } | ||||
6897 | } | ||||
6898 | |||||
6899 | if (!pTag) { | ||||
6900 | pTag = pProfile->FindTag(icSigDToB0Tag); | ||||
6901 | } | ||||
6902 | } | ||||
6903 | |||||
6904 | //Unsupported elements cause fall back behavior | ||||
6905 | if (pTag && !pTag->IsSupported()) | ||||
6906 | pTag = NULL__null; | ||||
6907 | |||||
6908 | if (pTag && pProfile->m_Header.spectralPCS) { | ||||
6909 | bUseSpectralPCS = true; | ||||
6910 | } | ||||
6911 | |||||
6912 | if (bUseColorimeticTags) { | ||||
6913 | if (!pTag) { | ||||
6914 | if (nTagIntent == icAbsoluteColorimetric) | ||||
6915 | nTagIntent = icRelativeColorimetric; | ||||
6916 | pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent); | ||||
6917 | } | ||||
6918 | |||||
6919 | if (!pTag) { | ||||
6920 | pTag = pProfile->FindTag(icSigAToB0Tag); | ||||
6921 | } | ||||
6922 | } | ||||
6923 | |||||
6924 | if (!pTag) { | ||||
6925 | if (bUseColorimeticTags && pProfile->m_Header.colorSpace == icSigRgbData && pProfile->m_Header.version < icVersionNumberV50x05000000) { | ||||
6926 | rv = new CIccXformMatrixTRC(); | ||||
6927 | } | ||||
6928 | else | ||||
6929 | return NULL__null; | ||||
6930 | } | ||||
6931 | else if (pTag->GetType()==icSigMultiProcessElementType) { | ||||
6932 | rv = new CIccXformMpe(pTag); | ||||
6933 | } | ||||
6934 | else { | ||||
6935 | switch(pProfile->m_Header.colorSpace) { | ||||
6936 | case icSigXYZData: | ||||
6937 | case icSigLabData: | ||||
6938 | case icSigLuvData: | ||||
6939 | case icSigYCbCrData: | ||||
6940 | case icSigYxyData: | ||||
6941 | case icSigRgbData: | ||||
6942 | case icSigHsvData: | ||||
6943 | case icSigHlsData: | ||||
6944 | case icSigCmyData: | ||||
6945 | case icSig3colorData: | ||||
6946 | rv = new CIccXform3DLut(pTag); | ||||
6947 | break; | ||||
6948 | |||||
6949 | case icSigCmykData: | ||||
6950 | case icSig4colorData: | ||||
6951 | rv = new CIccXform4DLut(pTag); | ||||
6952 | break; | ||||
6953 | |||||
6954 | default: | ||||
6955 | rv = new CIccXformNDLut(pTag); | ||||
6956 | break; | ||||
6957 | } | ||||
6958 | } | ||||
6959 | } | ||||
6960 | else { | ||||
6961 | CIccTag *pTag = NULL__null; | ||||
6962 | |||||
6963 | if (bUseDToB) { | ||||
6964 | pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent); | ||||
6965 | |||||
6966 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | ||||
6967 | pTag = pProfile->FindTag(icSigBToD1Tag); | ||||
6968 | if (pTag) | ||||
6969 | nTagIntent = icRelativeColorimetric; | ||||
6970 | } | ||||
6971 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | ||||
6972 | pTag = pProfile->FindTag(icSigBToD3Tag); | ||||
6973 | if (pTag) { | ||||
6974 | nTagIntent = icAbsoluteColorimetric; | ||||
6975 | bAbsToRel = true; | ||||
6976 | } | ||||
6977 | } | ||||
6978 | |||||
6979 | if (!pTag) { | ||||
6980 | pTag = pProfile->FindTag(icSigBToD0Tag); | ||||
6981 | } | ||||
6982 | } | ||||
6983 | |||||
6984 | //Unsupported elements cause fall back behavior | ||||
6985 | if (pTag && !pTag->IsSupported()) | ||||
6986 | pTag = NULL__null; | ||||
6987 | |||||
6988 | if (bUseColorimeticTags) { | ||||
6989 | if (!pTag) { | ||||
6990 | if (nTagIntent == icAbsoluteColorimetric) | ||||
6991 | nTagIntent = icRelativeColorimetric; | ||||
6992 | pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent); | ||||
6993 | } | ||||
6994 | |||||
6995 | if (!pTag) { | ||||
6996 | pTag = pProfile->FindTag(icSigBToA0Tag); | ||||
6997 | } | ||||
6998 | } | ||||
6999 | |||||
7000 | if (!pTag) { | ||||
7001 | if (bUseColorimeticTags && pProfile->m_Header.colorSpace == icSigRgbData && pProfile->m_Header.version<icVersionNumberV50x05000000) { | ||||
7002 | rv = new CIccXformMatrixTRC(); | ||||
7003 | } | ||||
7004 | else | ||||
7005 | return NULL__null; | ||||
7006 | } | ||||
7007 | |||||
7008 | if (pTag->GetType()==icSigMultiProcessElementType) { | ||||
7009 | rv = new CIccXformMpe(pTag); | ||||
7010 | } | ||||
7011 | else { | ||||
7012 | switch(pProfile->m_Header.pcs) { | ||||
7013 | case icSigXYZData: | ||||
7014 | case icSigLabData: | ||||
7015 | rv = new CIccXform3DLut(pTag); | ||||
7016 | |||||
7017 | default: | ||||
7018 | break; | ||||
7019 | } | ||||
7020 | } | ||||
7021 | } | ||||
7022 | break; | ||||
7023 | |||||
7024 | case icXformLutNamedColor: | ||||
7025 | { | ||||
7026 | CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag); | ||||
7027 | if (!pTag) | ||||
7028 | return NULL__null; | ||||
7029 | |||||
7030 | rv = new CIccXformNamedColor(pTag, pProfile->m_Header.pcs, pProfile->m_Header.colorSpace, | ||||
7031 | pProfile->m_Header.spectralPCS, | ||||
7032 | &pProfile->m_Header.spectralRange, | ||||
7033 | &pProfile->m_Header.biSpectralRange); | ||||
7034 | } | ||||
7035 | break; | ||||
7036 | |||||
7037 | case icXformLutPreview: | ||||
7038 | { | ||||
7039 | bInput = false; | ||||
7040 | CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent); | ||||
7041 | if (!pTag) { | ||||
7042 | pTag = pProfile->FindTag(icSigPreview0Tag); | ||||
7043 | } | ||||
7044 | if (!pTag) { | ||||
7045 | return NULL__null; | ||||
7046 | } | ||||
7047 | else { | ||||
7048 | switch(pProfile->m_Header.pcs) { | ||||
7049 | case icSigXYZData: | ||||
7050 | case icSigLabData: | ||||
7051 | rv = new CIccXform3DLut(pTag); | ||||
7052 | |||||
7053 | default: | ||||
7054 | break; | ||||
7055 | } | ||||
7056 | } | ||||
7057 | } | ||||
7058 | break; | ||||
7059 | |||||
7060 | case icXformLutGamut: | ||||
7061 | { | ||||
7062 | bInput = false; | ||||
7063 | CIccTag *pTag = pProfile->FindTag(icSigGamutTag); | ||||
7064 | if (!pTag) { | ||||
7065 | return NULL__null; | ||||
7066 | } | ||||
7067 | else { | ||||
7068 | switch(pProfile->m_Header.pcs) { | ||||
7069 | case icSigXYZData: | ||||
7070 | case icSigLabData: | ||||
7071 | rv = new CIccXform3DLut(pTag); | ||||
7072 | |||||
7073 | default: | ||||
7074 | break; | ||||
7075 | } | ||||
7076 | } | ||||
7077 | } | ||||
7078 | break; | ||||
7079 | } | ||||
7080 | |||||
7081 | if (rv) { | ||||
7082 | rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel); | ||||
7083 | } | ||||
7084 | |||||
7085 | return rv; | ||||
7086 | } | ||||
7087 | |||||
7088 | /** | ||||
7089 | ************************************************************************** | ||||
7090 | * Name: CIccXformMPE::IsLateBinding | ||||
7091 | * | ||||
7092 | * Purpose: | ||||
7093 | * Determines if any processing elements are late binding with connection | ||||
7094 | * conditions | ||||
7095 | ************************************************************************** | ||||
7096 | */ | ||||
7097 | bool CIccXformMpe::IsLateBinding() const | ||||
7098 | { | ||||
7099 | if (m_pTag) | ||||
7100 | return m_pTag->IsLateBinding(); | ||||
7101 | |||||
7102 | return false; | ||||
7103 | } | ||||
7104 | |||||
7105 | /** | ||||
7106 | ************************************************************************** | ||||
7107 | * Name: CIccXformMPE::IsLateBindingReflectance | ||||
7108 | * | ||||
7109 | * Purpose: | ||||
7110 | * Determines if any processing elements are late binding with connection | ||||
7111 | * conditions | ||||
7112 | ************************************************************************** | ||||
7113 | */ | ||||
7114 | bool CIccXformMpe::IsLateBindingReflectance() const | ||||
7115 | { | ||||
7116 | if (m_pTag) | ||||
7117 | return m_pTag->IsLateBindingReflectance(); | ||||
7118 | |||||
7119 | return false; | ||||
7120 | } | ||||
7121 | |||||
7122 | /** | ||||
7123 | ************************************************************************** | ||||
7124 | * Name: CIccXformMPE::GetConnectionConditions | ||||
7125 | * | ||||
7126 | * Purpose: | ||||
7127 | * Gets appropriate connection conditions | ||||
7128 | ************************************************************************** | ||||
7129 | */ | ||||
7130 | IIccProfileConnectionConditions *CIccXformMpe::GetConnectionConditions() const | ||||
7131 | { | ||||
7132 | if (m_pAppliedPCC) | ||||
7133 | return m_pAppliedPCC; | ||||
7134 | |||||
7135 | return m_pConnectionConditions; | ||||
7136 | } | ||||
7137 | |||||
7138 | /** | ||||
7139 | ************************************************************************** | ||||
7140 | * Name: CIccXformMPE::SetAppliedCC | ||||
7141 | * | ||||
7142 | * Purpose: | ||||
7143 | * This creates combined connection conditions based on profile, | ||||
7144 | * alternate connection conditions and whether reflectance is used | ||||
7145 | * by any late binding processing elements. | ||||
7146 | ************************************************************************** | ||||
7147 | */ | ||||
7148 | void CIccXformMpe::SetAppliedCC(IIccProfileConnectionConditions *pPCC) | ||||
7149 | { | ||||
7150 | if (!pPCC) { | ||||
7151 | if (m_pAppliedPCC && m_bDeleteAppliedPCC) { | ||||
7152 | delete m_pAppliedPCC; | ||||
7153 | } | ||||
7154 | m_pAppliedPCC = NULL__null; | ||||
7155 | m_bDeleteAppliedPCC = false; | ||||
7156 | return; | ||||
7157 | } | ||||
7158 | |||||
7159 | if (m_pTag) { | ||||
7160 | bool bReflectance = m_pTag->IsLateBindingReflectance(); | ||||
7161 | |||||
7162 | if (pPCC != (IIccProfileConnectionConditions *)m_pProfile) { | ||||
7163 | if (!bReflectance) { | ||||
7164 | const CIccTagSpectralViewingConditions *pViewPCC = pPCC ? pPCC->getPccViewingConditions() : NULL__null; | ||||
7165 | const CIccTagSpectralViewingConditions *pViewProfile = m_pProfile ? m_pProfile->getPccViewingConditions() : NULL__null; | ||||
7166 | |||||
7167 | if (pViewPCC && pViewProfile && | ||||
7168 | pViewPCC->getStdIllumiant() == pViewProfile->getStdIllumiant() && | ||||
7169 | pViewPCC->getIlluminantCCT() == pViewProfile->getIlluminantCCT() && | ||||
7170 | pViewPCC->getStdIllumiant() != icIlluminantUnknown) { | ||||
7171 | m_pAppliedPCC = pPCC; | ||||
7172 | m_bDeleteAppliedPCC = false; | ||||
7173 | } | ||||
7174 | else { | ||||
7175 | m_pAppliedPCC = new CIccCombinedConnectionConditions(m_pProfile, pPCC, bReflectance); | ||||
7176 | m_bDeleteAppliedPCC = true; | ||||
7177 | } | ||||
7178 | } | ||||
7179 | else { | ||||
7180 | m_pAppliedPCC = new CIccCombinedConnectionConditions(m_pProfile, pPCC, bReflectance); | ||||
7181 | m_bDeleteAppliedPCC = true; | ||||
7182 | } | ||||
7183 | } | ||||
7184 | else { | ||||
7185 | m_pAppliedPCC = NULL__null; | ||||
7186 | } | ||||
7187 | } | ||||
7188 | else { | ||||
7189 | m_pAppliedPCC = pPCC; | ||||
7190 | m_bDeleteAppliedPCC = false; | ||||
7191 | } | ||||
7192 | } | ||||
7193 | |||||
7194 | |||||
7195 | /** | ||||
7196 | ************************************************************************** | ||||
7197 | * Name: CIccXformMPE::Begin | ||||
7198 | * | ||||
7199 | * Purpose: | ||||
7200 | * This function will be called before the xform is applied. Derived objects | ||||
7201 | * should also call the base class function to initialize for Absolute Colorimetric | ||||
7202 | * Intent handling which is performed through the use of the CheckSrcAbs and | ||||
7203 | * CheckDstAbs functions. | ||||
7204 | ************************************************************************** | ||||
7205 | */ | ||||
7206 | icStatusCMM CIccXformMpe::Begin() | ||||
7207 | { | ||||
7208 | icStatusCMM status; | ||||
7209 | status = CIccXform::Begin(); | ||||
7210 | |||||
7211 | if (status != icCmmStatOk) | ||||
7212 | return status; | ||||
7213 | |||||
7214 | if (!m_pTag) { | ||||
7215 | return icCmmStatInvalidLut; | ||||
7216 | } | ||||
7217 | |||||
7218 | if (!m_pTag->Begin(icElemInterpLinear, GetProfileCC(), GetConnectionConditions(), GetCmmEnvVarLookup())) { | ||||
7219 | return icCmmStatInvalidProfile; | ||||
7220 | } | ||||
7221 | |||||
7222 | return icCmmStatOk; | ||||
7223 | } | ||||
7224 | |||||
7225 | |||||
7226 | /** | ||||
7227 | ************************************************************************** | ||||
7228 | * Name: CIccXformMpe::GetNewApply | ||||
7229 | * | ||||
7230 | * Purpose: | ||||
7231 | * This Factory function allocates data specific for the application of the xform. | ||||
7232 | * This allows multiple threads to simultaneously use the same xform. | ||||
7233 | ************************************************************************** | ||||
7234 | */ | ||||
7235 | CIccApplyXform *CIccXformMpe::GetNewApply(icStatusCMM &status) | ||||
7236 | { | ||||
7237 | if (!m_pTag) | ||||
7238 | return NULL__null; | ||||
7239 | |||||
7240 | CIccApplyXformMpe *rv= new CIccApplyXformMpe(this); | ||||
7241 | |||||
7242 | if (!rv) { | ||||
7243 | status = icCmmStatAllocErr; | ||||
7244 | return NULL__null; | ||||
7245 | } | ||||
7246 | |||||
7247 | rv->m_pApply = m_pTag->GetNewApply(); | ||||
7248 | if (!rv->m_pApply) { | ||||
7249 | status = icCmmStatAllocErr; | ||||
7250 | delete rv; | ||||
7251 | return NULL__null; | ||||
7252 | } | ||||
7253 | |||||
7254 | status = icCmmStatOk; | ||||
7255 | return rv; | ||||
7256 | } | ||||
7257 | |||||
7258 | |||||
7259 | /** | ||||
7260 | ************************************************************************** | ||||
7261 | * Name: CIccXformMPE::Apply | ||||
7262 | * | ||||
7263 | * Purpose: | ||||
7264 | * Does the actual application of the Xform. | ||||
7265 | * | ||||
7266 | * Args: | ||||
7267 | * pApply = ApplyXform object containging temporary storage used during Apply | ||||
7268 | * DstPixel = Destination pixel where the result is stored, | ||||
7269 | * SrcPixel = Source pixel which is to be applied. | ||||
7270 | ************************************************************************** | ||||
7271 | */ | ||||
7272 | void CIccXformMpe::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | ||||
7273 | { | ||||
7274 | const CIccTagMultiProcessElement *pTag = m_pTag; | ||||
7275 | |||||
7276 | if (!m_bInput) { //PCS comming in? | ||||
7277 | if (m_nIntent != icAbsoluteColorimetric || m_nIntent != m_nTagIntent) { //B2D3 tags don't need abs conversion | ||||
7278 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | ||||
7279 | } | ||||
7280 | |||||
7281 | //Since MPE tags use "real" values for PCS we need to convert from | ||||
7282 | //internal encoding used by IccProfLib | ||||
7283 | icFloatNumber temp[3]; | ||||
7284 | switch (GetSrcSpace()) { | ||||
7285 | case icSigXYZData: | ||||
7286 | memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber)); | ||||
7287 | icXyzFromPcs(temp); | ||||
7288 | SrcPixel = &temp[0]; | ||||
7289 | break; | ||||
7290 | |||||
7291 | case icSigLabData: | ||||
7292 | memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber)); | ||||
7293 | icLabFromPcs(temp); | ||||
7294 | SrcPixel = &temp[0]; | ||||
7295 | break; | ||||
7296 | |||||
7297 | default: | ||||
7298 | break; | ||||
7299 | } | ||||
7300 | } | ||||
7301 | |||||
7302 | //Note: pApply should be a CIccApplyXformMpe type here | ||||
7303 | CIccApplyXformMpe *pApplyMpe = (CIccApplyXformMpe *)pApply; | ||||
7304 | |||||
7305 | pTag->Apply(pApplyMpe->m_pApply, DstPixel, SrcPixel); | ||||
7306 | |||||
7307 | if (m_bInput) { //PCS going out? | ||||
7308 | //Since MPE tags use "real" values for PCS we need to convert to | ||||
7309 | //internal encoding used by IccProfLib | ||||
7310 | switch(GetDstSpace()) { | ||||
7311 | case icSigXYZData: | ||||
7312 | icXyzToPcs(DstPixel); | ||||
7313 | break; | ||||
7314 | |||||
7315 | case icSigLabData: | ||||
7316 | icLabToPcs(DstPixel); | ||||
7317 | break; | ||||
7318 | |||||
7319 | default: | ||||
7320 | break; | ||||
7321 | } | ||||
7322 | |||||
7323 | if (m_nIntent != icAbsoluteColorimetric || m_nIntent != m_nTagIntent) { //D2B3 tags don't need abs conversion | ||||
7324 | CheckDstAbs(DstPixel); | ||||
7325 | } | ||||
7326 | } | ||||
7327 | } | ||||
7328 | |||||
7329 | /** | ||||
7330 | ************************************************************************** | ||||
7331 | * Name: CIccApplyXformMpe::CIccApplyXformMpe | ||||
7332 | * | ||||
7333 | * Purpose: | ||||
7334 | * Constructor | ||||
7335 | ************************************************************************** | ||||
7336 | */ | ||||
7337 | CIccApplyXformMpe::CIccApplyXformMpe(CIccXformMpe *pXform) : CIccApplyXform(pXform) | ||||
7338 | { | ||||
7339 | } | ||||
7340 | |||||
7341 | /** | ||||
7342 | ************************************************************************** | ||||
7343 | * Name: CIccApplyXformMpe::~CIccApplyXformMpe | ||||
7344 | * | ||||
7345 | * Purpose: | ||||
7346 | * Destructor | ||||
7347 | ************************************************************************** | ||||
7348 | */ | ||||
7349 | CIccApplyXformMpe::~CIccApplyXformMpe() | ||||
7350 | { | ||||
7351 | } | ||||
7352 | |||||
7353 | |||||
7354 | /** | ||||
7355 | ************************************************************************** | ||||
7356 | * Name: CIccApplyCmm::CIccApplyCmm | ||||
7357 | * | ||||
7358 | * Purpose: | ||||
7359 | * Constructor | ||||
7360 | * | ||||
7361 | * Args: | ||||
7362 | * pCmm = ptr to CMM to apply against | ||||
7363 | ************************************************************************** | ||||
7364 | */ | ||||
7365 | CIccApplyCmm::CIccApplyCmm(CIccCmm *pCmm) | ||||
7366 | { | ||||
7367 | m_pCmm = pCmm; | ||||
7368 | m_pPCS = m_pCmm->GetPCS(); | ||||
7369 | |||||
7370 | m_Xforms = new CIccApplyXformList; | ||||
7371 | m_Xforms->clear(); | ||||
7372 | |||||
7373 | m_Pixel = NULL__null; | ||||
7374 | m_Pixel2 = NULL__null; | ||||
7375 | } | ||||
7376 | |||||
7377 | /** | ||||
7378 | ************************************************************************** | ||||
7379 | * Name: CIccApplyCmm::~CIccApplyCmm | ||||
7380 | * | ||||
7381 | * Purpose: | ||||
7382 | * Destructor | ||||
7383 | ************************************************************************** | ||||
7384 | */ | ||||
7385 | CIccApplyCmm::~CIccApplyCmm() | ||||
7386 | { | ||||
7387 | if (m_Xforms) { | ||||
7388 | CIccApplyXformList::iterator i; | ||||
7389 | |||||
7390 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | ||||
7391 | if (i->ptr) | ||||
7392 | delete i->ptr; | ||||
7393 | } | ||||
7394 | |||||
7395 | delete m_Xforms; | ||||
7396 | } | ||||
7397 | |||||
7398 | if (m_pPCS) | ||||
7399 | delete m_pPCS; | ||||
7400 | |||||
7401 | if (m_Pixel) | ||||
7402 | free(m_Pixel); | ||||
7403 | if (m_Pixel2) | ||||
7404 | free(m_Pixel2); | ||||
7405 | } | ||||
7406 | |||||
7407 | bool CIccApplyCmm::InitPixel() | ||||
7408 | { | ||||
7409 | if (m_Pixel && m_Pixel2) | ||||
7410 | return true; | ||||
7411 | |||||
7412 | icUInt16Number nSamples = 16; | ||||
7413 | CIccApplyXformList::iterator i; | ||||
7414 | |||||
7415 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | ||||
7416 | if (i->ptr->GetXform()) { | ||||
7417 | icUInt16Number nXformSamples = i->ptr->GetXform()->GetNumDstSamples(); | ||||
7418 | if (nXformSamples>nSamples) | ||||
7419 | nSamples=nXformSamples; | ||||
7420 | } | ||||
7421 | } | ||||
7422 | m_Pixel = (icFloatNumber*)malloc(nSamples*sizeof(icFloatNumber)); | ||||
7423 | m_Pixel2 = (icFloatNumber*)malloc(nSamples*sizeof(icFloatNumber)); | ||||
7424 | |||||
7425 | if (!m_Pixel || !m_Pixel2) | ||||
7426 | return false; | ||||
7427 | |||||
7428 | return true; | ||||
7429 | } | ||||
7430 | |||||
7431 | |||||
7432 | /** | ||||
7433 | ************************************************************************** | ||||
7434 | * Name: CIccApplyCmm::Apply | ||||
7435 | * | ||||
7436 | * Purpose: | ||||
7437 | * Does the actual application of the Xforms in the list. | ||||
7438 | * | ||||
7439 | * Args: | ||||
7440 | * DstPixel = Destination pixel where the result is stored, | ||||
7441 | * SrcPixel = Source pixel which is to be applied. | ||||
7442 | ************************************************************************** | ||||
7443 | */ | ||||
7444 | icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) | ||||
7445 | { | ||||
7446 | icFloatNumber *pDst, *pTmp; | ||||
7447 | const icFloatNumber *pSrc; | ||||
7448 | CIccApplyXformList::iterator i; | ||||
7449 | const CIccXform *pLastXform; | ||||
7450 | int j, n = (int)m_Xforms->size(); | ||||
7451 | bool bNoClip; | ||||
7452 | |||||
7453 | if (!n) | ||||
7454 | return icCmmStatBadXform; | ||||
7455 | |||||
7456 | if (!m_Pixel && !InitPixel()) { | ||||
7457 | return icCmmStatAllocErr; | ||||
7458 | } | ||||
7459 | |||||
7460 | m_pPCS->Reset(m_pCmm->m_nSrcSpace); | ||||
7461 | |||||
7462 | pSrc = SrcPixel; | ||||
7463 | pDst = m_Pixel; | ||||
7464 | |||||
7465 | if (n>1) { | ||||
7466 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | ||||
7467 | |||||
7468 | i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform())); | ||||
7469 | pTmp = (icFloatNumber*)pSrc; | ||||
7470 | pSrc = pDst; | ||||
7471 | if (pTmp == SrcPixel) | ||||
7472 | pDst = m_Pixel2; | ||||
7473 | else | ||||
7474 | pDst = pTmp; | ||||
7475 | } | ||||
7476 | |||||
7477 | pLastXform = i->ptr->GetXform(); | ||||
7478 | i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, pLastXform)); | ||||
7479 | bNoClip = pLastXform->NoClipPCS(); | ||||
7480 | } | ||||
7481 | else if (n==1) { | ||||
7482 | i = m_Xforms->begin(); | ||||
7483 | |||||
7484 | pLastXform = i->ptr->GetXform(); | ||||
7485 | i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, pLastXform)); | ||||
7486 | bNoClip = pLastXform->NoClipPCS(); | ||||
7487 | } | ||||
7488 | else { | ||||
7489 | bNoClip = true; | ||||
7490 | } | ||||
7491 | |||||
7492 | m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace, bNoClip); | ||||
7493 | |||||
7494 | return icCmmStatOk; | ||||
7495 | } | ||||
7496 | |||||
7497 | /** | ||||
7498 | ************************************************************************** | ||||
7499 | * Name: CIccApplyCmm::Apply | ||||
7500 | * | ||||
7501 | * Purpose: | ||||
7502 | * Does the actual application of the Xforms in the list. | ||||
7503 | * | ||||
7504 | * Args: | ||||
7505 | * DstPixel = Destination pixel where the result is stored, | ||||
7506 | * SrcPixel = Source pixel which is to be applied. | ||||
7507 | ************************************************************************** | ||||
7508 | */ | ||||
7509 | icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) | ||||
7510 | { | ||||
7511 | icFloatNumber *pDst, *pTmp; | ||||
7512 | const icFloatNumber *pSrc; | ||||
7513 | CIccApplyXformList::iterator i; | ||||
7514 | int j, n = (int)m_Xforms->size(); | ||||
7515 | icUInt32Number k; | ||||
7516 | |||||
7517 | if (!n) | ||||
7518 | return icCmmStatBadXform; | ||||
7519 | |||||
7520 | if (!m_Pixel && !InitPixel()) { | ||||
7521 | return icCmmStatAllocErr; | ||||
7522 | } | ||||
7523 | |||||
7524 | for (k=0; k<nPixels; k++) { | ||||
7525 | m_pPCS->Reset(m_pCmm->m_nSrcSpace); | ||||
7526 | |||||
7527 | pSrc = SrcPixel; | ||||
7528 | pDst = m_Pixel; | ||||
7529 | |||||
7530 | if (n>1) { | ||||
7531 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | ||||
7532 | |||||
7533 | i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform())); | ||||
7534 | pTmp = (icFloatNumber*)pSrc; | ||||
7535 | pSrc = pDst; | ||||
7536 | if (pTmp==SrcPixel) | ||||
7537 | pDst = m_Pixel2; | ||||
7538 | else | ||||
7539 | pDst = pTmp; | ||||
7540 | } | ||||
7541 | |||||
7542 | i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, i->ptr->GetXform())); | ||||
7543 | } | ||||
7544 | else if (n==1) { | ||||
7545 | i = m_Xforms->begin(); | ||||
7546 | i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, i->ptr->GetXform())); | ||||
7547 | } | ||||
7548 | |||||
7549 | m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace); | ||||
7550 | |||||
7551 | DstPixel += m_pCmm->GetDestSamples(); | ||||
7552 | SrcPixel += m_pCmm->GetSourceSamples(); | ||||
7553 | } | ||||
7554 | |||||
7555 | return icCmmStatOk; | ||||
7556 | } | ||||
7557 | |||||
7558 | void CIccApplyCmm::AppendApplyXform(CIccApplyXform *pApplyXform) | ||||
7559 | { | ||||
7560 | CIccApplyXformPtr ptr; | ||||
7561 | ptr.ptr = pApplyXform; | ||||
7562 | |||||
7563 | m_Xforms->push_back(ptr); | ||||
7564 | } | ||||
7565 | |||||
7566 | /** | ||||
7567 | ************************************************************************** | ||||
7568 | * Name: CIccCmm::CIccCmm | ||||
7569 | * | ||||
7570 | * Purpose: | ||||
7571 | * Constructor | ||||
7572 | * | ||||
7573 | * Args: | ||||
7574 | * nSrcSpace = signature of the source color space, | ||||
7575 | * nDestSpace = signature of the destination color space, | ||||
7576 | * bFirstInput = true if the first profile added is an input profile | ||||
7577 | ************************************************************************** | ||||
7578 | */ | ||||
7579 | CIccCmm::CIccCmm(icColorSpaceSignature nSrcSpace /*=icSigUnknownData*/, | ||||
7580 | icColorSpaceSignature nDestSpace /*=icSigUnknownData*/, | ||||
7581 | bool bFirstInput /*=true*/) | ||||
7582 | { | ||||
7583 | m_bValid = false; | ||||
7584 | |||||
7585 | m_bLastInput = !bFirstInput; | ||||
7586 | m_nSrcSpace = nSrcSpace; | ||||
7587 | m_nDestSpace = nDestSpace; | ||||
7588 | |||||
7589 | m_nLastSpace = nSrcSpace; | ||||
7590 | m_nLastIntent = icUnknownIntent((icRenderingIntent) 0x3f3f3f3f); | ||||
7591 | |||||
7592 | m_Xforms = new CIccXformList; | ||||
7593 | m_Xforms->clear(); | ||||
7594 | |||||
7595 | m_pApply = NULL__null; | ||||
7596 | } | ||||
7597 | |||||
7598 | /** | ||||
7599 | ************************************************************************** | ||||
7600 | * Name: CIccCmm::~CIccCmm | ||||
7601 | * | ||||
7602 | * Purpose: | ||||
7603 | * Destructor | ||||
7604 | ************************************************************************** | ||||
7605 | */ | ||||
7606 | CIccCmm::~CIccCmm() | ||||
7607 | { | ||||
7608 | if (m_Xforms) { | ||||
7609 | CIccXformList::iterator i; | ||||
7610 | |||||
7611 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | ||||
7612 | if (i->ptr) | ||||
7613 | delete i->ptr; | ||||
7614 | } | ||||
7615 | |||||
7616 | delete m_Xforms; | ||||
7617 | } | ||||
7618 | |||||
7619 | if (m_pApply) | ||||
7620 | delete m_pApply; | ||||
7621 | } | ||||
7622 | |||||
7623 | const icChar* CIccCmm::GetStatusText(icStatusCMM stat) | ||||
7624 | { | ||||
7625 | switch (stat) { | ||||
7626 | case icCmmStatBad: | ||||
7627 | return "Bad CMM"; | ||||
7628 | case icCmmStatOk: | ||||
7629 | return "OK"; | ||||
7630 | case icCmmStatCantOpenProfile: | ||||
7631 | return "Cannot open profile"; | ||||
7632 | case icCmmStatBadSpaceLink: | ||||
7633 | return "Invalid space link"; | ||||
7634 | case icCmmStatInvalidProfile: | ||||
7635 | return "Invalid profile"; | ||||
7636 | case icCmmStatBadXform: | ||||
7637 | return "Invalid profile transform"; | ||||
7638 | case icCmmStatInvalidLut: | ||||
7639 | return "Invalid Look-Up Table"; | ||||
7640 | case icCmmStatProfileMissingTag: | ||||
7641 | return "Missing tag in profile"; | ||||
7642 | case icCmmStatColorNotFound: | ||||
7643 | return "Color not found"; | ||||
7644 | case icCmmStatIncorrectApply: | ||||
7645 | return "Incorrect Apply object"; | ||||
7646 | case icCmmStatBadColorEncoding: | ||||
7647 | return "Invalid color encoding used"; | ||||
7648 | case icCmmStatAllocErr: | ||||
7649 | return "Memory allocation error"; | ||||
7650 | case icCmmStatBadLutType: | ||||
7651 | return "Invalid Look-Up Table type"; | ||||
7652 | case icCmmStatIdentityXform: | ||||
7653 | return "Identity transform used"; | ||||
7654 | case icCmmStatUnsupportedPcsLink: | ||||
7655 | return "Unsupported PCS Link used"; | ||||
7656 | case icCmmStatBadConnection: | ||||
7657 | return "Invalid profile connection"; | ||||
7658 | case icCmmStatBadTintXform: | ||||
7659 | return "Invalid tint transform"; | ||||
7660 | case icCmmStatTooManySamples: | ||||
7661 | return "Too many samples used"; | ||||
7662 | case icCmmStatBadMCSLink: | ||||
7663 | return "Invalid MCS link connection"; | ||||
7664 | default: | ||||
7665 | return "Unknown CMM Status value"; | ||||
7666 | |||||
7667 | } | ||||
7668 | } | ||||
7669 | |||||
7670 | /** | ||||
7671 | ************************************************************************** | ||||
7672 | * Name: CIccCmm::AddXform | ||||
7673 | * | ||||
7674 | * Purpose: | ||||
7675 | * Adds a profile at the end of the Xform list | ||||
7676 | * | ||||
7677 | * Args: | ||||
7678 | * szProfilePath = file name of the profile to be added, | ||||
7679 | * nIntent = rendering intent to be used with the profile, | ||||
7680 | * nInterp = type of interpolation to be used with the profile, | ||||
7681 | * nLutType = selection of which transform lut to use | ||||
7682 | * pHintManager = hints for creating the xform | ||||
7683 | * | ||||
7684 | * Return: | ||||
7685 | * icCmmStatOk, if the profile was added to the list succesfully | ||||
7686 | ************************************************************************** | ||||
7687 | */ | ||||
7688 | icStatusCMM CIccCmm::AddXform(const icChar *szProfilePath, | ||||
7689 | icRenderingIntent nIntent /*=icUnknownIntent*/, | ||||
7690 | icXformInterp nInterp /*icXformInterp*/, | ||||
7691 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
7692 | icXformLutType nLutType /*=icXformLutColor*/, | ||||
7693 | bool bUseD2BxB2DxTags /*=true*/, | ||||
7694 | CIccCreateXformHintManager *pHintManager /*=NULL*/, | ||||
7695 | bool bUseSubProfile /*=false*/) | ||||
7696 | { | ||||
7697 | CIccProfile *pProfile = OpenIccProfile(szProfilePath, bUseSubProfile); | ||||
7698 | |||||
7699 | if (!pProfile) | ||||
7700 | return icCmmStatCantOpenProfile; | ||||
7701 | |||||
7702 | icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | ||||
7703 | |||||
7704 | if (rv != icCmmStatOk) | ||||
7705 | delete pProfile; | ||||
7706 | |||||
7707 | return rv; | ||||
7708 | } | ||||
7709 | |||||
7710 | |||||
7711 | /** | ||||
7712 | ************************************************************************** | ||||
7713 | * Name: CIccCmm::AddXform | ||||
7714 | * | ||||
7715 | * Purpose: | ||||
7716 | * Adds a profile at the end of the Xform list | ||||
7717 | * | ||||
7718 | * Args: | ||||
7719 | * pProfileMem = ptr to profile loaded into memory. Note: this memory | ||||
7720 | * needs to be available until after the Begin() function is called. | ||||
7721 | * nProfileLen = size in bytes of profile loaded into memory | ||||
7722 | * nIntent = rendering intent to be used with the profile, | ||||
7723 | * nInterp = type of interpolation to be used with the profile, | ||||
7724 | * nLutType = selection of which transform lut to use | ||||
7725 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | ||||
7726 | * pHintManager = hints for creating the xform | ||||
7727 | * | ||||
7728 | * Return: | ||||
7729 | * icCmmStatOk, if the profile was added to the list succesfully | ||||
7730 | ************************************************************************** | ||||
7731 | */ | ||||
7732 | icStatusCMM CIccCmm::AddXform(icUInt8Number *pProfileMem, | ||||
7733 | icUInt32Number nProfileLen, | ||||
7734 | icRenderingIntent nIntent /*=icUnknownIntent*/, | ||||
7735 | icXformInterp nInterp /*icXformInterp*/, | ||||
7736 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
7737 | icXformLutType nLutType /*=icXformLutColor*/, | ||||
7738 | bool bUseD2BxB2DxTags /*=true*/, | ||||
7739 | CIccCreateXformHintManager *pHintManager /*=NULL*/, | ||||
7740 | bool bUseSubProfile /*=false*/) | ||||
7741 | { | ||||
7742 | CIccMemIO *pFile = new CIccMemIO; | ||||
7743 | |||||
7744 | if (!pFile || !pFile->Attach(pProfileMem, nProfileLen, bUseSubProfile)) | ||||
7745 | return icCmmStatCantOpenProfile; | ||||
7746 | |||||
7747 | CIccProfile *pProfile = new CIccProfile; | ||||
7748 | |||||
7749 | if (!pProfile) | ||||
7750 | return icCmmStatCantOpenProfile; | ||||
7751 | |||||
7752 | if (!pProfile->Attach(pFile)) { | ||||
7753 | delete pFile; | ||||
7754 | delete pProfile; | ||||
7755 | return icCmmStatCantOpenProfile; | ||||
7756 | } | ||||
7757 | |||||
7758 | icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | ||||
7759 | |||||
7760 | if (rv != icCmmStatOk) | ||||
7761 | delete pProfile; | ||||
7762 | |||||
7763 | return rv; | ||||
7764 | } | ||||
7765 | |||||
7766 | |||||
7767 | /** | ||||
7768 | ************************************************************************** | ||||
7769 | * Name: CIccCmm::AddXform | ||||
7770 | * | ||||
7771 | * Purpose: | ||||
7772 | * Adds a profile at the end of the Xform list | ||||
7773 | * | ||||
7774 | * Args: | ||||
7775 | * pProfile = pointer to the CIccProfile object to be added, | ||||
7776 | * nIntent = rendering intent to be used with the profile, | ||||
7777 | * nInterp = type of interpolation to be used with the profile, | ||||
7778 | * nLutType = selection of which transform lut to use | ||||
7779 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | ||||
7780 | * pHintManager = hints for creating the xform | ||||
7781 | * | ||||
7782 | * Return: | ||||
7783 | * icCmmStatOk, if the profile was added to the list succesfully | ||||
7784 | ************************************************************************** | ||||
7785 | */ | ||||
7786 | icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile, | ||||
7787 | icRenderingIntent nIntent /*=icUnknownIntent*/, | ||||
7788 | icXformInterp nInterp /*=icInterpLinear*/, | ||||
7789 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
7790 | icXformLutType nLutType /*=icXformLutColor*/, | ||||
7791 | bool bUseD2BxB2DxTags /*=true*/, | ||||
7792 | CIccCreateXformHintManager *pHintManager /*=NULL*/) | ||||
7793 | { | ||||
7794 | icColorSpaceSignature nSrcSpace, nDstSpace; | ||||
7795 | bool bInput = !m_bLastInput; | ||||
7796 | |||||
7797 | if (!pProfile) | ||||
7798 | return icCmmStatInvalidProfile; | ||||
7799 | |||||
7800 | switch(pProfile->m_Header.deviceClass) { | ||||
7801 | case icSigMaterialIdentificationClass: | ||||
7802 | case icSigMaterialVisualizationClass: | ||||
7803 | case icSigMaterialLinkClass: | ||||
7804 | nIntent = icPerceptual; | ||||
7805 | nLutType = icXformLutMCS; | ||||
7806 | |||||
7807 | default: | ||||
7808 | break; | ||||
7809 | } | ||||
7810 | |||||
7811 | switch (nLutType) { | ||||
7812 | case icXformLutColor: | ||||
7813 | case icXformLutColorimetric: | ||||
7814 | case icXformLutSpectral: | ||||
7815 | { | ||||
7816 | //Check pProfile if nIntent and input can be found. | ||||
7817 | if (bInput) { | ||||
7818 | nSrcSpace = pProfile->m_Header.colorSpace; | ||||
7819 | |||||
7820 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) | ||||
7821 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
7822 | else | ||||
7823 | nDstSpace = pProfile->m_Header.pcs; | ||||
7824 | } | ||||
7825 | else { | ||||
7826 | if (pProfile->m_Header.deviceClass == icSigLinkClass) { | ||||
7827 | return icCmmStatBadSpaceLink; | ||||
7828 | } | ||||
7829 | if (pProfile->m_Header.deviceClass == icSigAbstractClass) { | ||||
7830 | bInput = true; | ||||
7831 | nIntent = icPerceptual; // Note: icPerceptualIntent = 0 | ||||
7832 | } | ||||
7833 | |||||
7834 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) | ||||
7835 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
7836 | else | ||||
7837 | nSrcSpace = pProfile->m_Header.pcs; | ||||
7838 | |||||
7839 | nDstSpace = pProfile->m_Header.colorSpace; | ||||
7840 | } | ||||
7841 | } | ||||
7842 | break; | ||||
7843 | |||||
7844 | case icXformLutPreview: | ||||
7845 | nSrcSpace = pProfile->m_Header.pcs; | ||||
7846 | nDstSpace = pProfile->m_Header.pcs; | ||||
7847 | bInput = false; | ||||
7848 | break; | ||||
7849 | |||||
7850 | case icXformLutGamut: | ||||
7851 | nSrcSpace = pProfile->m_Header.pcs; | ||||
7852 | nDstSpace = icSigGamutData((icColorSpaceSignature) 0x67616D74); | ||||
7853 | bInput = true; | ||||
7854 | break; | ||||
7855 | |||||
7856 | case icXformLutBRDFParam: | ||||
7857 | if (!bInput) | ||||
7858 | return icCmmStatBadSpaceLink; | ||||
7859 | nSrcSpace = pProfile->m_Header.colorSpace; | ||||
7860 | nDstSpace = icSigBRDFParameters((icColorSpaceSignature) 0x62700000); | ||||
7861 | bInput = true; | ||||
7862 | break; | ||||
7863 | |||||
7864 | case icXformLutBRDFDirect: | ||||
7865 | if (!bInput) | ||||
7866 | return icCmmStatBadSpaceLink; | ||||
7867 | nSrcSpace = icSigBRDFDirect((icColorSpaceSignature) 0x62640000); | ||||
7868 | nDstSpace = pProfile->m_Header.pcs; | ||||
7869 | bInput = true; | ||||
7870 | break; | ||||
7871 | |||||
7872 | case icXformLutBRDFMcsParam: | ||||
7873 | if (!bInput) | ||||
7874 | return icCmmStatBadSpaceLink; | ||||
7875 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | ||||
7876 | nDstSpace = icSigBRDFParameters((icColorSpaceSignature) 0x62700000); | ||||
7877 | break; | ||||
7878 | |||||
7879 | case icXformLutMCS: | ||||
7880 | if (bInput) { | ||||
7881 | nSrcSpace = pProfile->m_Header.colorSpace; | ||||
7882 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | ||||
7883 | } | ||||
7884 | else { | ||||
7885 | if (m_Xforms->size()) { | ||||
7886 | CIccXformList::iterator prev = --(m_Xforms->end()); | ||||
7887 | |||||
7888 | //Make sure previous profile connects with an icXformLutMCS | ||||
7889 | if (prev->ptr->GetXformType()!=icXformLutMCS) { | ||||
7890 | //check to see if we can convert previous xform to connect via an MCS | ||||
7891 | if (!prev->ptr->GetProfile()->m_Header.mcs) { | ||||
7892 | return icCmmStatBadMCSLink; | ||||
7893 | } | ||||
7894 | |||||
7895 | CIccXform *pPrev = prev->ptr; | ||||
7896 | CIccXform *pNew = CIccXform::Create(pPrev->GetProfilePtr(), pPrev->IsInput(), pPrev->GetIntent(), pPrev->GetInterp(), | ||||
7897 | pPrev->GetConnectionConditions(), icXformLutMCS, bUseD2BxB2DxTags, pHintManager); | ||||
7898 | |||||
7899 | if (pNew) { | ||||
7900 | pPrev->DetachAll(); | ||||
7901 | delete pPrev; | ||||
7902 | } | ||||
7903 | |||||
7904 | prev->ptr = pNew; | ||||
7905 | |||||
7906 | } | ||||
7907 | } | ||||
7908 | else { | ||||
7909 | return icCmmStatBadMCSLink; | ||||
7910 | } | ||||
7911 | |||||
7912 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | ||||
7913 | if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) { | ||||
7914 | if (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS) { | ||||
7915 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
7916 | } | ||||
7917 | else { | ||||
7918 | nDstSpace = pProfile->m_Header.pcs; | ||||
7919 | } | ||||
7920 | } | ||||
7921 | else if (pProfile->m_Header.deviceClass==icSigMaterialLinkClass) { | ||||
7922 | nDstSpace = pProfile->m_Header.colorSpace; | ||||
7923 | } | ||||
7924 | else { | ||||
7925 | return icCmmStatBadSpaceLink; | ||||
7926 | } | ||||
7927 | } | ||||
7928 | break; | ||||
7929 | |||||
7930 | default: | ||||
7931 | return icCmmStatBadLutType; | ||||
7932 | } | ||||
7933 | |||||
7934 | //Make sure colorspaces match with previous xforms | ||||
7935 | if (!m_Xforms->size()) { | ||||
7936 | if (m_nSrcSpace == icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | ||||
7937 | m_nLastSpace = nSrcSpace; | ||||
7938 | m_nSrcSpace = nSrcSpace; | ||||
7939 | } | ||||
7940 | else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)((m_nSrcSpace)==(nSrcSpace) || ((((m_nSrcSpace)==icSigXYZData || (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nSrcSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) )) { | ||||
7941 | return icCmmStatBadSpaceLink; | ||||
7942 | } | ||||
7943 | } | ||||
7944 | else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)((m_nLastSpace)==(nSrcSpace) || ((((m_nLastSpace)==icSigXYZData || (m_nLastSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) )) { | ||||
7945 | return icCmmStatBadSpaceLink; | ||||
7946 | } | ||||
7947 | |||||
7948 | if (nSrcSpace==icSigNamedData) | ||||
7949 | return icCmmStatBadSpaceLink; | ||||
7950 | |||||
7951 | //Automatic creation of intent from header/last profile | ||||
7952 | if (nIntent==icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) { | ||||
7953 | if (bInput) { | ||||
7954 | nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent; | ||||
7955 | } | ||||
7956 | else { | ||||
7957 | nIntent = m_nLastIntent; | ||||
7958 | } | ||||
7959 | if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | ||||
7960 | nIntent = icPerceptual; | ||||
7961 | } | ||||
7962 | |||||
7963 | CIccXformPtr Xform; | ||||
7964 | |||||
7965 | Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | ||||
7966 | |||||
7967 | if (!Xform.ptr) { | ||||
7968 | return icCmmStatBadXform; | ||||
7969 | } | ||||
7970 | |||||
7971 | if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) { | ||||
7972 | bInput = true; | ||||
7973 | } | ||||
7974 | |||||
7975 | m_nLastSpace = nDstSpace; | ||||
7976 | m_nLastIntent = nIntent; | ||||
7977 | m_bLastInput = bInput; | ||||
7978 | |||||
7979 | m_Xforms->push_back(Xform); | ||||
7980 | |||||
7981 | return icCmmStatOk; | ||||
7982 | } | ||||
7983 | |||||
7984 | /** | ||||
7985 | ************************************************************************** | ||||
7986 | * Name: CIccCmm::AddXform | ||||
7987 | * | ||||
7988 | * Purpose: | ||||
7989 | * Adds a profile at the end of the Xform list | ||||
7990 | * | ||||
7991 | * Args: | ||||
7992 | * pProfile = pointer to the CIccProfile object to be added, | ||||
7993 | * nIntent = rendering intent to be used with the profile, | ||||
7994 | * nInterp = type of interpolation to be used with the profile, | ||||
7995 | * nLutType = selection of which transform lut to use | ||||
7996 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | ||||
7997 | * pHintManager = hints for creating the xform | ||||
7998 | * | ||||
7999 | * Return: | ||||
8000 | * icCmmStatOk, if the profile was added to the list succesfully | ||||
8001 | ************************************************************************** | ||||
8002 | */ | ||||
8003 | icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile, | ||||
8004 | CIccTag *pXformTag, | ||||
8005 | icRenderingIntent nIntent/*= icUnknownIntent*/, | ||||
8006 | icXformInterp nInterp /*=icInterpLinear*/, | ||||
8007 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
8008 | bool bUseSpectralPCS /*=false*/, | ||||
8009 | CIccCreateXformHintManager *pHintManager /*=NULL*/) | ||||
8010 | { | ||||
8011 | icColorSpaceSignature nSrcSpace, nDstSpace; | ||||
8012 | bool bInput = !m_bLastInput; | ||||
8013 | |||||
8014 | if (!pProfile) | ||||
8015 | return icCmmStatInvalidProfile; | ||||
8016 | |||||
8017 | switch (pProfile->m_Header.deviceClass) { | ||||
8018 | case icSigMaterialIdentificationClass: | ||||
8019 | case icSigMaterialVisualizationClass: | ||||
8020 | case icSigMaterialLinkClass: | ||||
8021 | return icCmmStatBadLutType; | ||||
8022 | |||||
8023 | default: | ||||
8024 | break; | ||||
8025 | } | ||||
8026 | |||||
8027 | //Check pProfile if nIntent and input can be found. | ||||
8028 | if (bInput) { | ||||
8029 | nSrcSpace = pProfile->m_Header.colorSpace; | ||||
8030 | |||||
8031 | if (bUseSpectralPCS && pProfile->m_Header.spectralPCS) | ||||
8032 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
8033 | else { | ||||
8034 | nDstSpace = pProfile->m_Header.pcs; | ||||
8035 | bUseSpectralPCS = false; | ||||
8036 | } | ||||
8037 | } | ||||
8038 | else { | ||||
8039 | if (pProfile->m_Header.deviceClass == icSigLinkClass) { | ||||
8040 | return icCmmStatBadSpaceLink; | ||||
8041 | } | ||||
8042 | if (pProfile->m_Header.deviceClass == icSigAbstractClass) { | ||||
8043 | bInput = true; | ||||
8044 | nIntent = icPerceptual; // Note: icPerceptualIntent = 0 | ||||
8045 | } | ||||
8046 | |||||
8047 | if (bUseSpectralPCS && pProfile->m_Header.spectralPCS) | ||||
8048 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
8049 | else { | ||||
8050 | nSrcSpace = pProfile->m_Header.pcs; | ||||
8051 | bUseSpectralPCS = false; | ||||
8052 | } | ||||
8053 | |||||
8054 | nDstSpace = pProfile->m_Header.colorSpace; | ||||
8055 | } | ||||
8056 | |||||
8057 | //Make sure colorspaces match with previous xforms | ||||
8058 | if (!m_Xforms->size()) { | ||||
8059 | if (m_nSrcSpace == icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | ||||
8060 | m_nLastSpace = nSrcSpace; | ||||
8061 | m_nSrcSpace = nSrcSpace; | ||||
8062 | } | ||||
8063 | else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)((m_nSrcSpace)==(nSrcSpace) || ((((m_nSrcSpace)==icSigXYZData || (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nSrcSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) )) { | ||||
8064 | return icCmmStatBadSpaceLink; | ||||
8065 | } | ||||
8066 | } | ||||
8067 | else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)((m_nLastSpace)==(nSrcSpace) || ((((m_nLastSpace)==icSigXYZData || (m_nLastSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) )) { | ||||
8068 | return icCmmStatBadSpaceLink; | ||||
8069 | } | ||||
8070 | |||||
8071 | if (nSrcSpace == icSigNamedData) | ||||
8072 | return icCmmStatBadSpaceLink; | ||||
8073 | |||||
8074 | //Automatic creation of intent from header/last profile | ||||
8075 | if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) { | ||||
8076 | if (bInput) { | ||||
8077 | nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent; | ||||
8078 | } | ||||
8079 | else { | ||||
8080 | nIntent = m_nLastIntent; | ||||
8081 | } | ||||
8082 | if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | ||||
8083 | nIntent = icPerceptual; | ||||
8084 | } | ||||
8085 | |||||
8086 | CIccXformPtr Xform; | ||||
8087 | |||||
8088 | Xform.ptr = CIccXform::Create(pProfile, pXformTag, bInput, nIntent, nInterp, pPcc, bUseSpectralPCS, pHintManager); | ||||
8089 | |||||
8090 | if (!Xform.ptr) { | ||||
8091 | return icCmmStatBadXform; | ||||
8092 | } | ||||
8093 | |||||
8094 | m_nLastSpace = nDstSpace; | ||||
8095 | m_nLastIntent = nIntent; | ||||
8096 | m_bLastInput = bInput; | ||||
8097 | |||||
8098 | m_Xforms->push_back(Xform); | ||||
8099 | |||||
8100 | return icCmmStatOk; | ||||
8101 | } | ||||
8102 | |||||
8103 | /** | ||||
8104 | ************************************************************************** | ||||
8105 | * Name: CIccCmm::AddXform | ||||
8106 | * | ||||
8107 | * Purpose: | ||||
8108 | * Adds a profile at the end of the Xform list | ||||
8109 | * | ||||
8110 | * Args: | ||||
8111 | * Profile = reference a CIccProfile object that will be copies and added, | ||||
8112 | * nIntent = rendering intent to be used with the profile, | ||||
8113 | * nInterp = type of interpolation to be used with the profile, | ||||
8114 | * nLutType = selection of which transform lut to use | ||||
8115 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | ||||
8116 | * pHintManager = hints for creating the xform | ||||
8117 | * | ||||
8118 | * Return: | ||||
8119 | * icCmmStatOk, if the profile was added to the list succesfully | ||||
8120 | ************************************************************************** | ||||
8121 | */ | ||||
8122 | icStatusCMM CIccCmm::AddXform(CIccProfile &Profile, | ||||
8123 | icRenderingIntent nIntent /*=icUnknownIntent*/, | ||||
8124 | icXformInterp nInterp /*=icInterpLinear*/, | ||||
8125 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
8126 | icXformLutType nLutType /*=icXformLutColor*/, | ||||
8127 | bool bUseD2BxB2DxTags /*=true*/, | ||||
8128 | CIccCreateXformHintManager *pHintManager /*=NULL*/) | ||||
8129 | { | ||||
8130 | CIccProfile *pProfile = new CIccProfile(Profile); | ||||
8131 | |||||
8132 | if (!pProfile) | ||||
8133 | return icCmmStatAllocErr; | ||||
8134 | |||||
8135 | icStatusCMM stat = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | ||||
8136 | |||||
8137 | if (stat != icCmmStatOk) | ||||
8138 | delete pProfile; | ||||
8139 | |||||
8140 | return stat; | ||||
8141 | } | ||||
8142 | |||||
8143 | icStatusCMM CIccCmm::CheckPCSConnections(bool bUsePCSConversions/*=false*/) | ||||
8144 | { | ||||
8145 | icStatusCMM rv = icCmmStatOk; | ||||
8146 | |||||
8147 | CIccXformList::iterator last, next; | ||||
8148 | CIccXformList xforms; | ||||
8149 | CIccXformPtr ptr; | ||||
8150 | bool bUsesPcsXforms = false; | ||||
8151 | |||||
8152 | next=m_Xforms->begin(); | ||||
8153 | |||||
8154 | if (next!=m_Xforms->end()) { | ||||
8155 | last = next; | ||||
8156 | next++; | ||||
8157 | |||||
8158 | xforms.push_back(*last); | ||||
8159 | |||||
8160 | for (;next!=m_Xforms->end(); last=next, next++) { | ||||
8161 | if ((last->ptr->IsInput() && last->ptr->IsMCS() && next->ptr->IsMCS()) || | ||||
8162 | (IsSpaceSpectralPCS(last->ptr->GetDstSpace()) || IsSpaceSpectralPCS(next->ptr->GetSrcSpace())) || | ||||
8163 | (!bUsePCSConversions && | ||||
8164 | (IsSpaceColorimetricPCS(last->ptr->GetDstSpace())((last->ptr->GetDstSpace())==icSigXYZData || (last-> ptr->GetDstSpace())==icSigLabData) || IsSpaceColorimetricPCS(next->ptr->GetSrcSpace())((next->ptr->GetSrcSpace())==icSigXYZData || (next-> ptr->GetSrcSpace())==icSigLabData)))) { | ||||
8165 | last->ptr->SetDstPCSConversion(false); | ||||
8166 | next->ptr->SetSrcPCSConversion(false); | ||||
8167 | CIccPcsXform *pPcs = new CIccPcsXform(); | ||||
8168 | |||||
8169 | if (!pPcs) { | ||||
8170 | return icCmmStatAllocErr; | ||||
8171 | } | ||||
8172 | |||||
8173 | rv = pPcs->Connect(last->ptr, next->ptr); | ||||
8174 | |||||
8175 | if (rv!=icCmmStatOk && rv!=icCmmStatIdentityXform) | ||||
8176 | return rv; | ||||
8177 | |||||
8178 | if (rv!=icCmmStatIdentityXform) { | ||||
8179 | ptr.ptr = pPcs; | ||||
8180 | xforms.push_back(ptr); | ||||
8181 | } | ||||
8182 | else { | ||||
8183 | delete pPcs; | ||||
8184 | } | ||||
8185 | |||||
8186 | bUsesPcsXforms = true; | ||||
8187 | } | ||||
8188 | xforms.push_back(*next); | ||||
8189 | } | ||||
8190 | } | ||||
8191 | |||||
8192 | if (bUsesPcsXforms) { | ||||
8193 | *m_Xforms = xforms; | ||||
8194 | } | ||||
8195 | |||||
8196 | return rv; | ||||
8197 | } | ||||
8198 | |||||
8199 | /** | ||||
8200 | ************************************************************************** | ||||
8201 | * Name: CIccCmm::SetLateBindingCC | ||||
8202 | * | ||||
8203 | * Purpose: | ||||
8204 | * Initializes the LateBinding Connection Conditions used by | ||||
8205 | * colorimetric based transforms | ||||
8206 | * | ||||
8207 | ************************************************************************** | ||||
8208 | */ | ||||
8209 | void CIccCmm::SetLateBindingCC() | ||||
8210 | { | ||||
8211 | CIccXformList::iterator i; | ||||
8212 | CIccXform *pLastXform = NULL__null; | ||||
8213 | |||||
8214 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | ||||
8215 | if (i->ptr->IsInput()) { | ||||
8216 | if (i->ptr->IsLateBinding()) { | ||||
8217 | CIccXformList::iterator j=i; | ||||
8218 | j++; | ||||
8219 | if (j!=m_Xforms->end()) { | ||||
8220 | if (j->ptr->IsLateBinding()) { | ||||
8221 | i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | ||||
8222 | j->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | ||||
8223 | pLastXform = i->ptr; | ||||
8224 | } | ||||
8225 | else { | ||||
8226 | i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | ||||
8227 | j->ptr->SetAppliedCC(j->ptr->GetConnectionConditions()); | ||||
8228 | pLastXform = NULL__null; | ||||
8229 | } | ||||
8230 | } | ||||
8231 | else { | ||||
8232 | i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | ||||
8233 | pLastXform = NULL__null; | ||||
8234 | } | ||||
8235 | } | ||||
8236 | else if (IsSpaceSpectralPCS(i->ptr->GetDstSpace())) { | ||||
8237 | CIccXformList::iterator j=i; | ||||
8238 | j++; | ||||
8239 | if (j!=m_Xforms->end()) { | ||||
8240 | if (j->ptr->IsLateBinding()) { | ||||
8241 | j->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | ||||
8242 | pLastXform = i->ptr; | ||||
8243 | } | ||||
8244 | else if (!j->ptr->IsAbstract()){ | ||||
8245 | j->ptr->SetAppliedCC(j->ptr->GetConnectionConditions()); | ||||
8246 | pLastXform = NULL__null; | ||||
8247 | } | ||||
8248 | } | ||||
8249 | } | ||||
8250 | else { | ||||
8251 | pLastXform = NULL__null; | ||||
8252 | } | ||||
8253 | } | ||||
8254 | else { | ||||
8255 | if (!pLastXform) | ||||
8256 | i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | ||||
8257 | else | ||||
8258 | pLastXform = NULL__null; | ||||
8259 | } | ||||
8260 | } | ||||
8261 | } | ||||
8262 | |||||
8263 | |||||
8264 | /** | ||||
8265 | ************************************************************************** | ||||
8266 | * Name: CIccCmm::Begin | ||||
8267 | * | ||||
8268 | * Purpose: | ||||
8269 | * Does the initialization of the Xforms before Apply() is called. | ||||
8270 | * Must be called before Apply(). | ||||
8271 | * | ||||
8272 | ************************************************************************** | ||||
8273 | */ | ||||
8274 | icStatusCMM CIccCmm::Begin(bool bAllocApplyCmm/*=true*/, bool bUsePCSConversions/*=false*/) | ||||
8275 | { | ||||
8276 | if (m_pApply) | ||||
8277 | return icCmmStatOk; | ||||
8278 | |||||
8279 | if (m_nDestSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | ||||
8280 | m_nDestSpace = m_nLastSpace; | ||||
8281 | } | ||||
8282 | else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)((m_nDestSpace)==(m_nLastSpace) || ((((m_nDestSpace)==icSigXYZData || (m_nDestSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nDestSpace )) && (((m_nLastSpace)==icSigXYZData || (m_nLastSpace )==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace))) || ((( (icColorSpaceSignature)(((icUInt32Number)m_nDestSpace)&0xffff0000 ))==icSigSrcMCSChannelData) && (((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData )) )) { | ||||
8283 | return icCmmStatBadSpaceLink; | ||||
8284 | } | ||||
8285 | |||||
8286 | if (m_nSrcSpace==icSigNamedData || m_nDestSpace==icSigNamedData) { | ||||
8287 | return icCmmStatBadSpaceLink; | ||||
8288 | } | ||||
8289 | |||||
8290 | SetLateBindingCC(); | ||||
8291 | |||||
8292 | icStatusCMM rv; | ||||
8293 | CIccXformList::iterator i; | ||||
8294 | |||||
8295 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | ||||
8296 | |||||
8297 | rv = i->ptr->Begin(); | ||||
8298 | |||||
8299 | if (rv!= icCmmStatOk) | ||||
8300 | return rv; | ||||
8301 | } | ||||
8302 | |||||
8303 | rv = CheckPCSConnections(bUsePCSConversions); | ||||
8304 | if (rv != icCmmStatOk && rv!=icCmmStatIdentityXform) | ||||
8305 | return rv; | ||||
8306 | |||||
8307 | if (bAllocApplyCmm) { | ||||
8308 | m_pApply = GetNewApplyCmm(rv); | ||||
8309 | } | ||||
8310 | else | ||||
8311 | rv = icCmmStatOk; | ||||
8312 | |||||
8313 | return rv; | ||||
8314 | } | ||||
8315 | |||||
8316 | |||||
8317 | /** | ||||
8318 | ************************************************************************** | ||||
8319 | * Name: CIccCmm::GetNewApplyCmm | ||||
8320 | * | ||||
8321 | * Purpose: | ||||
8322 | * Allocates an CIccApplyCmm object that does the initialization of the Xforms | ||||
8323 | * that provides an Apply() function. | ||||
8324 | * Multiple CIccApplyCmm objects can be allocated and used in separate threads. | ||||
8325 | * | ||||
8326 | ************************************************************************** | ||||
8327 | */ | ||||
8328 | CIccApplyCmm *CIccCmm::GetNewApplyCmm(icStatusCMM &status) | ||||
8329 | { | ||||
8330 | CIccApplyCmm *pApply = new CIccApplyCmm(this); | ||||
8331 | |||||
8332 | if (!pApply) { | ||||
8333 | status = icCmmStatAllocErr; | ||||
8334 | return NULL__null; | ||||
8335 | } | ||||
8336 | |||||
8337 | CIccXformList::iterator i; | ||||
8338 | CIccApplyXform *pXform; | ||||
8339 | |||||
8340 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | ||||
8341 | pXform = i->ptr->GetNewApply(status); | ||||
8342 | if (!pXform || status != icCmmStatOk) { | ||||
8343 | delete pApply; | ||||
8344 | return NULL__null; | ||||
8345 | } | ||||
8346 | pApply->AppendApplyXform(pXform); | ||||
8347 | } | ||||
8348 | |||||
8349 | m_bValid = true; | ||||
8350 | |||||
8351 | status = icCmmStatOk; | ||||
8352 | |||||
8353 | return pApply; | ||||
8354 | } | ||||
8355 | |||||
8356 | |||||
8357 | /** | ||||
8358 | ************************************************************************** | ||||
8359 | * Name: CIccCmm::Apply | ||||
8360 | * | ||||
8361 | * Purpose: | ||||
8362 | * Uses the m_pApply object allocated during Begin to Apply the transformations | ||||
8363 | * associated with the CMM. | ||||
8364 | * | ||||
8365 | ************************************************************************** | ||||
8366 | */ | ||||
8367 | icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) | ||||
8368 | { | ||||
8369 | return m_pApply->Apply(DstPixel, SrcPixel); | ||||
8370 | } | ||||
8371 | |||||
8372 | |||||
8373 | /** | ||||
8374 | ************************************************************************** | ||||
8375 | * Name: CIccCmm::Apply | ||||
8376 | * | ||||
8377 | * Purpose: | ||||
8378 | * Uses the m_pApply object allocated during Begin to Apply the transformations | ||||
8379 | * associated with the CMM. | ||||
8380 | * | ||||
8381 | ************************************************************************** | ||||
8382 | */ | ||||
8383 | icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) | ||||
8384 | { | ||||
8385 | return m_pApply->Apply(DstPixel, SrcPixel, nPixels); | ||||
8386 | } | ||||
8387 | |||||
8388 | |||||
8389 | /** | ||||
8390 | ************************************************************************** | ||||
8391 | * Name: CIccCmm::RemoveAllIO() | ||||
8392 | * | ||||
8393 | * Purpose: | ||||
8394 | * Remove any attachments to CIccIO objects associated with the profiles | ||||
8395 | * related to the transforms attached to the CMM. | ||||
8396 | * Must be called after Begin(). | ||||
8397 | * | ||||
8398 | * Return: | ||||
8399 | * icCmmStatOK - All IO objects removed | ||||
8400 | * icCmmStatBadXform - Begin() has not been performed. | ||||
8401 | ************************************************************************** | ||||
8402 | */ | ||||
8403 | icStatusCMM CIccCmm::RemoveAllIO() | ||||
8404 | { | ||||
8405 | if (!Valid()) | ||||
8406 | return icCmmStatBadXform; | ||||
8407 | |||||
8408 | CIccXformList::iterator i; | ||||
8409 | |||||
8410 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | ||||
8411 | i->ptr->RemoveIO(); | ||||
8412 | } | ||||
8413 | |||||
8414 | return icCmmStatOk; | ||||
8415 | } | ||||
8416 | |||||
8417 | /** | ||||
8418 | ************************************************************************* | ||||
8419 | ** Name: CIccCmm::IsInGamut | ||||
8420 | ** | ||||
8421 | ** Purpose: | ||||
8422 | ** Function to check if internal representation of gamut is in gamut. Note | ||||
8423 | ** since gamut table is 8 bit and a color is considered to be in out of gamut | ||||
8424 | ** if the value is not zero. Then we need to check where the 8 bit representation | ||||
8425 | ** of the internal value is not zero. | ||||
8426 | ** | ||||
8427 | ** Args: | ||||
8428 | ** pInternal = internal pixel representation of gamut value | ||||
8429 | ** | ||||
8430 | ** Return: | ||||
8431 | ** true if in gamut, false if out of gamut | ||||
8432 | **************************************************************************/ | ||||
8433 | bool CIccCmm::IsInGamut(icFloatNumber *pInternal) | ||||
8434 | { | ||||
8435 | if (!((unsigned int)((*pInternal)*255.0))) | ||||
8436 | return true; | ||||
8437 | return false; | ||||
8438 | } | ||||
8439 | |||||
8440 | |||||
8441 | /** | ||||
8442 | ************************************************************************** | ||||
8443 | * Name: CIccCmm::ToInternalEncoding | ||||
8444 | * | ||||
8445 | * Purpose: | ||||
8446 | * Functions for converting to Internal representation of pixel colors. | ||||
8447 | * | ||||
8448 | * Args: | ||||
8449 | * nSpace = color space signature of the data, | ||||
8450 | * nEncode = icFloatColorEncoding type of the data, | ||||
8451 | * pInternal = converted data is stored here, | ||||
8452 | * pData = the data to be converted | ||||
8453 | * bClip = flag to clip to internal range | ||||
8454 | ************************************************************************** | ||||
8455 | */ | ||||
8456 | icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode, | ||||
8457 | icFloatNumber *pInternal, const icFloatNumber *pData, | ||||
8458 | bool bClip) | ||||
8459 | { | ||||
8460 | int nSamples = icGetSpaceSamples(nSpace); | ||||
8461 | if (!nSamples) | ||||
8462 | return icCmmStatBadColorEncoding; | ||||
8463 | |||||
8464 | |||||
8465 | icUInt16Number i; | ||||
8466 | CIccPixelBuf pInput(nSamples); | ||||
8467 | |||||
8468 | if (!pInput.get()) | ||||
8469 | return icCmmStatAllocErr; | ||||
8470 | |||||
8471 | memcpy(pInput, pData, nSamples*sizeof(icFloatNumber)); | ||||
8472 | bool bCLRspace = icIsSpaceCLR(nSpace); | ||||
8473 | |||||
8474 | switch(icGetColorSpaceType(nSpace)((icColorSpaceSignature)(((icUInt32Number)nSpace)&0xffff0000 ))) | ||||
8475 | { | ||||
8476 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | ||||
8477 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | ||||
8478 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | ||||
8479 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | ||||
8480 | bCLRspace = true; | ||||
8481 | break; | ||||
8482 | } | ||||
8483 | |||||
8484 | switch(nSpace) { | ||||
8485 | |||||
8486 | case icSigLabData: | ||||
8487 | { | ||||
8488 | switch(nEncode) { | ||||
8489 | case icEncodeValue: | ||||
8490 | { | ||||
8491 | icLabToPcs(pInput); | ||||
8492 | break; | ||||
8493 | } | ||||
8494 | case icEncodeFloat: | ||||
8495 | { | ||||
8496 | break; | ||||
8497 | } | ||||
8498 | case icEncode8Bit: | ||||
8499 | { | ||||
8500 | pInput[0] = icU8toF((icUInt8Number)pInput[0])*100.0f; | ||||
8501 | pInput[1] = icU8toAB((icUInt8Number)pInput[1]); | ||||
8502 | pInput[2] = icU8toAB((icUInt8Number)pInput[2]); | ||||
8503 | |||||
8504 | icLabToPcs(pInput); | ||||
8505 | break; | ||||
8506 | } | ||||
8507 | case icEncode16Bit: | ||||
8508 | { | ||||
8509 | pInput[0] = icU16toF((icUInt16Number)pInput[0]); | ||||
8510 | pInput[1] = icU16toF((icUInt16Number)pInput[1]); | ||||
8511 | pInput[2] = icU16toF((icUInt16Number)pInput[2]); | ||||
8512 | break; | ||||
8513 | } | ||||
8514 | case icEncode16BitV2: | ||||
8515 | { | ||||
8516 | pInput[0] = icU16toF((icUInt16Number)pInput[0]); | ||||
8517 | pInput[1] = icU16toF((icUInt16Number)pInput[1]); | ||||
8518 | pInput[2] = icU16toF((icUInt16Number)pInput[2]); | ||||
8519 | |||||
8520 | CIccPCS::Lab2ToLab4(pInput, pInput); | ||||
8521 | break; | ||||
8522 | } | ||||
8523 | default: | ||||
8524 | return icCmmStatBadColorEncoding; | ||||
8525 | break; | ||||
8526 | } | ||||
8527 | break; | ||||
8528 | } | ||||
8529 | |||||
8530 | case icSigXYZData: | ||||
8531 | { | ||||
8532 | switch(nEncode) { | ||||
8533 | case icEncodeValue: | ||||
8534 | { | ||||
8535 | pInput[0] = (icFloatNumber)pInput[0]; | ||||
8536 | pInput[1] = (icFloatNumber)pInput[1]; | ||||
8537 | pInput[2] = (icFloatNumber)pInput[2]; | ||||
8538 | icXyzToPcs(pInput); | ||||
8539 | break; | ||||
8540 | } | ||||
8541 | case icEncodePercent: | ||||
8542 | { | ||||
8543 | pInput[0] = (icFloatNumber)(pInput[0] / 100.0); | ||||
8544 | pInput[1] = (icFloatNumber)(pInput[1] / 100.0); | ||||
8545 | pInput[2] = (icFloatNumber)(pInput[2] / 100.0); | ||||
8546 | icXyzToPcs(pInput); | ||||
8547 | break; | ||||
8548 | } | ||||
8549 | case icEncodeFloat: | ||||
8550 | { | ||||
8551 | icXyzToPcs(pInput); | ||||
8552 | break; | ||||
8553 | } | ||||
8554 | |||||
8555 | case icEncode16Bit: | ||||
8556 | case icEncode16BitV2: | ||||
8557 | { | ||||
8558 | pInput[0] = icUSFtoD((icU1Fixed15Number)pInput[0]); | ||||
8559 | pInput[1] = icUSFtoD((icU1Fixed15Number)pInput[1]); | ||||
8560 | pInput[2] = icUSFtoD((icU1Fixed15Number)pInput[2]); | ||||
8561 | break; | ||||
8562 | } | ||||
8563 | |||||
8564 | default: | ||||
8565 | return icCmmStatBadColorEncoding; | ||||
8566 | break; | ||||
8567 | } | ||||
8568 | break; | ||||
8569 | } | ||||
8570 | |||||
8571 | case icSigNamedData: | ||||
8572 | return icCmmStatBadColorEncoding; | ||||
8573 | |||||
8574 | default: | ||||
8575 | { | ||||
8576 | switch(nEncode) { | ||||
8577 | case icEncodeValue: | ||||
8578 | { | ||||
8579 | if (!bCLRspace || nSamples<3) { | ||||
8580 | return icCmmStatBadColorEncoding; | ||||
8581 | } | ||||
8582 | if (nSamples==3) | ||||
8583 | icLabToPcs(pInput); | ||||
8584 | break; | ||||
8585 | } | ||||
8586 | |||||
8587 | case icEncodePercent: | ||||
8588 | { | ||||
8589 | if (bClip) { | ||||
8590 | for(i=0; i<nSamples; i++) { | ||||
8591 | pInput[i] = (icFloatNumber)(pInput[i]/100.0); | ||||
8592 | if (pInput[i] < 0.0) pInput[i] = 0.0; | ||||
8593 | if (pInput[i] > 1.0) pInput[i] = 1.0; | ||||
8594 | } | ||||
8595 | } | ||||
8596 | else { | ||||
8597 | for(i=0; i<nSamples; i++) { | ||||
8598 | pInput[i] = (icFloatNumber)(pInput[i]/100.0); | ||||
8599 | } | ||||
8600 | } | ||||
8601 | break; | ||||
8602 | } | ||||
8603 | |||||
8604 | case icEncodeFloat: | ||||
8605 | { | ||||
8606 | if (bClip) { | ||||
8607 | for(i=0; i<nSamples; i++) { | ||||
8608 | if (pInput[i] < 0.0) pInput[i] = 0.0; | ||||
8609 | if (pInput[i] > 1.0) pInput[i] = 1.0; | ||||
8610 | } | ||||
8611 | } | ||||
8612 | break; | ||||
8613 | } | ||||
8614 | |||||
8615 | case icEncode8Bit: | ||||
8616 | { | ||||
8617 | for(i=0; i<nSamples; i++) { | ||||
8618 | pInput[i] = icU8toF((icUInt8Number)pInput[i]); | ||||
8619 | } | ||||
8620 | break; | ||||
8621 | } | ||||
8622 | |||||
8623 | case icEncode16Bit: | ||||
8624 | case icEncode16BitV2: | ||||
8625 | { | ||||
8626 | for(i=0; i<nSamples; i++) { | ||||
8627 | pInput[i] = icU16toF((icUInt16Number)pInput[i]); | ||||
8628 | } | ||||
8629 | break; | ||||
8630 | } | ||||
8631 | |||||
8632 | default: | ||||
8633 | return icCmmStatBadColorEncoding; | ||||
8634 | break; | ||||
8635 | } | ||||
8636 | break; | ||||
8637 | } | ||||
8638 | } | ||||
8639 | |||||
8640 | memcpy(pInternal, pInput, nSamples*sizeof(icFloatNumber)); | ||||
8641 | return icCmmStatOk; | ||||
8642 | } | ||||
8643 | |||||
8644 | |||||
8645 | /** | ||||
8646 | ************************************************************************** | ||||
8647 | * Name: CIccCmm::ToInternalEncoding | ||||
8648 | * | ||||
8649 | * Purpose: | ||||
8650 | * Functions for converting to Internal representation of 8 bit pixel colors. | ||||
8651 | * | ||||
8652 | * Args: | ||||
8653 | * nSpace = color space signature of the data, | ||||
8654 | * nEncode = icFloatColorEncoding type of the data, | ||||
8655 | * pInternal = converted data is stored here, | ||||
8656 | * pData = the data to be converted | ||||
8657 | * bClip = flag to clip to internal range | ||||
8658 | ************************************************************************** | ||||
8659 | */ | ||||
8660 | icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal, | ||||
8661 | const icUInt8Number *pData) | ||||
8662 | { | ||||
8663 | switch(nSpace) { | ||||
8664 | case icSigRgbData: | ||||
8665 | { | ||||
8666 | pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 255.0); | ||||
8667 | pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 255.0); | ||||
8668 | pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 255.0); | ||||
8669 | |||||
8670 | return icCmmStatOk; | ||||
8671 | } | ||||
8672 | case icSigCmykData: | ||||
8673 | { | ||||
8674 | pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 255.0); | ||||
8675 | pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 255.0); | ||||
8676 | pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 255.0); | ||||
8677 | pInternal[3] = (icFloatNumber)((icFloatNumber)pData[3] / 255.0); | ||||
8678 | return icCmmStatOk; | ||||
8679 | } | ||||
8680 | default: | ||||
8681 | { | ||||
8682 | icUInt32Number i; | ||||
8683 | icUInt32Number nSamples = icGetSpaceSamples(nSpace); | ||||
8684 | CIccPixelBuf FloatPixel(nSamples); | ||||
8685 | if (!FloatPixel.get()) | ||||
8686 | return icCmmStatAllocErr; | ||||
8687 | |||||
8688 | for(i=0; i<nSamples; i++) { | ||||
8689 | FloatPixel[i] = (icFloatNumber)pData[i]; | ||||
8690 | } | ||||
8691 | return ToInternalEncoding(nSpace, icEncode8Bit, pInternal, FloatPixel); | ||||
8692 | } | ||||
8693 | } | ||||
8694 | |||||
8695 | } | ||||
8696 | |||||
8697 | |||||
8698 | /** | ||||
8699 | ************************************************************************** | ||||
8700 | * Name: CIccCmm::ToInternalEncoding | ||||
8701 | * | ||||
8702 | * Purpose: | ||||
8703 | * Functions for converting to Internal representation of 16 bit pixel colors. | ||||
8704 | * | ||||
8705 | * Args: | ||||
8706 | * nSpace = color space signature of the data, | ||||
8707 | * nEncode = icFloatColorEncoding type of the data, | ||||
8708 | * pInternal = converted data is stored here, | ||||
8709 | * pData = the data to be converted | ||||
8710 | * bClip = flag to clip to internal range | ||||
8711 | ************************************************************************** | ||||
8712 | */ | ||||
8713 | icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal, | ||||
8714 | const icUInt16Number *pData) | ||||
8715 | { | ||||
8716 | switch(nSpace) { | ||||
8717 | case icSigRgbData: | ||||
8718 | { | ||||
8719 | pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 65535.0); | ||||
8720 | pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 65535.0); | ||||
8721 | pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 65535.0); | ||||
8722 | |||||
8723 | return icCmmStatOk; | ||||
8724 | } | ||||
8725 | case icSigCmykData: | ||||
8726 | { | ||||
8727 | pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 65535.0); | ||||
8728 | pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 65535.0); | ||||
8729 | pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 65535.0); | ||||
8730 | pInternal[3] = (icFloatNumber)((icFloatNumber)pData[3] / 65535.0); | ||||
8731 | return icCmmStatOk; | ||||
8732 | } | ||||
8733 | default: | ||||
8734 | { | ||||
8735 | icUInt32Number i; | ||||
8736 | icUInt32Number nSamples = icGetSpaceSamples(nSpace); | ||||
8737 | CIccPixelBuf pFloatPixel(nSamples); | ||||
8738 | if (!pFloatPixel.get()) | ||||
8739 | return icCmmStatAllocErr; | ||||
8740 | |||||
8741 | for(i=0; i<nSamples; i++) { | ||||
8742 | pFloatPixel[i] = (icFloatNumber)pData[i]; | ||||
8743 | } | ||||
8744 | return ToInternalEncoding(nSpace, icEncode16Bit, pInternal, pFloatPixel); | ||||
8745 | } | ||||
8746 | } | ||||
8747 | } | ||||
8748 | |||||
8749 | |||||
8750 | /** | ||||
8751 | ************************************************************************** | ||||
8752 | * Name: CIccCmm::FromInternalEncoding | ||||
8753 | * | ||||
8754 | * Purpose: | ||||
8755 | * Functions for converting from Internal representation of pixel colors. | ||||
8756 | * | ||||
8757 | * Args: | ||||
8758 | * nSpace = color space signature of the data, | ||||
8759 | * nEncode = icFloatColorEncoding type of the data, | ||||
8760 | * pData = converted data is stored here, | ||||
8761 | * pInternal = the data to be converted | ||||
8762 | * bClip = flag to clip data to internal range | ||||
8763 | ************************************************************************** | ||||
8764 | */ | ||||
8765 | icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode, | ||||
8766 | icFloatNumber *pData, const icFloatNumber *pInternal, bool bClip) | ||||
8767 | { | ||||
8768 | int nSamples = icGetSpaceSamples(nSpace); | ||||
8769 | if (!nSamples) | ||||
8770 | return icCmmStatBadColorEncoding; | ||||
8771 | |||||
8772 | icUInt16Number i; | ||||
8773 | CIccPixelBuf pInput(nSamples); | ||||
8774 | |||||
8775 | if (!pInput.get()) | ||||
8776 | return icCmmStatAllocErr; | ||||
8777 | |||||
8778 | memcpy(pInput, pInternal, nSamples*sizeof(icFloatNumber)); | ||||
8779 | bool bCLRspace = (icIsSpaceCLR(nSpace) || (nSpace == icSigDevLabData((icColorSpaceSignature) 0x644C6162)) || (nSpace==icSigDevXYZData((icColorSpaceSignature) 0x6458595A))); | ||||
8780 | |||||
8781 | switch(nSpace) { | ||||
8782 | |||||
8783 | case icSigLabData: | ||||
8784 | { | ||||
8785 | switch(nEncode) { | ||||
8786 | case icEncodeValue: | ||||
8787 | { | ||||
8788 | icLabFromPcs(pInput); | ||||
8789 | break; | ||||
8790 | } | ||||
8791 | case icEncodeUnitFloat: | ||||
8792 | case icEncodeFloat: | ||||
8793 | { | ||||
8794 | break; | ||||
8795 | } | ||||
8796 | case icEncode8Bit: | ||||
8797 | { | ||||
8798 | icLabFromPcs(pInput); | ||||
8799 | |||||
8800 | pInput[0] = (icUInt8Number)(pInput[0]/100.0 * 255.0 + 0.5); | ||||
8801 | pInput[1] = icABtoU8(pInput[1]); | ||||
8802 | pInput[2] = icABtoU8(pInput[2]); | ||||
8803 | break; | ||||
8804 | } | ||||
8805 | case icEncode16Bit: | ||||
8806 | { | ||||
8807 | pInput[0] = icFtoU16(pInput[0]); | ||||
8808 | pInput[1] = icFtoU16(pInput[1]); | ||||
8809 | pInput[2] = icFtoU16(pInput[2]); | ||||
8810 | break; | ||||
8811 | } | ||||
8812 | case icEncode16BitV2: | ||||
8813 | { | ||||
8814 | CIccPCS::Lab4ToLab2(pInput, pInput); | ||||
8815 | |||||
8816 | pInput[0] = icFtoU16(pInput[0]); | ||||
8817 | pInput[1] = icFtoU16(pInput[1]); | ||||
8818 | pInput[2] = icFtoU16(pInput[2]); | ||||
8819 | break; | ||||
8820 | } | ||||
8821 | default: | ||||
8822 | return icCmmStatBadColorEncoding; | ||||
8823 | break; | ||||
8824 | } | ||||
8825 | break; | ||||
8826 | } | ||||
8827 | |||||
8828 | case icSigXYZData: | ||||
8829 | { | ||||
8830 | switch(nEncode) { | ||||
8831 | case icEncodeValue: | ||||
8832 | { | ||||
8833 | icXyzFromPcs(pInput); | ||||
8834 | break; | ||||
8835 | } | ||||
8836 | case icEncodePercent: | ||||
8837 | { | ||||
8838 | icXyzFromPcs(pInput); | ||||
8839 | pInput[0] = (icFloatNumber)(pInput[0] * 100.0); | ||||
8840 | pInput[1] = (icFloatNumber)(pInput[1] * 100.0); | ||||
8841 | pInput[2] = (icFloatNumber)(pInput[2] * 100.0); | ||||
8842 | break; | ||||
8843 | } | ||||
8844 | case icEncodeFloat: | ||||
8845 | case icEncodeUnitFloat: | ||||
8846 | { | ||||
8847 | icXyzFromPcs(pInput); | ||||
8848 | break; | ||||
8849 | } | ||||
8850 | |||||
8851 | case icEncode16Bit: | ||||
8852 | case icEncode16BitV2: | ||||
8853 | { | ||||
8854 | icXyzFromPcs(pInput); | ||||
8855 | pInput[0] = icDtoUSF(pInput[0]); | ||||
8856 | pInput[1] = icDtoUSF(pInput[1]); | ||||
8857 | pInput[2] = icDtoUSF(pInput[2]); | ||||
8858 | break; | ||||
8859 | } | ||||
8860 | |||||
8861 | default: | ||||
8862 | return icCmmStatBadColorEncoding; | ||||
8863 | break; | ||||
8864 | } | ||||
8865 | break; | ||||
8866 | } | ||||
8867 | |||||
8868 | case icSigNamedData: | ||||
8869 | return icCmmStatBadColorEncoding; | ||||
8870 | |||||
8871 | default: | ||||
8872 | { | ||||
8873 | switch(nEncode) { | ||||
8874 | case icEncodeValue: | ||||
8875 | { | ||||
8876 | if (nSpace == icSigDevXYZData((icColorSpaceSignature) 0x6458595A)) { | ||||
8877 | icXyzFromPcs(pInput); | ||||
8878 | } | ||||
8879 | else if (bCLRspace && nSamples >=3) { | ||||
8880 | icLabFromPcs(pInput); | ||||
8881 | } | ||||
8882 | break; | ||||
8883 | } | ||||
8884 | case icEncodePercent: | ||||
8885 | { | ||||
8886 | if (bClip) { | ||||
8887 | for(i=0; i<nSamples; i++) { | ||||
8888 | if (pInput[i] < 0.0) pInput[i] = 0.0; | ||||
8889 | if (pInput[i] > 1.0) pInput[i] = 1.0; | ||||
8890 | pInput[i] = (icFloatNumber)(pInput[i]*100.0); | ||||
8891 | } | ||||
8892 | } | ||||
8893 | else { | ||||
8894 | for(i=0; i<nSamples; i++) { | ||||
8895 | pInput[i] = (icFloatNumber)(pInput[i]*100.0); | ||||
8896 | } | ||||
8897 | } | ||||
8898 | break; | ||||
8899 | } | ||||
8900 | |||||
8901 | case icEncodeFloat: | ||||
8902 | break; | ||||
8903 | |||||
8904 | case icEncodeUnitFloat: | ||||
8905 | { | ||||
8906 | if (bClip) { | ||||
8907 | for(i=0; i<nSamples; i++) { | ||||
8908 | if (pInput[i] < 0.0) pInput[i] = 0.0; | ||||
8909 | if (pInput[i] > 1.0) pInput[i] = 1.0; | ||||
8910 | } | ||||
8911 | } | ||||
8912 | break; | ||||
8913 | } | ||||
8914 | |||||
8915 | case icEncode8Bit: | ||||
8916 | { | ||||
8917 | for(i=0; i<nSamples; i++) { | ||||
8918 | pInput[i] = icFtoU8(pInput[i]); | ||||
8919 | } | ||||
8920 | break; | ||||
8921 | } | ||||
8922 | |||||
8923 | case icEncode16Bit: | ||||
8924 | case icEncode16BitV2: | ||||
8925 | { | ||||
8926 | for(i=0; i<nSamples; i++) { | ||||
8927 | pInput[i] = icFtoU16(pInput[i]); | ||||
8928 | } | ||||
8929 | break; | ||||
8930 | } | ||||
8931 | |||||
8932 | default: | ||||
8933 | return icCmmStatBadColorEncoding; | ||||
8934 | break; | ||||
8935 | } | ||||
8936 | break; | ||||
8937 | } | ||||
8938 | } | ||||
8939 | |||||
8940 | memcpy(pData, pInput, nSamples*sizeof(icFloatNumber)); | ||||
8941 | return icCmmStatOk; | ||||
8942 | } | ||||
8943 | |||||
8944 | |||||
8945 | /** | ||||
8946 | ************************************************************************** | ||||
8947 | * Name: CIccCmm::FromInternalEncoding | ||||
8948 | * | ||||
8949 | * Purpose: | ||||
8950 | * Functions for converting from Internal representation of 8 bit pixel colors. | ||||
8951 | * | ||||
8952 | * Args: | ||||
8953 | * nSpace = color space signature of the data, | ||||
8954 | * nEncode = icFloatColorEncoding type of the data, | ||||
8955 | * pData = converted data is stored here, | ||||
8956 | * pInternal = the data to be converted | ||||
8957 | * bClip = flag to clip data to internal range | ||||
8958 | ************************************************************************** | ||||
8959 | */ | ||||
8960 | icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icUInt8Number *pData, | ||||
8961 | const icFloatNumber *pInternal) | ||||
8962 | { | ||||
8963 | switch(nSpace) { | ||||
8964 | case icSigRgbData: | ||||
8965 | { | ||||
8966 | pData[0] = icFtoU8(pInternal[0]); | ||||
8967 | pData[1] = icFtoU8(pInternal[1]); | ||||
8968 | pData[2] = icFtoU8(pInternal[2]); | ||||
8969 | |||||
8970 | return icCmmStatOk; | ||||
8971 | } | ||||
8972 | case icSigCmykData: | ||||
8973 | { | ||||
8974 | pData[0] = icFtoU8(pInternal[0]); | ||||
8975 | pData[1] = icFtoU8(pInternal[1]); | ||||
8976 | pData[2] = icFtoU8(pInternal[2]); | ||||
8977 | pData[3] = icFtoU8(pInternal[3]); | ||||
8978 | |||||
8979 | return icCmmStatOk; | ||||
8980 | } | ||||
8981 | default: | ||||
8982 | { | ||||
8983 | icUInt32Number i; | ||||
8984 | icUInt32Number nSamples = icGetSpaceSamples(nSpace); | ||||
8985 | |||||
8986 | CIccPixelBuf pFloatPixel(nSamples); | ||||
8987 | icStatusCMM convertStat; | ||||
8988 | |||||
8989 | if (!pFloatPixel.get()) | ||||
8990 | return icCmmStatAllocErr; | ||||
8991 | |||||
8992 | convertStat = FromInternalEncoding(nSpace, icEncode8Bit, pFloatPixel, pInternal); | ||||
8993 | if (convertStat) | ||||
8994 | return convertStat; | ||||
8995 | for(i=0; i<nSamples; i++) { | ||||
8996 | pData[i] = (icUInt8Number)(pFloatPixel[i] + 0.5); | ||||
8997 | } | ||||
8998 | |||||
8999 | return icCmmStatOk; | ||||
9000 | } | ||||
9001 | } | ||||
9002 | } | ||||
9003 | |||||
9004 | |||||
9005 | /** | ||||
9006 | ************************************************************************** | ||||
9007 | * Name: CIccCmm::FromInternalEncoding | ||||
9008 | * | ||||
9009 | * Purpose: | ||||
9010 | * Functions for converting from Internal representation of 16 bit pixel colors. | ||||
9011 | * | ||||
9012 | * Args: | ||||
9013 | * nSpace = color space signature of the data, | ||||
9014 | * nEncode = icFloatColorEncoding type of the data, | ||||
9015 | * pData = converted data is stored here, | ||||
9016 | * pInternal = the data to be converted | ||||
9017 | * bClip = flag to clip data to internal range | ||||
9018 | ************************************************************************** | ||||
9019 | */ | ||||
9020 | icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icUInt16Number *pData, | ||||
9021 | const icFloatNumber *pInternal) | ||||
9022 | { | ||||
9023 | switch(nSpace) { | ||||
9024 | case icSigRgbData: | ||||
9025 | { | ||||
9026 | pData[0] = icFtoU16(pInternal[0]); | ||||
9027 | pData[1] = icFtoU16(pInternal[1]); | ||||
9028 | pData[2] = icFtoU16(pInternal[2]); | ||||
9029 | |||||
9030 | return icCmmStatOk; | ||||
9031 | } | ||||
9032 | case icSigCmykData: | ||||
9033 | { | ||||
9034 | pData[0] = icFtoU16(pInternal[0]); | ||||
9035 | pData[1] = icFtoU16(pInternal[1]); | ||||
9036 | pData[2] = icFtoU16(pInternal[2]); | ||||
9037 | pData[3] = icFtoU16(pInternal[3]); | ||||
9038 | |||||
9039 | return icCmmStatOk; | ||||
9040 | } | ||||
9041 | default: | ||||
9042 | { | ||||
9043 | icUInt32Number i; | ||||
9044 | icUInt32Number nSamples = icGetSpaceSamples(nSpace); | ||||
9045 | CIccPixelBuf pFloatPixel(nSamples); | ||||
9046 | icStatusCMM convertStat; | ||||
9047 | |||||
9048 | if (!pFloatPixel.get()) | ||||
9049 | return icCmmStatAllocErr; | ||||
9050 | |||||
9051 | convertStat = FromInternalEncoding(nSpace, icEncode16Bit, pFloatPixel, pInternal); | ||||
9052 | if (convertStat) | ||||
9053 | return convertStat; | ||||
9054 | for(i=0; i<nSamples; i++) { | ||||
9055 | pData[i] = (icUInt16Number)(pFloatPixel[i] + 0.5); | ||||
9056 | } | ||||
9057 | |||||
9058 | return icCmmStatOk; | ||||
9059 | } | ||||
9060 | } | ||||
9061 | } | ||||
9062 | |||||
9063 | |||||
9064 | /** | ||||
9065 | ************************************************************************** | ||||
9066 | * Name: CIccCmm::GetFloatColorEncoding | ||||
9067 | * | ||||
9068 | * Purpose: | ||||
9069 | * Converts the encoding type to characters for printing | ||||
9070 | * | ||||
9071 | * Args: | ||||
9072 | * val = encoding type | ||||
9073 | * | ||||
9074 | * Return: | ||||
9075 | * characters for printing | ||||
9076 | ************************************************************************** | ||||
9077 | */ | ||||
9078 | const icChar* CIccCmm::GetFloatColorEncoding(icFloatColorEncoding val) | ||||
9079 | { | ||||
9080 | switch(val) { | ||||
9081 | |||||
9082 | case icEncodeValue: | ||||
9083 | return "icEncodeValue"; | ||||
9084 | |||||
9085 | case icEncodeFloat: | ||||
9086 | return "icEncodeFloat"; | ||||
9087 | |||||
9088 | case icEncodeUnitFloat: | ||||
9089 | return "icEncodeUnitFloat"; | ||||
9090 | |||||
9091 | case icEncodePercent: | ||||
9092 | return "icEncodePercent"; | ||||
9093 | |||||
9094 | case icEncode8Bit: | ||||
9095 | return "icEncode8Bit"; | ||||
9096 | |||||
9097 | case icEncode16Bit: | ||||
9098 | return "icEncode16Bit"; | ||||
9099 | |||||
9100 | case icEncode16BitV2: | ||||
9101 | return "icEncode16BitV2"; | ||||
9102 | |||||
9103 | default: | ||||
9104 | return "icEncodeUnknown"; | ||||
9105 | } | ||||
9106 | } | ||||
9107 | |||||
9108 | /** | ||||
9109 | ************************************************************************** | ||||
9110 | * Name: CIccCmm::GetFloatColorEncoding | ||||
9111 | * | ||||
9112 | * Purpose: | ||||
9113 | * Converts the string containing encoding type to icFloatColorEncoding | ||||
9114 | * | ||||
9115 | * Args: | ||||
9116 | * val = string containing encoding type | ||||
9117 | * | ||||
9118 | * Return: | ||||
9119 | * encoding type | ||||
9120 | ************************************************************************** | ||||
9121 | */ | ||||
9122 | icFloatColorEncoding CIccCmm::GetFloatColorEncoding(const icChar* val) | ||||
9123 | { | ||||
9124 | if (!stricmpstrcasecmp(val, "icEncodePercent")) { | ||||
9125 | return icEncodePercent; | ||||
9126 | } | ||||
9127 | else if (!stricmpstrcasecmp(val, "icEncodeUnitFloat")) { | ||||
9128 | return icEncodeUnitFloat; | ||||
9129 | } | ||||
9130 | else if (!stricmpstrcasecmp(val, "icEncodeFloat")) { | ||||
9131 | return icEncodeFloat; | ||||
9132 | } | ||||
9133 | else if (!stricmpstrcasecmp(val, "icEncode8Bit")) { | ||||
9134 | return icEncode8Bit; | ||||
9135 | } | ||||
9136 | else if (!stricmpstrcasecmp(val, "icEncode16Bit")) { | ||||
9137 | return icEncode16Bit; | ||||
9138 | } | ||||
9139 | else if (!stricmpstrcasecmp(val, "icEncode16BitV2")) { | ||||
9140 | return icEncode16BitV2; | ||||
9141 | } | ||||
9142 | else if (!stricmpstrcasecmp(val, "icEncodeValue")) { | ||||
9143 | return icEncodeValue; | ||||
9144 | } | ||||
9145 | else { | ||||
9146 | return icEncodeUnknown; | ||||
9147 | } | ||||
9148 | |||||
9149 | } | ||||
9150 | |||||
9151 | /** | ||||
9152 | ************************************************************************** | ||||
9153 | * Name: CIccCmm::GetNumXforms | ||||
9154 | * | ||||
9155 | * Purpose: | ||||
9156 | * Get number of xforms in the xform list | ||||
9157 | * | ||||
9158 | * Return: | ||||
9159 | * number of m_Xforms | ||||
9160 | ************************************************************************** | ||||
9161 | */ | ||||
9162 | icUInt32Number CIccCmm::GetNumXforms() const | ||||
9163 | { | ||||
9164 | return (icUInt32Number)m_Xforms->size(); | ||||
9165 | } | ||||
9166 | |||||
9167 | |||||
9168 | /** | ||||
9169 | ************************************************************************** | ||||
9170 | * Name: CIccCmm::GetFirstXformSource | ||||
9171 | * | ||||
9172 | * Purpose: | ||||
9173 | * Get source colorspace of first transform (similar to m_nSrcSpace with differences in dev colorimetric spaces) | ||||
9174 | * | ||||
9175 | * Return: | ||||
9176 | * colorspace | ||||
9177 | ************************************************************************** | ||||
9178 | */ | ||||
9179 | icColorSpaceSignature CIccCmm::GetFirstXformSource() | ||||
9180 | { | ||||
9181 | if (!m_Xforms->size()) | ||||
9182 | return m_nSrcSpace; | ||||
9183 | |||||
9184 | return m_Xforms->begin()->ptr->GetSrcSpace(); | ||||
9185 | } | ||||
9186 | |||||
9187 | /** | ||||
9188 | ************************************************************************** | ||||
9189 | * Name: CIccCmm::GetNumXforms | ||||
9190 | * | ||||
9191 | * Purpose: | ||||
9192 | * Get source colorspace of last transform (similar to m_nSrcSpace with differences in dev colorimetric spaces) | ||||
9193 | * | ||||
9194 | * Return: | ||||
9195 | * colorspace | ||||
9196 | ************************************************************************** | ||||
9197 | */ | ||||
9198 | icColorSpaceSignature CIccCmm::GetLastXformDest() | ||||
9199 | { | ||||
9200 | if (!m_Xforms->size()) | ||||
9201 | return m_nDestSpace; | ||||
9202 | |||||
9203 | return m_Xforms->rbegin()->ptr->GetDstSpace(); | ||||
9204 | } | ||||
9205 | |||||
9206 | /** | ||||
9207 | ************************************************************************** | ||||
9208 | * Name: CIccApplyCmm::CIccApplyCmm | ||||
9209 | * | ||||
9210 | * Purpose: | ||||
9211 | * Constructor | ||||
9212 | * | ||||
9213 | * Args: | ||||
9214 | * pCmm = ptr to CMM to apply against | ||||
9215 | ************************************************************************** | ||||
9216 | */ | ||||
9217 | CIccApplyNamedColorCmm::CIccApplyNamedColorCmm(CIccNamedColorCmm *pCmm) : CIccApplyCmm(pCmm) | ||||
9218 | { | ||||
9219 | } | ||||
9220 | |||||
9221 | |||||
9222 | /** | ||||
9223 | ************************************************************************** | ||||
9224 | * Name: CIccApplyCmm::CIccApplyCmm | ||||
9225 | * | ||||
9226 | * Purpose: | ||||
9227 | * Destructor | ||||
9228 | ************************************************************************** | ||||
9229 | */ | ||||
9230 | CIccApplyNamedColorCmm::~CIccApplyNamedColorCmm() | ||||
9231 | { | ||||
9232 | } | ||||
9233 | |||||
9234 | |||||
9235 | /** | ||||
9236 | ************************************************************************** | ||||
9237 | * Name: CIccApplyNamedColorCmm::Apply | ||||
9238 | * | ||||
9239 | * Purpose: | ||||
9240 | * Does the actual application of the Xforms in the list. | ||||
9241 | * | ||||
9242 | * Args: | ||||
9243 | * DstPixel = Destination pixel where the result is stored, | ||||
9244 | * SrcPixel = Source pixel which is to be applied. | ||||
9245 | ************************************************************************** | ||||
9246 | */ | ||||
9247 | icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) | ||||
9248 | { | ||||
9249 | icFloatNumber *pDst, *pTmp; | ||||
9250 | const icFloatNumber *pSrc; | ||||
9251 | CIccApplyXformList::iterator i; | ||||
9252 | int j, n = (int)m_Xforms->size(); | ||||
9253 | CIccApplyXform *pApply; | ||||
9254 | const CIccXform *pApplyXform; | ||||
9255 | CIccXformNamedColor *pXform; | ||||
9256 | |||||
9257 | if (!n) | ||||
9258 | return icCmmStatBadXform; | ||||
9259 | |||||
9260 | if (!m_Pixel && !InitPixel()) { | ||||
9261 | return icCmmStatAllocErr; | ||||
9262 | } | ||||
9263 | |||||
9264 | icChar NamedColor[256]; | ||||
9265 | icStatusCMM rv; | ||||
9266 | |||||
9267 | m_pPCS->Reset(m_pCmm->GetSourceSpace()); | ||||
9268 | |||||
9269 | pSrc = SrcPixel; | ||||
9270 | pDst = m_Pixel; | ||||
9271 | |||||
9272 | if (n>1) { | ||||
9273 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | ||||
9274 | |||||
9275 | pApply = i->ptr; | ||||
9276 | pApplyXform = pApply->GetXform(); | ||||
9277 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9278 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9279 | |||||
9280 | switch(pXform->GetInterface()) { | ||||
9281 | case icApplyPixel2Pixel: | ||||
9282 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | ||||
9283 | break; | ||||
9284 | |||||
9285 | case icApplyPixel2Named: | ||||
9286 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | ||||
9287 | break; | ||||
9288 | |||||
9289 | case icApplyNamed2Pixel: | ||||
9290 | if (j==0) { | ||||
9291 | return icCmmStatIncorrectApply; | ||||
9292 | } | ||||
9293 | |||||
9294 | rv = pXform->Apply(pApply, pDst, NamedColor); | ||||
9295 | |||||
9296 | if (rv) { | ||||
9297 | return rv; | ||||
9298 | } | ||||
9299 | break; | ||||
9300 | |||||
9301 | default: | ||||
9302 | break; | ||||
9303 | } | ||||
9304 | } | ||||
9305 | else { | ||||
9306 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); | ||||
9307 | } | ||||
9308 | pTmp = (icFloatNumber*)pSrc; | ||||
9309 | pSrc = pDst; | ||||
9310 | if (pTmp==SrcPixel) | ||||
9311 | pDst = m_Pixel2; | ||||
9312 | else | ||||
9313 | pDst = pTmp; | ||||
9314 | } | ||||
9315 | |||||
9316 | pApply = i->ptr; | ||||
9317 | pApplyXform = pApply->GetXform(); | ||||
9318 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9319 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9320 | |||||
9321 | switch(pXform->GetInterface()) { | ||||
9322 | case icApplyPixel2Pixel: | ||||
9323 | pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform)); | ||||
9324 | break; | ||||
9325 | |||||
9326 | case icApplyPixel2Named: | ||||
9327 | default: | ||||
9328 | return icCmmStatIncorrectApply; | ||||
9329 | break; | ||||
9330 | |||||
9331 | case icApplyNamed2Pixel: | ||||
9332 | rv = pXform->Apply(pApply, DstPixel, NamedColor); | ||||
9333 | if (rv) { | ||||
9334 | return rv; | ||||
9335 | } | ||||
9336 | break; | ||||
9337 | |||||
9338 | } | ||||
9339 | } | ||||
9340 | else { | ||||
9341 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | ||||
9342 | } | ||||
9343 | |||||
9344 | } | ||||
9345 | else if (n==1) { | ||||
9346 | i = m_Xforms->begin(); | ||||
9347 | |||||
9348 | pApply = i->ptr; | ||||
9349 | pApplyXform = pApply->GetXform(); | ||||
9350 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9351 | return icCmmStatIncorrectApply; | ||||
9352 | } | ||||
9353 | |||||
9354 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | ||||
9355 | } | ||||
9356 | |||||
9357 | m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace(), true); | ||||
9358 | |||||
9359 | return icCmmStatOk; | ||||
9360 | } | ||||
9361 | |||||
9362 | |||||
9363 | /** | ||||
9364 | ************************************************************************** | ||||
9365 | * Name: CIccApplyNamedColorCmm::Apply | ||||
9366 | * | ||||
9367 | * Purpose: | ||||
9368 | * Does the actual application of the Xforms in the list. | ||||
9369 | * | ||||
9370 | * Args: | ||||
9371 | * DstPixel = Destination pixel where the result is stored, | ||||
9372 | * SrcPixel = Source pixel which is to be applied. | ||||
9373 | ************************************************************************** | ||||
9374 | */ | ||||
9375 | icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) | ||||
9376 | { | ||||
9377 | icFloatNumber *pDst; | ||||
9378 | const icFloatNumber *pSrc; | ||||
9379 | CIccApplyXformList::iterator i; | ||||
9380 | int j, n = (int)m_Xforms->size(); | ||||
9381 | CIccApplyXform *pApply; | ||||
9382 | const CIccXform *pApplyXform; | ||||
9383 | CIccXformNamedColor *pXform; | ||||
9384 | icUInt32Number k; | ||||
9385 | |||||
9386 | if (!n) | ||||
9387 | return icCmmStatBadXform; | ||||
9388 | |||||
9389 | if (!m_Pixel && !InitPixel()) { | ||||
9390 | return icCmmStatAllocErr; | ||||
9391 | } | ||||
9392 | |||||
9393 | icChar NamedColor[255]; | ||||
9394 | icStatusCMM rv; | ||||
9395 | |||||
9396 | for (k=0; k<nPixels; k++) { | ||||
9397 | m_pPCS->Reset(m_pCmm->GetSourceSpace()); | ||||
9398 | |||||
9399 | pSrc = SrcPixel; | ||||
9400 | pDst = m_Pixel; | ||||
9401 | |||||
9402 | if (n>1) { | ||||
9403 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | ||||
9404 | |||||
9405 | pApply = i->ptr; | ||||
9406 | pApplyXform = pApply->GetXform(); | ||||
9407 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9408 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9409 | |||||
9410 | switch(pXform->GetInterface()) { | ||||
9411 | case icApplyPixel2Pixel: | ||||
9412 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | ||||
9413 | break; | ||||
9414 | |||||
9415 | case icApplyPixel2Named: | ||||
9416 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | ||||
9417 | break; | ||||
9418 | |||||
9419 | case icApplyNamed2Pixel: | ||||
9420 | if (j==0) { | ||||
9421 | return icCmmStatIncorrectApply; | ||||
9422 | } | ||||
9423 | |||||
9424 | rv = pXform->Apply(pApply, pDst, NamedColor); | ||||
9425 | |||||
9426 | if (rv) { | ||||
9427 | return rv; | ||||
9428 | } | ||||
9429 | break; | ||||
9430 | |||||
9431 | default: | ||||
9432 | break; | ||||
9433 | } | ||||
9434 | } | ||||
9435 | else { | ||||
9436 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); | ||||
9437 | } | ||||
9438 | pSrc = pDst; | ||||
9439 | } | ||||
9440 | |||||
9441 | pApply = i->ptr; | ||||
9442 | pApplyXform = pApply->GetXform(); | ||||
9443 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9444 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9445 | |||||
9446 | switch(pXform->GetInterface()) { | ||||
9447 | case icApplyPixel2Pixel: | ||||
9448 | pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform)); | ||||
9449 | break; | ||||
9450 | |||||
9451 | case icApplyPixel2Named: | ||||
9452 | default: | ||||
9453 | return icCmmStatIncorrectApply; | ||||
9454 | break; | ||||
9455 | |||||
9456 | case icApplyNamed2Pixel: | ||||
9457 | rv = pXform->Apply(pApply, DstPixel, NamedColor); | ||||
9458 | if (rv) { | ||||
9459 | return rv; | ||||
9460 | } | ||||
9461 | break; | ||||
9462 | |||||
9463 | } | ||||
9464 | } | ||||
9465 | else { | ||||
9466 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | ||||
9467 | } | ||||
9468 | |||||
9469 | } | ||||
9470 | else if (n==1) { | ||||
9471 | i = m_Xforms->begin(); | ||||
9472 | |||||
9473 | pApply = i->ptr; | ||||
9474 | pApplyXform = pApply->GetXform(); | ||||
9475 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9476 | return icCmmStatIncorrectApply; | ||||
9477 | } | ||||
9478 | |||||
9479 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | ||||
9480 | } | ||||
9481 | |||||
9482 | m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace()); | ||||
9483 | |||||
9484 | SrcPixel += m_pCmm->GetSourceSamples(); | ||||
9485 | DstPixel += m_pCmm->GetDestSamples(); | ||||
9486 | } | ||||
9487 | |||||
9488 | return icCmmStatOk; | ||||
9489 | } | ||||
9490 | |||||
9491 | |||||
9492 | /** | ||||
9493 | ************************************************************************** | ||||
9494 | * Name: CIccApplyNamedColorCmm::Apply | ||||
9495 | * | ||||
9496 | * Purpose: | ||||
9497 | * Does the actual application of the Xforms in the list. | ||||
9498 | * | ||||
9499 | * Args: | ||||
9500 | * DstColorName = Destination string where the result is stored, | ||||
9501 | * SrcPixel = Source pixel which is to be applied. | ||||
9502 | ************************************************************************** | ||||
9503 | */ | ||||
9504 | icStatusCMM CIccApplyNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel) | ||||
9505 | { | ||||
9506 | icFloatNumber *pDst, *pTmp; | ||||
9507 | const icFloatNumber *pSrc; | ||||
9508 | CIccApplyXformList::iterator i; | ||||
9509 | int j, n = (int)m_Xforms->size(); | ||||
9510 | CIccApplyXform *pApply; | ||||
9511 | const CIccXform *pApplyXform; | ||||
9512 | CIccXformNamedColor *pXform; | ||||
9513 | |||||
9514 | if (!n) | ||||
9515 | return icCmmStatBadXform; | ||||
9516 | |||||
9517 | if (!m_Pixel && !InitPixel()) { | ||||
9518 | return icCmmStatAllocErr; | ||||
9519 | } | ||||
9520 | |||||
9521 | icChar NamedColor[256]; | ||||
9522 | icStatusCMM rv; | ||||
9523 | |||||
9524 | m_pPCS->Reset(m_pCmm->GetSourceSpace()); | ||||
9525 | |||||
9526 | pSrc = SrcPixel; | ||||
9527 | pDst = m_Pixel; | ||||
9528 | |||||
9529 | if (n>1) { | ||||
9530 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | ||||
9531 | |||||
9532 | pApply = i->ptr; | ||||
9533 | pApplyXform = pApply->GetXform(); | ||||
9534 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9535 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9536 | switch(pXform->GetInterface()) { | ||||
9537 | case icApplyPixel2Pixel: | ||||
9538 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | ||||
9539 | break; | ||||
9540 | |||||
9541 | case icApplyPixel2Named: | ||||
9542 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | ||||
9543 | break; | ||||
9544 | |||||
9545 | case icApplyNamed2Pixel: | ||||
9546 | if (j==0) { | ||||
9547 | return icCmmStatIncorrectApply; | ||||
9548 | } | ||||
9549 | rv = pXform->Apply(pApply, pDst, NamedColor); | ||||
9550 | if (rv) { | ||||
9551 | return rv; | ||||
9552 | } | ||||
9553 | break; | ||||
9554 | |||||
9555 | default: | ||||
9556 | break; | ||||
9557 | } | ||||
9558 | } | ||||
9559 | else { | ||||
9560 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); | ||||
9561 | } | ||||
9562 | pTmp = (icFloatNumber*)pSrc; | ||||
9563 | pSrc = pDst; | ||||
9564 | if (pTmp==SrcPixel) | ||||
9565 | pDst = m_Pixel2; | ||||
9566 | else | ||||
9567 | pDst = pTmp; | ||||
9568 | } | ||||
9569 | |||||
9570 | pApply = i->ptr; | ||||
9571 | pApplyXform = pApply->GetXform(); | ||||
9572 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9573 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9574 | switch(pXform->GetInterface()) { | ||||
9575 | |||||
9576 | case icApplyPixel2Named: | ||||
9577 | pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform)); | ||||
9578 | break; | ||||
9579 | |||||
9580 | case icApplyPixel2Pixel: | ||||
9581 | case icApplyNamed2Pixel: | ||||
9582 | default: | ||||
9583 | return icCmmStatIncorrectApply; | ||||
9584 | break; | ||||
9585 | } | ||||
9586 | } | ||||
9587 | else { | ||||
9588 | return icCmmStatIncorrectApply; | ||||
9589 | } | ||||
9590 | |||||
9591 | } | ||||
9592 | else if (n==1) { | ||||
9593 | i = m_Xforms->begin(); | ||||
9594 | pApply = i->ptr; | ||||
9595 | pApplyXform = pApply->GetXform(); | ||||
9596 | if (pApplyXform->GetXformType()!=icXformTypeNamedColor) { | ||||
9597 | return icCmmStatIncorrectApply; | ||||
9598 | } | ||||
9599 | |||||
9600 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9601 | pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform)); | ||||
9602 | } | ||||
9603 | |||||
9604 | return icCmmStatOk; | ||||
9605 | } | ||||
9606 | |||||
9607 | |||||
9608 | /** | ||||
9609 | ************************************************************************** | ||||
9610 | * Name: CIccApplyNamedColorCmm::Apply | ||||
9611 | * | ||||
9612 | * Purpose: | ||||
9613 | * Does the actual application of the Xforms in the list. | ||||
9614 | * | ||||
9615 | * Args: | ||||
9616 | * DstPixel = Destination pixel where the result is stored, | ||||
9617 | * SrcColorName = Source color name which is to be searched. | ||||
9618 | ************************************************************************** | ||||
9619 | */ | ||||
9620 | icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/) | ||||
9621 | { | ||||
9622 | icFloatNumber *pDst, *pTmp; | ||||
9623 | const icFloatNumber *pSrc; | ||||
9624 | CIccApplyXformList::iterator i; | ||||
9625 | int j, n = (int)m_Xforms->size(); | ||||
9626 | CIccApplyXform *pApply; | ||||
9627 | const CIccXform *pApplyXform; | ||||
9628 | CIccXformNamedColor *pXform; | ||||
9629 | |||||
9630 | if (!n) | ||||
9631 | return icCmmStatBadXform; | ||||
9632 | |||||
9633 | if (!m_Pixel && !InitPixel()) { | ||||
9634 | return icCmmStatAllocErr; | ||||
9635 | } | ||||
9636 | |||||
9637 | icChar NamedColor[255]; | ||||
9638 | icStatusCMM rv; | ||||
9639 | |||||
9640 | i=m_Xforms->begin(); | ||||
9641 | pApply = i->ptr; | ||||
9642 | pApplyXform = pApply->GetXform(); | ||||
9643 | if (pApplyXform->GetXformType()!=icXformTypeNamedColor) | ||||
9644 | return icCmmStatIncorrectApply; | ||||
9645 | |||||
9646 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9647 | m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS()); | ||||
9648 | |||||
9649 | pDst = m_Pixel; | ||||
9650 | |||||
9651 | if (n>1) { | ||||
9652 | rv = pXform->Apply(pApply, pDst, SrcColorName, tint); | ||||
9653 | if (rv) { | ||||
9654 | return rv; | ||||
9655 | } | ||||
9656 | |||||
9657 | pSrc = pDst; | ||||
9658 | pDst = m_Pixel2; | ||||
9659 | |||||
9660 | for (j=0, i++; j<n-2 && i!=m_Xforms->end(); i++, j++) { | ||||
9661 | |||||
9662 | pApply = i->ptr; | ||||
9663 | pApplyXform = pApply->GetXform(); | ||||
9664 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9665 | CIccXformNamedColor *pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9666 | switch(pXform->GetInterface()) { | ||||
9667 | case icApplyPixel2Pixel: | ||||
9668 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | ||||
9669 | break; | ||||
9670 | |||||
9671 | case icApplyPixel2Named: | ||||
9672 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | ||||
9673 | break; | ||||
9674 | |||||
9675 | case icApplyNamed2Pixel: | ||||
9676 | rv = pXform->Apply(pApply, pDst, NamedColor); | ||||
9677 | if (rv) { | ||||
9678 | return rv; | ||||
9679 | } | ||||
9680 | break; | ||||
9681 | |||||
9682 | default: | ||||
9683 | break; | ||||
9684 | } | ||||
9685 | } | ||||
9686 | else { | ||||
9687 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); | ||||
9688 | } | ||||
9689 | pTmp = (icFloatNumber*)pSrc; | ||||
9690 | pSrc = pDst; | ||||
9691 | pDst = pTmp; | ||||
9692 | } | ||||
9693 | |||||
9694 | pApply = i->ptr; | ||||
9695 | pApplyXform = pApply->GetXform(); | ||||
9696 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9697 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9698 | switch(pXform->GetInterface()) { | ||||
9699 | case icApplyPixel2Pixel: | ||||
9700 | pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform)); | ||||
9701 | break; | ||||
9702 | |||||
9703 | case icApplyPixel2Named: | ||||
9704 | default: | ||||
9705 | return icCmmStatIncorrectApply; | ||||
9706 | break; | ||||
9707 | |||||
9708 | case icApplyNamed2Pixel: | ||||
9709 | rv = pXform->Apply(pApply, DstPixel, NamedColor); | ||||
9710 | if (rv) { | ||||
9711 | return rv; | ||||
9712 | } | ||||
9713 | break; | ||||
9714 | |||||
9715 | } | ||||
9716 | } | ||||
9717 | else { | ||||
9718 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | ||||
9719 | } | ||||
9720 | |||||
9721 | } | ||||
9722 | else if (n==1) { | ||||
9723 | rv = pXform->Apply(pApply, DstPixel, SrcColorName, tint); | ||||
9724 | if (rv) { | ||||
9725 | return rv; | ||||
9726 | } | ||||
9727 | m_pPCS->Check(DstPixel, pXform); | ||||
9728 | } | ||||
9729 | |||||
9730 | m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace()); | ||||
9731 | |||||
9732 | return icCmmStatOk; | ||||
9733 | } | ||||
9734 | |||||
9735 | /** | ||||
9736 | ************************************************************************** | ||||
9737 | * Name: CIccApplyNamedColorCmm::Apply | ||||
9738 | * | ||||
9739 | * Purpose: | ||||
9740 | * Does the actual application of the Xforms in the list. | ||||
9741 | * | ||||
9742 | * Args: | ||||
9743 | * DstColorName = Destination string where the result is stored, | ||||
9744 | * SrcColorName = Source color name which is to be searched. | ||||
9745 | ************************************************************************** | ||||
9746 | */ | ||||
9747 | icStatusCMM CIccApplyNamedColorCmm::Apply(icChar *DstColorName, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/) | ||||
9748 | { | ||||
9749 | icFloatNumber *pDst, *pTmp; | ||||
9750 | const icFloatNumber *pSrc; | ||||
9751 | CIccApplyXformList::iterator i; | ||||
9752 | int j, n = (int)m_Xforms->size(); | ||||
9753 | icChar NamedColor[256]; | ||||
9754 | icStatusCMM rv; | ||||
9755 | CIccApplyXform *pApply; | ||||
9756 | const CIccXform *pApplyXform; | ||||
9757 | CIccXformNamedColor *pXform; | ||||
9758 | |||||
9759 | if (!n) | ||||
9760 | return icCmmStatBadXform; | ||||
9761 | |||||
9762 | if (!m_Pixel && !InitPixel()) { | ||||
9763 | return icCmmStatAllocErr; | ||||
9764 | } | ||||
9765 | |||||
9766 | i=m_Xforms->begin(); | ||||
9767 | |||||
9768 | pApply = i->ptr; | ||||
9769 | pApplyXform = pApply->GetXform(); | ||||
9770 | if (pApplyXform->GetXformType()!=icXformTypeNamedColor) | ||||
9771 | return icCmmStatIncorrectApply; | ||||
9772 | |||||
9773 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9774 | |||||
9775 | m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS()); | ||||
9776 | |||||
9777 | pDst = m_Pixel; | ||||
9778 | |||||
9779 | if (n>1) { | ||||
9780 | rv = pXform->Apply(pApply, pDst, SrcColorName, tint); | ||||
9781 | |||||
9782 | if (rv) { | ||||
9783 | return rv; | ||||
9784 | } | ||||
9785 | |||||
9786 | pSrc = pDst; | ||||
9787 | pDst = m_Pixel2; | ||||
9788 | |||||
9789 | for (j=0, i++; j<n-2 && i!=m_Xforms->end(); i++, j++) { | ||||
9790 | |||||
9791 | pApply = i->ptr; | ||||
9792 | pApplyXform = pApply->GetXform(); | ||||
9793 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9794 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9795 | switch(pXform->GetInterface()) { | ||||
9796 | case icApplyPixel2Pixel: | ||||
9797 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | ||||
9798 | break; | ||||
9799 | |||||
9800 | |||||
9801 | case icApplyPixel2Named: | ||||
9802 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | ||||
9803 | break; | ||||
9804 | |||||
9805 | case icApplyNamed2Pixel: | ||||
9806 | rv = pXform->Apply(pApply, pDst, NamedColor); | ||||
9807 | if (rv) { | ||||
9808 | return rv; | ||||
9809 | } | ||||
9810 | break; | ||||
9811 | |||||
9812 | default: | ||||
9813 | break; | ||||
9814 | } | ||||
9815 | } | ||||
9816 | else { | ||||
9817 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | ||||
9818 | } | ||||
9819 | pTmp = (icFloatNumber*)pSrc; | ||||
9820 | pSrc = pDst; | ||||
9821 | pDst = pTmp; | ||||
9822 | } | ||||
9823 | |||||
9824 | pApply = i->ptr; | ||||
9825 | pApplyXform = pApply->GetXform(); | ||||
9826 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | ||||
9827 | pXform = (CIccXformNamedColor*)pApplyXform; | ||||
9828 | switch(pXform->GetInterface()) { | ||||
9829 | case icApplyPixel2Named: | ||||
9830 | pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform)); | ||||
9831 | break; | ||||
9832 | |||||
9833 | case icApplyPixel2Pixel: | ||||
9834 | case icApplyNamed2Pixel: | ||||
9835 | default: | ||||
9836 | return icCmmStatIncorrectApply; | ||||
9837 | break; | ||||
9838 | } | ||||
9839 | } | ||||
9840 | else { | ||||
9841 | return icCmmStatIncorrectApply; | ||||
9842 | } | ||||
9843 | |||||
9844 | } | ||||
9845 | else if (n==1) { | ||||
9846 | return icCmmStatIncorrectApply; | ||||
9847 | } | ||||
9848 | |||||
9849 | return icCmmStatOk; | ||||
9850 | } | ||||
9851 | |||||
9852 | /** | ||||
9853 | ************************************************************************** | ||||
9854 | * Name: CIccNamedColorCmm::CIccNamedColorCmm | ||||
9855 | * | ||||
9856 | * Purpose: | ||||
9857 | * Constructor | ||||
9858 | * | ||||
9859 | * Args: | ||||
9860 | * nSrcSpace = signature of the source color space, | ||||
9861 | * nDestSpace = signature of the destination color space, | ||||
9862 | * bFirstInput = true if the first profile added is an input profile | ||||
9863 | ************************************************************************** | ||||
9864 | */ | ||||
9865 | CIccNamedColorCmm::CIccNamedColorCmm(icColorSpaceSignature nSrcSpace, icColorSpaceSignature nDestSpace, | ||||
9866 | bool bFirstInput) : CIccCmm(nSrcSpace, nDestSpace, bFirstInput) | ||||
9867 | { | ||||
9868 | m_nApplyInterface = icApplyPixel2Pixel; | ||||
9869 | } | ||||
9870 | |||||
9871 | /** | ||||
9872 | ************************************************************************** | ||||
9873 | * Name: CIccNamedColorCmm::~CIccNamedColorCmm | ||||
9874 | * | ||||
9875 | * Purpose: | ||||
9876 | * Destructor | ||||
9877 | ************************************************************************** | ||||
9878 | */ | ||||
9879 | CIccNamedColorCmm::~CIccNamedColorCmm() | ||||
9880 | { | ||||
9881 | } | ||||
9882 | |||||
9883 | |||||
9884 | /** | ||||
9885 | ************************************************************************** | ||||
9886 | * Name: CIccNamedColorCmm::AddXform | ||||
9887 | * | ||||
9888 | * Purpose: | ||||
9889 | * Adds a profile at the end of the Xform list | ||||
9890 | * | ||||
9891 | * Args: | ||||
9892 | * szProfilePath = file name of the profile to be added, | ||||
9893 | * nIntent = rendering intent to be used with the profile, | ||||
9894 | * nInterp = type of interpolation to be used with the profile | ||||
9895 | * pHintManager = hints for creating the xform | ||||
9896 | * | ||||
9897 | * Return: | ||||
9898 | * icCmmStatOk, if the profile was added to the list succesfully | ||||
9899 | ************************************************************************** | ||||
9900 | */ | ||||
9901 | icStatusCMM CIccNamedColorCmm::AddXform(const icChar *szProfilePath, | ||||
9902 | icRenderingIntent nIntent /*=icUnknownIntent*/, | ||||
9903 | icXformInterp nInterp /*icXformInterp*/, | ||||
9904 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
9905 | icXformLutType nLutType /*=icXformLutColor*/, | ||||
9906 | bool bUseD2BxB2DxTags /*=true*/, | ||||
9907 | CIccCreateXformHintManager *pHintManager /*=NULL*/, | ||||
9908 | bool bUseSubProfile /*=false*/) | ||||
9909 | { | ||||
9910 | CIccProfile *pProfile = OpenIccProfile(szProfilePath, bUseSubProfile); | ||||
9911 | |||||
9912 | if (!pProfile) | ||||
9913 | return icCmmStatCantOpenProfile; | ||||
9914 | |||||
9915 | icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | ||||
9916 | |||||
9917 | if (rv != icCmmStatOk) | ||||
9918 | delete pProfile; | ||||
9919 | |||||
9920 | return rv; | ||||
9921 | } | ||||
9922 | |||||
9923 | /** | ||||
9924 | ************************************************************************** | ||||
9925 | * Name: CIccNamedColorCmm::AddXform | ||||
9926 | * | ||||
9927 | * Purpose: | ||||
9928 | * Adds a profile at the end of the Xform list | ||||
9929 | * | ||||
9930 | * Args: | ||||
9931 | * pProfile = pointer to the CIccProfile object to be added, | ||||
9932 | * nIntent = rendering intent to be used with the profile, | ||||
9933 | * nInterp = type of interpolation to be used with the profile | ||||
9934 | * nLutType = type of lut to use from the profile | ||||
9935 | * pHintManager = hints for creating the xform | ||||
9936 | * | ||||
9937 | * Return: | ||||
9938 | * icCmmStatOk, if the profile was added to the list succesfully | ||||
9939 | ************************************************************************** | ||||
9940 | */ | ||||
9941 | icStatusCMM CIccNamedColorCmm::AddXform(CIccProfile *pProfile, | ||||
9942 | icRenderingIntent nIntent /*=icUnknownIntent*/, | ||||
9943 | icXformInterp nInterp /*=icInterpLinear*/, | ||||
9944 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | ||||
9945 | icXformLutType nLutType /*=icXformLutColor*/, | ||||
9946 | bool bUseD2BxB2DxTags /*=true*/, | ||||
9947 | CIccCreateXformHintManager *pHintManager /*=NULL*/) | ||||
9948 | { | ||||
9949 | icColorSpaceSignature nSrcSpace, nDstSpace; | ||||
9950 | CIccXformPtr Xform; | ||||
9951 | bool bInput = !m_bLastInput; | ||||
9952 | icStatusCMM rv; | ||||
9953 | icXformLutType nUseLutType = nLutType; | ||||
9954 | |||||
9955 | switch(pProfile->m_Header.deviceClass) { | ||||
9956 | case icSigMaterialIdentificationClass: | ||||
9957 | case icSigMaterialLinkClass: | ||||
9958 | nIntent = icPerceptual; | ||||
9959 | nLutType = icXformLutMCS; | ||||
9960 | break; | ||||
9961 | |||||
9962 | case icSigMaterialVisualizationClass: | ||||
9963 | nLutType = icXformLutMCS; | ||||
9964 | break; | ||||
9965 | |||||
9966 | default: | ||||
9967 | break; | ||||
9968 | } | ||||
9969 | |||||
9970 | Xform.ptr = NULL__null; | ||||
9971 | switch (nUseLutType) { | ||||
9972 | //Automatically choose which one | ||||
9973 | case icXformLutColor: | ||||
9974 | case icXformLutColorimetric: | ||||
9975 | case icXformLutSpectral: | ||||
9976 | case icXformLutNamedColor: | ||||
9977 | { | ||||
9978 | CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag); | ||||
9979 | |||||
9980 | if (pTag && (pProfile->m_Header.deviceClass==icSigNamedColorClass || nLutType == icXformLutNamedColor)) { | ||||
9981 | if (bInput) { | ||||
9982 | nSrcSpace = icSigNamedData; | ||||
9983 | } | ||||
9984 | else if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) { | ||||
9985 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
9986 | bUseD2BxB2DxTags = true; | ||||
9987 | } | ||||
9988 | else { | ||||
9989 | nSrcSpace = pProfile->m_Header.pcs; | ||||
9990 | } | ||||
9991 | |||||
9992 | if (!m_Xforms->size()) { | ||||
9993 | if (m_nSrcSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | ||||
9994 | m_nSrcSpace = nSrcSpace; | ||||
9995 | } | ||||
9996 | else { | ||||
9997 | nSrcSpace = m_nSrcSpace; | ||||
9998 | } | ||||
9999 | } | ||||
10000 | else { | ||||
10001 | if (m_nLastSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | ||||
10002 | m_nLastSpace = nSrcSpace; | ||||
10003 | } | ||||
10004 | else { | ||||
10005 | nSrcSpace = m_nLastSpace; | ||||
10006 | } | ||||
10007 | } | ||||
10008 | |||||
10009 | if (nSrcSpace==icSigNamedData) { | ||||
10010 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) { | ||||
10011 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
10012 | bUseD2BxB2DxTags = true; | ||||
10013 | } | ||||
10014 | else { | ||||
10015 | nDstSpace = pProfile->m_Header.pcs; | ||||
10016 | } | ||||
10017 | bInput = true; | ||||
10018 | } | ||||
10019 | else { | ||||
10020 | nDstSpace = icSigNamedData; | ||||
10021 | bInput = false; | ||||
10022 | } | ||||
10023 | |||||
10024 | Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, icXformLutNamedColor, bUseD2BxB2DxTags, pHintManager); | ||||
10025 | if (!Xform.ptr) { | ||||
10026 | return icCmmStatBadXform; | ||||
10027 | } | ||||
10028 | CIccXformNamedColor *pXform = (CIccXformNamedColor *)Xform.ptr; | ||||
10029 | rv = pXform->SetSrcSpace(nSrcSpace); | ||||
10030 | if (rv) | ||||
10031 | return rv; | ||||
10032 | |||||
10033 | rv = pXform->SetDestSpace(nDstSpace); | ||||
10034 | if (rv) | ||||
10035 | return rv; | ||||
10036 | } | ||||
10037 | else { | ||||
10038 | //It isn't named color so make we will use color lut. | ||||
10039 | if (nUseLutType==icXformLutNamedColor) | ||||
10040 | nUseLutType = icXformLutColor; | ||||
10041 | |||||
10042 | //Check pProfile if nIntent and input can be found. | ||||
10043 | if (bInput) { | ||||
10044 | nSrcSpace = pProfile->m_Header.colorSpace; | ||||
10045 | |||||
10046 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) { | ||||
10047 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
10048 | bUseD2BxB2DxTags = true; | ||||
10049 | } | ||||
10050 | else | ||||
10051 | nDstSpace = pProfile->m_Header.pcs; | ||||
10052 | } | ||||
10053 | else { | ||||
10054 | if (pProfile->m_Header.deviceClass == icSigLinkClass) { | ||||
10055 | return icCmmStatBadSpaceLink; | ||||
10056 | } | ||||
10057 | if (pProfile->m_Header.deviceClass == icSigAbstractClass) { | ||||
10058 | bInput = true; | ||||
10059 | nIntent = icPerceptual; // Note: icPerceptualIntent = 0 | ||||
10060 | } | ||||
10061 | |||||
10062 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) { | ||||
10063 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
10064 | bUseD2BxB2DxTags = true; | ||||
10065 | } | ||||
10066 | else | ||||
10067 | nSrcSpace = pProfile->m_Header.pcs; | ||||
10068 | |||||
10069 | nDstSpace = pProfile->m_Header.colorSpace; | ||||
10070 | } | ||||
10071 | } | ||||
10072 | } | ||||
10073 | break; | ||||
10074 | |||||
10075 | case icXformLutPreview: | ||||
10076 | nSrcSpace = pProfile->m_Header.pcs; | ||||
10077 | nDstSpace = pProfile->m_Header.pcs; | ||||
10078 | bInput = false; | ||||
10079 | break; | ||||
10080 | |||||
10081 | case icXformLutGamut: | ||||
10082 | nSrcSpace = pProfile->m_Header.pcs; | ||||
10083 | nDstSpace = icSigGamutData((icColorSpaceSignature) 0x67616D74); | ||||
10084 | bInput = true; | ||||
10085 | break; | ||||
10086 | |||||
10087 | case icXformLutBRDFParam: | ||||
10088 | nSrcSpace = pProfile->m_Header.colorSpace; | ||||
10089 | nDstSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | ||||
10090 | break; | ||||
10091 | |||||
10092 | case icXformLutBRDFDirect: | ||||
10093 | nSrcSpace = pProfile->m_Header.colorSpace; | ||||
10094 | nDstSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | ||||
10095 | break; | ||||
10096 | |||||
10097 | case icXformLutMCS: | ||||
10098 | switch(pProfile->m_Header.deviceClass) | ||||
10099 | { | ||||
10100 | case icSigInputClass: | ||||
10101 | case icSigMaterialIdentificationClass: | ||||
10102 | nSrcSpace = pProfile->m_Header.colorSpace; | ||||
10103 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | ||||
10104 | break; | ||||
10105 | case icSigMaterialVisualizationClass: | ||||
10106 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | ||||
10107 | if (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS) { | ||||
10108 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | ||||
10109 | } | ||||
10110 | else { | ||||
10111 | nDstSpace = pProfile->m_Header.pcs; | ||||
10112 | } | ||||
10113 | bInput = true; | ||||
10114 | break; | ||||
10115 | |||||
10116 | case icSigMaterialLinkClass: | ||||
10117 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | ||||
10118 | nDstSpace = pProfile->m_Header.colorSpace; | ||||
10119 | break; | ||||
10120 | |||||
10121 | default: | ||||
10122 | return icCmmStatBadLutType; | ||||
10123 | } | ||||
10124 | break; | ||||
10125 | |||||
10126 | default: | ||||
10127 | return icCmmStatBadLutType; | ||||
10128 | } | ||||
10129 | |||||
10130 | //Make sure color spaces match with previous xforms | ||||
10131 | if (!m_Xforms->size()) { | ||||
10132 | if (m_nSrcSpace == icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | ||||
10133 | m_nLastSpace = nSrcSpace; | ||||
10134 | m_nSrcSpace = nSrcSpace; | ||||
10135 | } | ||||
10136 | else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)((m_nSrcSpace)==(nSrcSpace) || ((((m_nSrcSpace)==icSigXYZData || (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nSrcSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) ) && !IsNChannelCompat(m_nSrcSpace, nSrcSpace)(((((icColorSpaceSignature)(((icUInt32Number)m_nSrcSpace)& 0xffff0000))==icSigNChannelData) && (((icUInt32Number )m_nSrcSpace)&0x0000ffff)==icGetSpaceSamples(nSrcSpace)) || ((((icColorSpaceSignature)(((icUInt32Number)nSrcSpace)&0xffff0000 ))==icSigNChannelData) && (((icUInt32Number)nSrcSpace )&0x0000ffff)==icGetSpaceSamples(m_nSrcSpace)))) { | ||||
10137 | return icCmmStatBadSpaceLink; | ||||
10138 | } | ||||
10139 | } | ||||
10140 | else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)((m_nLastSpace)==(nSrcSpace) || ((((m_nLastSpace)==icSigXYZData || (m_nLastSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) ) && !IsNChannelCompat(m_nSrcSpace, nSrcSpace)(((((icColorSpaceSignature)(((icUInt32Number)m_nSrcSpace)& 0xffff0000))==icSigNChannelData) && (((icUInt32Number )m_nSrcSpace)&0x0000ffff)==icGetSpaceSamples(nSrcSpace)) || ((((icColorSpaceSignature)(((icUInt32Number)nSrcSpace)&0xffff0000 ))==icSigNChannelData) && (((icUInt32Number)nSrcSpace )&0x0000ffff)==icGetSpaceSamples(m_nSrcSpace)))) { | ||||
10141 | return icCmmStatBadSpaceLink; | ||||
10142 | } | ||||
10143 | |||||
10144 | //Automatic creation of intent from header/last profile | ||||
10145 | if (nIntent==icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) { | ||||
10146 | if (bInput) { | ||||
10147 | nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent; | ||||
10148 | } | ||||
10149 | else { | ||||
10150 | nIntent = m_nLastIntent; | ||||
10151 | } | ||||
10152 | if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | ||||
10153 | nIntent = icPerceptual; | ||||
10154 | } | ||||
10155 | |||||
10156 | if (!Xform.ptr) | ||||
10157 | Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, nUseLutType, bUseD2BxB2DxTags, pHintManager); | ||||
10158 | |||||
10159 | if (!Xform.ptr) { | ||||
10160 | return icCmmStatBadXform; | ||||
10161 | } | ||||
10162 | |||||
10163 | m_nLastSpace = Xform.ptr->GetDstSpace(); | ||||
10164 | m_nLastIntent = nIntent; | ||||
10165 | |||||
10166 | if (pProfile->m_Header.deviceClass == icSigLinkClass) | ||||
10167 | bInput = false; | ||||
10168 | m_bLastInput = bInput; | ||||
10169 | |||||
10170 | m_Xforms->push_back(Xform); | ||||
10171 | |||||
10172 | return icCmmStatOk; | ||||
10173 | } | ||||
10174 | |||||
10175 | /** | ||||
10176 | ************************************************************************** | ||||
10177 | * Name: CIccNamedColorCmm::Begin | ||||
10178 | * | ||||
10179 | * Purpose: | ||||
10180 | * Does the initialization of the Xforms in the list before Apply() is called. | ||||
10181 | * Must be called before Apply(). | ||||
10182 | * | ||||
10183 | ************************************************************************** | ||||
10184 | */ | ||||
10185 | icStatusCMM CIccNamedColorCmm::Begin(bool bAllocNewApply/* =true */, bool bUsePcsConversion/*=false*/) | ||||
10186 | { | ||||
10187 | if (m_nDestSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | ||||
10188 | m_nDestSpace = m_nLastSpace; | ||||
10189 | } | ||||
10190 | else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)((m_nDestSpace)==(m_nLastSpace) || ((((m_nDestSpace)==icSigXYZData || (m_nDestSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nDestSpace )) && (((m_nLastSpace)==icSigXYZData || (m_nLastSpace )==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace))) || ((( (icColorSpaceSignature)(((icUInt32Number)m_nDestSpace)&0xffff0000 ))==icSigSrcMCSChannelData) && (((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData )) )) { | ||||
10191 | return icCmmStatBadSpaceLink; | ||||
10192 | } | ||||
10193 | |||||
10194 | if (m_nSrcSpace != icSigNamedData) { | ||||
10195 | if (m_nDestSpace != icSigNamedData) { | ||||
10196 | m_nApplyInterface = icApplyPixel2Pixel; | ||||
10197 | } | ||||
10198 | else { | ||||
10199 | m_nApplyInterface = icApplyPixel2Named; | ||||
10200 | } | ||||
10201 | } | ||||
10202 | else { | ||||
10203 | if (m_nDestSpace != icSigNamedData) { | ||||
10204 | m_nApplyInterface = icApplyNamed2Pixel; | ||||
10205 | } | ||||
10206 | else { | ||||
10207 | m_nApplyInterface = icApplyNamed2Named; | ||||
10208 | } | ||||
10209 | } | ||||
10210 | |||||
10211 | SetLateBindingCC(); | ||||
10212 | |||||
10213 | icStatusCMM rv; | ||||
10214 | CIccXformList::iterator i; | ||||
10215 | |||||
10216 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | ||||
10217 | rv = i->ptr->Begin(); | ||||
10218 | |||||
10219 | if (rv!= icCmmStatOk) { | ||||
10220 | return rv; | ||||
10221 | } | ||||
10222 | } | ||||
10223 | |||||
10224 | rv = CheckPCSConnections(bUsePcsConversion); | ||||
10225 | if (rv != icCmmStatOk && rv!=icCmmStatIdentityXform) | ||||
10226 | return rv; | ||||
10227 | |||||
10228 | if (bAllocNewApply) { | ||||
10229 | rv = icCmmStatOk; | ||||
10230 | |||||
10231 | m_pApply = GetNewApplyCmm(rv); | ||||
10232 | } | ||||
10233 | else | ||||
10234 | rv = icCmmStatOk; | ||||
10235 | |||||
10236 | return rv; | ||||
10237 | } | ||||
10238 | |||||
10239 | /** | ||||
10240 | ************************************************************************** | ||||
10241 | * Name: CIccNamedColorCmm::GetNewApplyCmm | ||||
10242 | * | ||||
10243 | * Purpose: | ||||
10244 | * Allocates a CIccApplyCmm object that allows one to call apply from | ||||
10245 | * multiple threads. | ||||
10246 | * | ||||
10247 | ************************************************************************** | ||||
10248 | */ | ||||
10249 | CIccApplyCmm *CIccNamedColorCmm::GetNewApplyCmm(icStatusCMM &status) | ||||
10250 | { | ||||
10251 | CIccApplyCmm *pApply = new CIccApplyNamedColorCmm(this); | ||||
10252 | |||||
10253 | CIccXformList::iterator i; | ||||
10254 | |||||
10255 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | ||||
10256 | CIccApplyXform *pXform = i->ptr->GetNewApply(status); | ||||
10257 | if (status != icCmmStatOk || !pXform) { | ||||
10258 | delete pApply; | ||||
10259 | return NULL__null; | ||||
10260 | } | ||||
10261 | pApply->AppendApplyXform(pXform); | ||||
10262 | } | ||||
10263 | |||||
10264 | m_bValid = true; | ||||
10265 | |||||
10266 | status = icCmmStatOk; | ||||
10267 | return pApply; | ||||
10268 | } | ||||
10269 | |||||
10270 | |||||
10271 | /** | ||||
10272 | ************************************************************************** | ||||
10273 | * Name: CIccApplyNamedColorCmm::Apply | ||||
10274 | * | ||||
10275 | * Purpose: | ||||
10276 | * Does the actual application of the Xforms in the list. | ||||
10277 | * | ||||
10278 | * Args: | ||||
10279 | * DstColorName = Destination string where the result is stored, | ||||
10280 | * SrcPoxel = Source pixel | ||||
10281 | ************************************************************************** | ||||
10282 | */ | ||||
10283 | icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel) | ||||
10284 | { | ||||
10285 | return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcPixel); | ||||
10286 | } | ||||
10287 | |||||
10288 | |||||
10289 | /** | ||||
10290 | ************************************************************************** | ||||
10291 | * Name: CIccApplyNamedColorCmm::Apply | ||||
10292 | * | ||||
10293 | * Purpose: | ||||
10294 | * Does the actual application of the Xforms in the list. | ||||
10295 | * | ||||
10296 | * Args: | ||||
10297 | * DestPixel = Destination pixel where the result is stored, | ||||
10298 | * SrcColorName = Source color name which is to be searched. | ||||
10299 | ************************************************************************** | ||||
10300 | */ | ||||
10301 | icStatusCMM CIccNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/) | ||||
10302 | { | ||||
10303 | return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstPixel, SrcColorName, tint); | ||||
10304 | } | ||||
10305 | |||||
10306 | |||||
10307 | /** | ||||
10308 | ************************************************************************** | ||||
10309 | * Name: CIccApplyNamedColorCmm::Apply | ||||
10310 | * | ||||
10311 | * Purpose: | ||||
10312 | * Does the actual application of the Xforms in the list. | ||||
10313 | * | ||||
10314 | * Args: | ||||
10315 | * DstColorName = Destination string where the result is stored, | ||||
10316 | * SrcColorName = Source color name which is to be searched. | ||||
10317 | ************************************************************************** | ||||
10318 | */ | ||||
10319 | icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/) | ||||
10320 | { | ||||
10321 | return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcColorName, tint); | ||||
10322 | } | ||||
10323 | |||||
10324 | |||||
10325 | /** | ||||
10326 | ************************************************************************** | ||||
10327 | * Name: CIccNamedColorCmm::SetLastXformDest | ||||
10328 | * | ||||
10329 | * Purpose: | ||||
10330 | * Sets the destination Color space of the last Xform in the list | ||||
10331 | * | ||||
10332 | * Args: | ||||
10333 | * nDestSpace = signature of the color space to be set | ||||
10334 | ************************************************************************** | ||||
10335 | */ | ||||
10336 | icStatusCMM CIccNamedColorCmm::SetLastXformDest(icColorSpaceSignature nDestSpace) | ||||
10337 | { | ||||
10338 | int n = (int)m_Xforms->size(); | ||||
10339 | CIccXformPtr *pLastXform; | ||||
10340 | |||||
10341 | if (!n) | ||||
10342 | return icCmmStatBadXform; | ||||
10343 | |||||
10344 | pLastXform = &m_Xforms->back(); | ||||
10345 | |||||
10346 | if (pLastXform->ptr->GetXformType()==icXformTypeNamedColor) { | ||||
10347 | CIccXformNamedColor *pXform = (CIccXformNamedColor *)pLastXform->ptr; | ||||
10348 | if (pXform->GetSrcSpace() == icSigNamedData && | ||||
10349 | nDestSpace == icSigNamedData) { | ||||
10350 | return icCmmStatBadSpaceLink; | ||||
10351 | } | ||||
10352 | |||||
10353 | if (nDestSpace != icSigNamedData && | ||||
10354 | pXform->GetDstSpace() == icSigNamedData) { | ||||
10355 | return icCmmStatBadSpaceLink; | ||||
10356 | } | ||||
10357 | |||||
10358 | return pXform->SetDestSpace(nDestSpace); | ||||
10359 | } | ||||
10360 | |||||
10361 | return icCmmStatBadXform; | ||||
10362 | } | ||||
10363 | |||||
10364 | |||||
10365 | /** | ||||
10366 | **************************************************************************** | ||||
10367 | * Name: CIccMruCmm::CIccMruCmm | ||||
10368 | * | ||||
10369 | * Purpose: private constructor - Use Attach to create CIccMruCmm objects | ||||
10370 | ***************************************************************************** | ||||
10371 | */ | ||||
10372 | CIccMruCmm::CIccMruCmm() | ||||
10373 | { | ||||
10374 | m_pCmm = NULL__null; | ||||
10375 | m_bDeleteCmm = false; | ||||
10376 | } | ||||
10377 | |||||
10378 | |||||
10379 | /** | ||||
10380 | **************************************************************************** | ||||
10381 | * Name: CIccMruCmm::~CIccMruCmm | ||||
10382 | * | ||||
10383 | * Purpose: destructor | ||||
10384 | ***************************************************************************** | ||||
10385 | */ | ||||
10386 | CIccMruCmm::~CIccMruCmm() | ||||
10387 | { | ||||
10388 | if (m_pCmm && m_bDeleteCmm) | ||||
10389 | delete m_pCmm; | ||||
10390 | } | ||||
10391 | |||||
10392 | |||||
10393 | /** | ||||
10394 | **************************************************************************** | ||||
10395 | * Name: CIccMruCmm::Attach | ||||
10396 | * | ||||
10397 | * Purpose: Create a Cmm decorator object that implements a cache of most | ||||
10398 | * recently used pixel transformations. | ||||
10399 | * | ||||
10400 | * Args: | ||||
10401 | * pCmm - pointer to cmm object that we are attaching to. | ||||
10402 | * nCacheSize - number of most recently used transformations to cache | ||||
10403 | * bDeleteCmm - flag to indicate whether cmm should be deleted when | ||||
10404 | * this is destroyed. | ||||
10405 | * | ||||
10406 | * Return: | ||||
10407 | * A CIccMruCmm object that represents a cached form of the pCmm passed in. | ||||
10408 | * The pCmm will be owned by the returned object unless. | ||||
10409 | * | ||||
10410 | * If this function fails the pCmm object will be deleted. | ||||
10411 | ***************************************************************************** | ||||
10412 | */ | ||||
10413 | CIccMruCmm* CIccMruCmm::Attach(CIccCmm *pCmm, icUInt8Number nCacheSize/* =4 */, bool bDeleteCmm/*=true*/) | ||||
10414 | { | ||||
10415 | if (!pCmm || !nCacheSize) | ||||
10416 | return NULL__null; | ||||
10417 | |||||
10418 | if (!pCmm->Valid()) { | ||||
10419 | if (bDeleteCmm) | ||||
10420 | delete pCmm; | ||||
10421 | return NULL__null; | ||||
10422 | } | ||||
10423 | |||||
10424 | CIccMruCmm *rv = new CIccMruCmm(); | ||||
10425 | |||||
10426 | rv->m_pCmm = pCmm; | ||||
10427 | rv->m_nCacheSize = nCacheSize; | ||||
10428 | rv->m_bDeleteCmm = bDeleteCmm; | ||||
10429 | |||||
10430 | rv->m_nSrcSpace = pCmm->GetSourceSpace(); | ||||
10431 | rv->m_nDestSpace = pCmm->GetDestSpace(); | ||||
10432 | rv->m_nLastSpace = pCmm->GetLastSpace(); | ||||
10433 | rv->m_nLastIntent = pCmm->GetLastIntent(); | ||||
10434 | |||||
10435 | if (rv->Begin()!=icCmmStatOk) { | ||||
10436 | delete rv; | ||||
10437 | return NULL__null; | ||||
10438 | } | ||||
10439 | |||||
10440 | return rv; | ||||
10441 | } | ||||
10442 | |||||
10443 | CIccApplyCmm *CIccMruCmm::GetNewApplyCmm(icStatusCMM &status) | ||||
10444 | { | ||||
10445 | CIccApplyMruCmm *rv = new CIccApplyMruCmm(this); | ||||
10446 | |||||
10447 | if (!rv) { | ||||
10448 | status = icCmmStatAllocErr; | ||||
10449 | return NULL__null; | ||||
10450 | } | ||||
10451 | |||||
10452 | if (!rv->Init(m_pCmm, m_nCacheSize)) { | ||||
10453 | delete rv; | ||||
10454 | status = icCmmStatBad; | ||||
10455 | return NULL__null; | ||||
10456 | } | ||||
10457 | |||||
10458 | return rv; | ||||
10459 | } | ||||
10460 | |||||
10461 | /** | ||||
10462 | **************************************************************************** | ||||
10463 | * Name: CIccMruCache::CIccMruCache | ||||
10464 | * | ||||
10465 | * Purpose: constructor | ||||
10466 | ***************************************************************************** | ||||
10467 | */ | ||||
10468 | template<class T> | ||||
10469 | CIccMruCache<T>::CIccMruCache() | ||||
10470 | { | ||||
10471 | m_cache = NULL__null; | ||||
10472 | |||||
10473 | m_pixelData = NULL__null; | ||||
10474 | } | ||||
10475 | |||||
10476 | /** | ||||
10477 | **************************************************************************** | ||||
10478 | * Name: CIccMruCache::~CIccMruCache | ||||
10479 | * | ||||
10480 | * Purpose: destructor | ||||
10481 | ***************************************************************************** | ||||
10482 | */ | ||||
10483 | template<class T> | ||||
10484 | CIccMruCache<T>::~CIccMruCache() | ||||
10485 | { | ||||
10486 | if (m_cache) | ||||
10487 | delete[] m_cache; | ||||
10488 | |||||
10489 | if (m_pixelData) | ||||
10490 | free(m_pixelData); | ||||
10491 | } | ||||
10492 | |||||
10493 | /** | ||||
10494 | **************************************************************************** | ||||
10495 | * Name: CIccMruCache::Init | ||||
10496 | * | ||||
10497 | * Purpose: Initialize the object and set up the cache | ||||
10498 | * | ||||
10499 | * Args: | ||||
10500 | * pCmm - pointer to cmm object that we are attaching to. | ||||
10501 | * nCacheSize - number of most recently used transformations to cache | ||||
10502 | * | ||||
10503 | * Return: | ||||
10504 | * true if successful | ||||
10505 | ***************************************************************************** | ||||
10506 | */ | ||||
10507 | template<class T> | ||||
10508 | bool CIccMruCache<T>::Init(icUInt16Number nSrcSamples, icUInt16Number nDstSamples, icUInt16Number nCacheSize) | ||||
10509 | { | ||||
10510 | m_nSrcSamples = nSrcSamples; | ||||
10511 | m_nSrcSize = nSrcSamples * sizeof(T); | ||||
10512 | m_nDstSize = nDstSamples * sizeof(T); | ||||
10513 | |||||
10514 | m_nTotalSamples = m_nSrcSamples + nDstSamples; | ||||
10515 | |||||
10516 | m_nNumPixel = 0; | ||||
10517 | m_nCacheSize = nCacheSize; | ||||
10518 | |||||
10519 | m_pFirst = NULL__null; | ||||
10520 | m_cache = new CIccMruPixel<T>[nCacheSize]; | ||||
10521 | |||||
10522 | if (!m_cache) | ||||
10523 | return false; | ||||
10524 | |||||
10525 | m_pixelData = (T*)malloc(nCacheSize * m_nTotalSamples * sizeof(T)); | ||||
10526 | |||||
10527 | if (!m_pixelData) | ||||
10528 | return false; | ||||
10529 | |||||
10530 | return true; | ||||
10531 | } | ||||
10532 | |||||
10533 | template<class T> | ||||
10534 | CIccMruCache<T> *CIccMruCache<T>::NewMruCache(icUInt16Number nSrcSamples, icUInt16Number nDstSamples, icUInt16Number nCacheSize /* = 4 */) | ||||
10535 | { | ||||
10536 | CIccMruCache<T> *rv = new CIccMruCache<T>; | ||||
10537 | |||||
10538 | if (!rv->Init(nSrcSamples, nDstSamples, nCacheSize)) { | ||||
10539 | delete rv; | ||||
10540 | return NULL__null; | ||||
10541 | } | ||||
10542 | |||||
10543 | return rv; | ||||
10544 | } | ||||
10545 | |||||
10546 | /** | ||||
10547 | **************************************************************************** | ||||
10548 | * Name: CIccMruCache::Apply | ||||
10549 | * | ||||
10550 | * Purpose: Apply a transformation to a pixel. | ||||
10551 | * | ||||
10552 | * Args: | ||||
10553 | * DstPixel - Location to store pixel results | ||||
10554 | * SrcPixel - Location to get pixel values from | ||||
10555 | * | ||||
10556 | * Return: | ||||
10557 | * true if SrcPixel found in cache and DstPixel initialized with value | ||||
10558 | * fails if SrcPixel not found (DstPixel not touched) | ||||
10559 | ***************************************************************************** | ||||
10560 | */ | ||||
10561 | template<class T> | ||||
10562 | bool CIccMruCache<T>::Apply(T *DstPixel, const T *SrcPixel) | ||||
10563 | { | ||||
10564 | CIccMruPixel<T> *ptr, *prev = NULL__null, *last = NULL__null; | ||||
10565 | int i; | ||||
10566 | T *pixel; | ||||
10567 | |||||
10568 | for (ptr = m_pFirst, i = 0; ptr; ptr = ptr->pNext, i++) { | ||||
10569 | if (!memcmp(SrcPixel, ptr->pPixelData, m_nSrcSize)) { | ||||
10570 | memcpy(DstPixel, &ptr->pPixelData[m_nSrcSamples], m_nDstSize); | ||||
10571 | if (ptr != m_pFirst) { | ||||
10572 | last->pNext = ptr->pNext; | ||||
10573 | |||||
10574 | ptr->pNext = m_pFirst; | ||||
10575 | m_pFirst = ptr; | ||||
10576 | } | ||||
10577 | return true; | ||||
10578 | } | ||||
10579 | prev = last; | ||||
10580 | last = ptr; | ||||
10581 | } | ||||
10582 | |||||
10583 | //If we get here SrcPixel is not in the cache | ||||
10584 | if (i < m_nCacheSize) { | ||||
10585 | pixel = &m_pixelData[i*m_nTotalSamples]; | ||||
10586 | |||||
10587 | ptr = &m_cache[i]; | ||||
10588 | ptr->pPixelData = pixel; | ||||
10589 | |||||
10590 | if (m_pFirst) { | ||||
10591 | ptr->pNext = m_pFirst; | ||||
10592 | } | ||||
10593 | m_pFirst = ptr; | ||||
10594 | } | ||||
10595 | else { //Reuse oldest value and put it at the front of the list | ||||
10596 | prev->pNext = NULL__null; | ||||
10597 | last->pNext = m_pFirst; | ||||
10598 | |||||
10599 | m_pFirst = last; | ||||
10600 | pixel = last->pPixelData; | ||||
10601 | } | ||||
10602 | T *dest = &pixel[m_nSrcSamples]; | ||||
10603 | |||||
10604 | memcpy(pixel, SrcPixel, m_nSrcSize); | ||||
10605 | |||||
10606 | return false; | ||||
10607 | } | ||||
10608 | |||||
10609 | template<class T> | ||||
10610 | void CIccMruCache<T>::Update(T* DstPixel) | ||||
10611 | { | ||||
10612 | memcpy(&m_pFirst->pPixelData[m_nSrcSamples], DstPixel, m_nDstSize); | ||||
10613 | } | ||||
10614 | |||||
10615 | //Make sure typedef classes get built | ||||
10616 | template class CIccMruCache<icFloatNumber>; | ||||
10617 | template class CIccMruCache<icUInt8Number>; | ||||
10618 | template class CIccMruCache<icUInt16Number>; | ||||
10619 | |||||
10620 | |||||
10621 | CIccApplyMruCmm::CIccApplyMruCmm(CIccMruCmm *pCmm) : CIccApplyCmm(pCmm) | ||||
10622 | { | ||||
10623 | m_pCachedCmm = NULL__null; | ||||
10624 | m_pCache = NULL__null; | ||||
10625 | } | ||||
10626 | |||||
10627 | /** | ||||
10628 | **************************************************************************** | ||||
10629 | * Name: CIccApplyMruCmm::~CIccApplyMruCmm | ||||
10630 | * | ||||
10631 | * Purpose: destructor | ||||
10632 | ***************************************************************************** | ||||
10633 | */ | ||||
10634 | CIccApplyMruCmm::~CIccApplyMruCmm() | ||||
10635 | { | ||||
10636 | if (m_pCache) | ||||
10637 | delete m_pCache; | ||||
10638 | |||||
10639 | } | ||||
10640 | |||||
10641 | /** | ||||
10642 | **************************************************************************** | ||||
10643 | * Name: CIccApplyMruCmm::Init | ||||
10644 | * | ||||
10645 | * Purpose: Initialize the object and set up the cache | ||||
10646 | * | ||||
10647 | * Args: | ||||
10648 | * pCmm - pointer to cmm object that we are attaching to. | ||||
10649 | * nCacheSize - number of most recently used transformations to cache | ||||
10650 | * | ||||
10651 | * Return: | ||||
10652 | * true if successful | ||||
10653 | ***************************************************************************** | ||||
10654 | */ | ||||
10655 | bool CIccApplyMruCmm::Init(CIccCmm *pCachedCmm, icUInt16Number nCacheSize) | ||||
10656 | { | ||||
10657 | m_pCachedCmm = pCachedCmm; | ||||
10658 | |||||
10659 | m_pCache = CIccMruCacheFloat::NewMruCache(m_pCmm->GetSourceSamples(), m_pCmm->GetDestSamples(), nCacheSize); | ||||
10660 | |||||
10661 | if (!m_pCache) | ||||
10662 | return false; | ||||
10663 | |||||
10664 | return true; | ||||
10665 | } | ||||
10666 | |||||
10667 | /** | ||||
10668 | **************************************************************************** | ||||
10669 | * Name: CIccMruCmm::Apply | ||||
10670 | * | ||||
10671 | * Purpose: Apply a transformation to a pixel. | ||||
10672 | * | ||||
10673 | * Args: | ||||
10674 | * DstPixel - Location to store pixel results | ||||
10675 | * SrcPixel - Location to get pixel values from | ||||
10676 | * | ||||
10677 | * Return: | ||||
10678 | * icCmmStatOk if successful | ||||
10679 | ***************************************************************************** | ||||
10680 | */ | ||||
10681 | icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) | ||||
10682 | { | ||||
10683 | #if defined(_DEBUG) | ||||
10684 | if (!m_pCache) | ||||
10685 | return icCmmStatInvalidLut; | ||||
10686 | #endif | ||||
10687 | |||||
10688 | if (!m_pCache->Apply(DstPixel, SrcPixel)) { | ||||
10689 | |||||
10690 | m_pCachedCmm->Apply(DstPixel, SrcPixel); | ||||
10691 | |||||
10692 | m_pCache->Update(DstPixel); | ||||
10693 | } | ||||
10694 | |||||
10695 | return icCmmStatOk; | ||||
10696 | } | ||||
10697 | |||||
10698 | /** | ||||
10699 | **************************************************************************** | ||||
10700 | * Name: CIccMruCmm::Apply | ||||
10701 | * | ||||
10702 | * Purpose: Apply a transformation to a pixel. | ||||
10703 | * | ||||
10704 | * Args: | ||||
10705 | * DstPixel - Location to store pixel results | ||||
10706 | * SrcPixel - Location to get pixel values from | ||||
10707 | * nPixels - number of pixels to convert | ||||
10708 | * | ||||
10709 | * Return: | ||||
10710 | * icCmmStatOk if successful | ||||
10711 | ***************************************************************************** | ||||
10712 | */ | ||||
10713 | icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) | ||||
10714 | { | ||||
10715 | icUInt32Number k; | ||||
10716 | |||||
10717 | #if defined(_DEBUG) | ||||
10718 | if (!m_pCache) | ||||
10719 | return icCmmStatInvalidLut; | ||||
10720 | #endif | ||||
10721 | |||||
10722 | for (k=0; k<nPixels;k++) { | ||||
10723 | if (!m_pCache->Apply(DstPixel, SrcPixel)) { | ||||
10724 | m_pCachedCmm->Apply(DstPixel, SrcPixel); | ||||
10725 | m_pCache->Update(DstPixel); | ||||
10726 | } | ||||
10727 | SrcPixel += m_pCmm->GetSourceSamples(); | ||||
10728 | DstPixel += m_pCmm->GetDestSamples(); | ||||
10729 | } | ||||
10730 | |||||
10731 | return icCmmStatOk; | ||||
10732 | } | ||||
10733 | |||||
10734 | |||||
10735 | #ifdef USEREFICCMAXNAMESPACE | ||||
10736 | } //namespace refIccMAX | ||||
10737 | #endif |