Bug Summary

File:IccProfLib/IccCmm.cpp
Warning:line 3471, column 7
Value stored to 'szSrc' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-apple-macosx14.0.0 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name IccCmm.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -ffp-contract=on -fno-rounding-math -funwind-tables=2 -target-sdk-version=14.0 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -target-cpu penryn -tune-cpu generic -debugger-tuning=lldb -target-linker-version 1015.7 -fprofile-instrument=clang -fcoverage-mapping -fcoverage-compilation-dir=/Users/xss/DemoIccMAX-hoyt-master/build/IccProfLib -resource-dir /usr/local/Cellar/llvm/17.0.3/lib/clang/17 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk -D IccProfLib2_EXPORTS -I /Users/xss/DemoIccMAX-hoyt-master/build/Cmake/../../IccProfLib -I /Developer/Headers/FlatCarbon -F/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/System/Library/Frameworks -internal-isystem /usr/local/Cellar/llvm/17.0.3/bin/../include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/usr/local/include -internal-isystem /usr/local/Cellar/llvm/17.0.3/lib/clang/17/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/usr/include -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/Users/xss/DemoIccMAX-hoyt-master/build/IccProfLib -ferror-limit 19 -fsanitize=address -fsanitize-system-ignorelist=/usr/local/Cellar/llvm/17.0.3/lib/clang/17/share/asan_ignorelist.txt -fno-sanitize-memory-param-retval -fsanitize-address-use-after-scope -fsanitize-address-globals-dead-stripping -fno-assume-sane-operator-new -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fmax-type-align=16 -analyzer-output=html -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/folders/l9/sd9kj1px4yq2wc5_lkwhlt6w0000gn/T/scan-build-2023-10-28-102616-57860-1 -x c++ /Users/xss/DemoIccMAX-hoyt-master/IccProfLib/IccCmm.cpp
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
89namespace refIccMAX {
90#endif
91
92////
93// Useful Macros
94////
95
96static __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 */
134CIccPCS::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*/
154void 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 */
176const 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 */
238void 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 */
265icFloatNumber 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 */
283icFloatNumber 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 */
299void 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 */
332void 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 */
375void 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 */
390void 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 */
405void 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 */
427void 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*/
442CIccCreateXformHintManager::~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*/
471bool 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*/
507bool 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*/
540IIccCreateXformHint* 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 */
567CIccXform::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 */
592CIccXform::~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
608void 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 */
637CIccXform *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*/
1292CIccXform *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 ******************************************************************************/
1394void 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 */
1454CIccXform *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 */
1484icStatusCMM 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*/
1615CIccApplyXform *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 */
1642void 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 */
1698const 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 */
1723void 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*/
1741icColorSpaceSignature 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*/
1780icUInt16Number 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*/
1811icColorSpaceSignature 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*/
1853icUInt16Number 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*/
1882CIccApplyXform::CIccApplyXform(CIccXform *pXform)
1883{
1884 m_pXform = pXform;
1885}
1886
1887/**
1888**************************************************************************
1889* Name: CIccApplyXform::CIccApplyXform
1890*
1891* Purpose:
1892* Destructor
1893**************************************************************************
1894*/
1895CIccApplyXform::~CIccApplyXform()
1896{
1897}
1898
1899
1900/**
1901**************************************************************************
1902* Name: CIccApplyPcsXform::CIccApplyPcsXform
1903*
1904* Purpose:
1905* Constructor
1906**************************************************************************
1907*/
1908CIccApplyPcsXform::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*/
1923CIccApplyPcsXform::~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*/
1950bool 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!=NULL__null && m_temp2!=NULL__null;
1961}
1962
1963
1964void 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*/
1983CIccPcsXform::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*/
2002CIccPcsXform::~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 */
2025icStatusCMM 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 */
2408icStatusCMM 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 */
2499CIccApplyXform *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 */
2539icUInt16Number 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 */
2562void 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 */
2579void 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 */
2599void 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 */
2619void 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 */
2639void 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 */
2659void 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 */
2682void 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 */
2697void 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*/
2712void 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*/
2731void 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 */
2752void 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 */
2784void 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 */
2803void 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 */
2824icStatusCMM 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
2945void 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 */
3006void 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 */
3036CIccPcsStepMatrix *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 */
3063void 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 */
3086void 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 */
3130void 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 */
3177icStatusCMM 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 */
3242icStatusCMM CIccPcsXform::pushBiRef2Xyz(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc)
3243{
3244 icStatusCMM stat = pushBiRef2Rad(pProfile, pPcc);
3245 if (stat!=icCmmStatOk)
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 */
3276icStatusCMM 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*/
3355void 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*/
3408CIccApplyPcsStep* 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*/
3422void 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*/
3437void 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*/
3451CIccPcsStepRouteMcs::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;
Value stored to 'szSrc' is never read
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*/
3494CIccPcsStepRouteMcs::~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*/
3511bool 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*/
3535void 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*/
3557void CIccPcsStepRouteMcs::dump(std::string &str) const
3558{
3559 str += "\nCIccPcsStepRouteMcs\n\n";
3560}
3561
3562extern 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*/
3572bool 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*/
3589CIccPcsStepLabToXYZ::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*/
3608void 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*/
3629void 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*/
3645CIccPcsStep *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*/
3664CIccPcsStepXYZToLab::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*/
3683void 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*/
3702void 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*/
3718CIccPcsStep *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*/
3737CIccPcsStepLab2ToXYZ::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*/
3755void 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*/
3776void 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*/
3792CIccPcsStep *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*/
3811CIccPcsStepXYZToLab2::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*/
3830void 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*/
3849void 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*/
3865CIccPcsStep *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*/
3884CIccPcsStepOffset::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*/
3899CIccPcsStepOffset::~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*/
3914void 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*/
3938void 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*/
3959CIccPcsStepOffset *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*/
3986CIccPcsStep *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*/
4003bool 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*/
4023CIccPcsStepScale::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*/
4038CIccPcsStepScale::~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*/
4052void 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*/
4076void 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*/
4097CIccPcsStepScale *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*/
4122CIccPcsStepMatrix *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*/
4153CIccPcsStepMatrix *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*/
4187CIccPcsStep *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*/
4214bool 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*/
4235void 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*/
4251CIccPcsStepMatrix *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*/
4283CIccPcsStepMatrix *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*/
4322CIccPcsStep *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*/
4344CIccPcsStep *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*/
4377CIccPcsStepMpe::CIccPcsStepMpe(CIccTagMultiProcessElement *pMpe)
4378{
4379 m_pMpe = pMpe;
4380}
4381
4382
4383/**
4384**************************************************************************
4385* Name: CIccPcsStepMpe::~CIccPcsStepMpe
4386*
4387* Purpose:
4388* Destructor
4389**************************************************************************
4390*/
4391CIccPcsStepMpe::~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*/
4406CIccApplyPcsStep* 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*/
4422void 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*/
4438void 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*/
4453bool 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*/
4469icUInt16Number 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*/
4484icUInt16Number 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*/
4499CIccMpeMatrix *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*/
4529bool CIccPcsStepMpe::Begin()
4530{
4531 return m_pMpe->Begin();
4532}
4533
4534
4535/**
4536**************************************************************************
4537* Name: CIccPcsStepSrcMatrix::CIccPcsStepSrcMatrix
4538*
4539* Purpose:
4540* Constructor
4541**************************************************************************
4542*/
4543CIccPcsStepSrcMatrix::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*/
4559CIccPcsStepSrcMatrix::~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*/
4575void 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*/
4597void 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*/
4617CIccPcsStepSparseMatrix::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*/
4635CIccPcsStepSparseMatrix::~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*/
4651void 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*/
4667void 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*/
4687CIccPcsStepSrcSparseMatrix::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*/
4706CIccPcsStepSrcSparseMatrix::~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*/
4722void 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*/
4738void 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*/
4758CIccXformMonochrome::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*/
4773CIccXformMonochrome::~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*/
4790icStatusCMM 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*/
4837void 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*/
4910CIccCurve *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*/
4935CIccCurve *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*/
4974LPIccCurve* 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*/
5002LPIccCurve* 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 */
5024CIccXformMatrixTRC::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 */
5039CIccXformMatrixTRC::~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 */
5061icStatusCMM 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
5141static icFloatNumber XYZScale(icFloatNumber v)
5142{
5143 v = (icFloatNumber)(v * 32768.0 / 65535.0);
5144 return v;
5145}
5146
5147static icFloatNumber XYZDescale(icFloatNumber v)
5148{
5149 return (icFloatNumber)(v * 65535.0 / 32768.0);
5150}
5151
5152static 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 */
5175void 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 */
5236CIccCurve *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 */
5261CIccTagXYZ *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 */
5286CIccCurve *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*/
5325LPIccCurve* 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*/
5355LPIccCurve* 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 */
5382CIccXform3DLut::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 */
5402CIccXform3DLut::~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 */
5562void 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*/
5655LPIccCurve* 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*/
5697LPIccCurve* 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 */
5736CIccXform4DLut::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 */
5757CIccXform4DLut::~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 */
5772icStatusCMM 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 */
5910void 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*/
5990LPIccCurve* 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*/
6034LPIccCurve* 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 */
6074CIccXformNDLut::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 */
6095CIccXformNDLut::~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 */
6110icStatusCMM 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 */
6247void 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*/
6341LPIccCurve* 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*/
6383LPIccCurve* 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 */
6424CIccXformNamedColor::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 */
6461CIccXformNamedColor::~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 */
6475icStatusCMM 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 */
6532icStatusCMM 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 = pA