Bug Summary

File:IccProfLib/IccCmm.cpp
Warning:line 6278, column 20
1st function call argument is an uninitialized value

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;
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++)
1
Assuming 'i' is >= field 'm_nNumInput'
2
Loop condition is false. Execution continues on line 6256
6254 Pixel[i] = SrcPixel[i];
6255
6256 if (m_pTag->m_bInputMatrix) {
3
Assuming field 'm_bInputMatrix' is true
4
Taking true branch
6257 if (m_ApplyCurvePtrB) {
5
Assuming field 'm_ApplyCurvePtrB' is null
6
Taking false branch
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) {
7
Assuming field 'm_CLUT' is null
8
Taking false branch
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) {
9
Assuming field 'm_ApplyCurvePtrA' is non-null
10
Taking true branch
6277 for (i=0; i<m_pTag->m_nOutput; i++) {
11
The value 0 is assigned to 'i'
12
Assuming 'i' is < field 'm_nOutput'
13
Loop condition is true. Entering loop body
6278 Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]);
14
1st function call argument is an uninitialized value
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 = pArray->FindPcsColor(pix);
6562 if (pColor)
6563 NamedColor = pColor->getName();
6564 else
6565 return icCmmStatColorNotFound;
6566 }
6567 }
6568 else {
6569 pColor = pArray->FindDeviceColor(SrcPixel);
6570 if (pColor)
6571 NamedColor = pColor->getName();
6572 else
6573 return icCmmStatColorNotFound;
6574 }
6575
6576 sprintf(DstColorName, "%s", NamedColor.c_str());
6577 }
6578 else if (m_pTag) {
6579 const CIccTagNamedColor2 *pTag = m_pTag;
6580
6581 icFloatNumber DevicePix[16], PCSPix[3];
6582 std::string NamedColor;
6583 icUInt32Number i, j;
6584
6585 if (IsSrcPCS()) {
6586 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
6587 for(i=0; i<3; i++)
6588 PCSPix[i] = SrcPixel[i];
6589
6590 j = pTag->FindCachedPCSColor(PCSPix);
6591 pTag->GetColorName(NamedColor, j);
6592 }
6593 else {
6594 for(i=0; i<m_pTag->GetDeviceCoords(); i++)
6595 DevicePix[i] = SrcPixel[i];
6596
6597 j = pTag->FindDeviceColor(DevicePix);
6598 pTag->GetColorName(NamedColor, j);
6599 }
6600
6601 sprintf(DstColorName, "%s", NamedColor.c_str());
6602 }
6603 else
6604 return icCmmStatBadXform;
6605
6606 return icCmmStatOk;
6607}
6608
6609
6610/**
6611**************************************************************************
6612* Name: CIccXformNamedColor::Apply
6613*
6614* Purpose:
6615* Does the actual application of the Xform.
6616*
6617* Args:
6618* pApply = ApplyXform object containing temporary storage used during Apply
6619* DstPixel = Destination pixel where the result is stored,
6620* SrcColorName = Source color name which is to be applied.
6621**************************************************************************
6622*/
6623icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint) const
6624{
6625
6626 if (m_pArray) {
6627 const CIccArrayNamedColor *pArray = m_pArray;
6628
6629 CIccStructNamedColor *pColor;
6630
6631 if (m_nSrcSpace != icSigNamedData)
6632 return icCmmStatBadSpaceLink;
6633
6634 pColor = pArray->FindColor(SrcColorName);
6635 if (!pColor)
6636 return icCmmStatColorNotFound;
6637
6638 if (IsDestPCS()) {
6639 if (IsSpaceSpectralPCS(m_nDestSpace)) {
6640 if (!pArray->GetSpectralTint(DstPixel, pColor, tint))
6641 return icCmmStatBadTintXform;
6642 }
6643 else {
6644 if (!pArray->GetPcsTint(DstPixel, pColor, tint))
6645 return icCmmStatBadTintXform;
6646
6647 if (m_nDestSpace == icSigLabData) {
6648 icLabToPcs(DstPixel);
6649 }
6650 else {
6651 icXyzToPcs(DstPixel);
6652 }
6653 CheckDstAbs(DstPixel);
6654 }
6655 }
6656 else {
6657 if (!pArray->GetDeviceTint(DstPixel, pColor, tint))
6658 return icCmmStatBadTintXform;
6659 }
6660 }
6661 else if (m_pTag) {
6662 const CIccTagNamedColor2 *pTag = m_pTag;
6663
6664 icInt32Number j;
6665
6666 if (m_nSrcSpace != icSigNamedData)
6667 return icCmmStatBadSpaceLink;
6668
6669 if (IsDestPCS()) {
6670
6671 j = pTag->FindColor(SrcColorName);
6672 if (j<0)
6673 return icCmmStatColorNotFound;
6674
6675 if (m_nDestSpace == icSigLabData) {
6676 memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber));
6677 }
6678 else {
6679 memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber));
6680 }
6681 CheckDstAbs(DstPixel);
6682 }
6683 else {
6684 j = pTag->FindColor(SrcColorName);
6685 if (j<0)
6686 return icCmmStatColorNotFound;
6687 memcpy(DstPixel, pTag->GetEntry(j)->deviceCoords, pTag->GetDeviceCoords()*sizeof(icFloatNumber));
6688 }
6689 }
6690
6691 return icCmmStatOk;
6692}
6693
6694/**
6695 **************************************************************************
6696 * Name: CIccXformNamedColor::SetSrcSpace
6697 *
6698 * Purpose:
6699 * Sets the source space of the Xform
6700 *
6701 * Args:
6702 * nSrcSpace = signature of the color space to be set
6703 **************************************************************************
6704 */
6705icStatusCMM CIccXformNamedColor::SetSrcSpace(icColorSpaceSignature nSrcSpace)
6706{
6707 if (m_pArray) {
6708
6709 }
6710 else if (m_pTag) {
6711 CIccTagNamedColor2 *pTag = m_pTag;
6712
6713 if (nSrcSpace!=pTag->GetPCS())
6714 if (nSrcSpace!=pTag->GetDeviceSpace())
6715 if (nSrcSpace!=icSigNamedData)
6716 return icCmmStatBadSpaceLink;
6717 }
6718
6719 m_nSrcSpace = nSrcSpace;
6720
6721 return icCmmStatOk;
6722}
6723
6724/**
6725 **************************************************************************
6726 * Name: CIccXformNamedColor::SetDestSpace
6727 *
6728 * Purpose:
6729 * Sets the destination space of the Xform
6730 *
6731 * Args:
6732 * nDestSpace = signature of the color space to be set
6733 **************************************************************************
6734 */
6735icStatusCMM CIccXformNamedColor::SetDestSpace(icColorSpaceSignature nDestSpace)
6736{
6737 if (m_nSrcSpace == nDestSpace)
6738 return icCmmStatBadSpaceLink;
6739
6740 if (m_pArray) {
6741
6742 }
6743 else if (m_pTag) {
6744 CIccTagNamedColor2 *pTag = (CIccTagNamedColor2*)m_pTag;
6745
6746 if (nDestSpace!=pTag->GetPCS())
6747 if (nDestSpace!=pTag->GetDeviceSpace())
6748 if (nDestSpace!=icSigNamedData)
6749 return icCmmStatBadSpaceLink;
6750 }
6751
6752 m_nDestSpace = nDestSpace;
6753
6754 return icCmmStatOk;
6755}
6756
6757/**
6758 **************************************************************************
6759 * Name: CIccXformNamedColor::IsSrcPCS
6760 *
6761 * Purpose:
6762 * Sets the source space is a PCS space
6763 **************************************************************************
6764 */
6765bool CIccXformNamedColor::IsSrcPCS() const
6766{
6767 if (m_pTag) {
6768 return m_nSrcSpace == m_pTag->GetPCS();
6769 }
6770 else if (m_pArray) {
6771 return IsSpacePCS(m_nSrcSpace)(((m_nSrcSpace)==icSigXYZData || (m_nSrcSpace)==icSigLabData)
|| IsSpaceSpectralPCS(m_nSrcSpace))
;
6772 }
6773 else
6774 return false;
6775}
6776
6777
6778/**
6779 **************************************************************************
6780 * Name: CIccXformNamedColor::IsDestPCS
6781 *
6782 * Purpose:
6783 * Sets the destination space is a PCS space
6784 **************************************************************************
6785 */
6786bool CIccXformNamedColor::IsDestPCS() const
6787{
6788 if (m_pTag) {
6789 return m_nDestSpace == m_pTag->GetPCS();
6790 }
6791 else if (m_pArray) {
6792 return IsSpacePCS(m_nDestSpace)(((m_nDestSpace)==icSigXYZData || (m_nDestSpace)==icSigLabData
) || IsSpaceSpectralPCS(m_nDestSpace))
;
6793 }
6794 else
6795 return false;
6796}
6797
6798
6799/**
6800**************************************************************************
6801* Name: CIccXformMPE::CIccXformMPE
6802*
6803* Purpose:
6804* Constructor
6805**************************************************************************
6806*/
6807CIccXformMpe::CIccXformMpe(CIccTag *pTag)
6808{
6809 if (pTag && pTag->GetType()==icSigMultiProcessElementType)
6810 m_pTag = (CIccTagMultiProcessElement*)pTag;
6811 else
6812 m_pTag = NULL__null;
6813
6814 m_bUsingAcs = false;
6815 m_pAppliedPCC = NULL__null;
6816 m_bDeleteAppliedPCC = false;
6817}
6818
6819/**
6820**************************************************************************
6821* Name: CIccXformMPE::~CIccXformMPE
6822*
6823* Purpose:
6824* Destructor
6825**************************************************************************
6826*/
6827CIccXformMpe::~CIccXformMpe()
6828{
6829 if (m_pAppliedPCC && m_bDeleteAppliedPCC)
6830 delete m_pAppliedPCC;
6831}
6832
6833/**
6834**************************************************************************
6835* Name: CIccXformMPE::Create
6836*
6837* Purpose:
6838* This is a static Creation function that creates derived CIccXform objects and
6839* initializes them.
6840*
6841* Args:
6842* pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will
6843* be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile
6844* object needs to be allocated on the heap.
6845* bInput = flag to indicate whether to use the input or output side of the profile,
6846* nIntent = the rendering intent to apply to the profile,
6847* nInterp = the interpolation algorithm to use for N-D luts.
6848* nLutType = selection of which transform lut to use
6849* pHintManager = hints for creating the xform
6850*
6851* Return:
6852* A suitable pXform object
6853**************************************************************************
6854*/
6855CIccXform *CIccXformMpe::Create(CIccProfile *pProfile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */,
6856 icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */,
6857 CIccCreateXformHintManager *pHintManager/* =NULL */)
6858{
6859 CIccXform *rv = NULL__null;
6860 icRenderingIntent nTagIntent = nIntent;
6861 bool bUseSpectralPCS = false;
6862 bool bAbsToRel = false;
6863 icXformLutType nUseLutType = nLutType;
6864 bool bUseColorimeticTags = true;
6865 bool bUseDToB = true;
6866
6867 if (nLutType == icXformLutSpectral) {
6868 nUseLutType = icXformLutColor;
6869 bUseColorimeticTags = false;
6870 }
6871 else if (nLutType == icXformLutColorimetric) {
6872 nUseLutType = icXformLutColor;
6873 bUseDToB = false;
6874 }
6875
6876 if (nTagIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f))
6877 nTagIntent = icPerceptual;
6878
6879 switch (nUseLutType) {
6880 case icXformLutColor:
6881 if (bInput) {
6882 CIccTag *pTag = NULL__null;
6883 if (bUseDToB) {
6884 pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent);
6885
6886 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
6887 pTag = pProfile->FindTag(icSigDToB1Tag);
6888 if (pTag)
6889 nTagIntent = icRelativeColorimetric;
6890 }
6891 else if (!pTag && nTagIntent != icAbsoluteColorimetric) {
6892 pTag = pProfile->FindTag(icSigDToB3Tag);
6893 if (pTag) {
6894 nTagIntent = icAbsoluteColorimetric;
6895 bAbsToRel = true;
6896 }
6897 }
6898
6899 if (!pTag) {
6900 pTag = pProfile->FindTag(icSigDToB0Tag);
6901 }
6902 }
6903
6904 //Unsupported elements cause fall back behavior
6905 if (pTag && !pTag->IsSupported())
6906 pTag = NULL__null;
6907
6908 if (pTag && pProfile->m_Header.spectralPCS) {
6909 bUseSpectralPCS = true;
6910 }
6911
6912 if (bUseColorimeticTags) {
6913 if (!pTag) {
6914 if (nTagIntent == icAbsoluteColorimetric)
6915 nTagIntent = icRelativeColorimetric;
6916 pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent);
6917 }
6918
6919 if (!pTag) {
6920 pTag = pProfile->FindTag(icSigAToB0Tag);
6921 }
6922 }
6923
6924 if (!pTag) {
6925 if (bUseColorimeticTags && pProfile->m_Header.colorSpace == icSigRgbData && pProfile->m_Header.version < icVersionNumberV50x05000000) {
6926 rv = new CIccXformMatrixTRC();
6927 }
6928 else
6929 return NULL__null;
6930 }
6931 else if (pTag->GetType()==icSigMultiProcessElementType) {
6932 rv = new CIccXformMpe(pTag);
6933 }
6934 else {
6935 switch(pProfile->m_Header.colorSpace) {
6936 case icSigXYZData:
6937 case icSigLabData:
6938 case icSigLuvData:
6939 case icSigYCbCrData:
6940 case icSigYxyData:
6941 case icSigRgbData:
6942 case icSigHsvData:
6943 case icSigHlsData:
6944 case icSigCmyData:
6945 case icSig3colorData:
6946 rv = new CIccXform3DLut(pTag);
6947 break;
6948
6949 case icSigCmykData:
6950 case icSig4colorData:
6951 rv = new CIccXform4DLut(pTag);
6952 break;
6953
6954 default:
6955 rv = new CIccXformNDLut(pTag);
6956 break;
6957 }
6958 }
6959 }
6960 else {
6961 CIccTag *pTag = NULL__null;
6962
6963 if (bUseDToB) {
6964 pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent);
6965
6966 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
6967 pTag = pProfile->FindTag(icSigBToD1Tag);
6968 if (pTag)
6969 nTagIntent = icRelativeColorimetric;
6970 }
6971 else if (!pTag && nTagIntent != icAbsoluteColorimetric) {
6972 pTag = pProfile->FindTag(icSigBToD3Tag);
6973 if (pTag) {
6974 nTagIntent = icAbsoluteColorimetric;
6975 bAbsToRel = true;
6976 }
6977 }
6978
6979 if (!pTag) {
6980 pTag = pProfile->FindTag(icSigBToD0Tag);
6981 }
6982 }
6983
6984 //Unsupported elements cause fall back behavior
6985 if (pTag && !pTag->IsSupported())
6986 pTag = NULL__null;
6987
6988 if (bUseColorimeticTags) {
6989 if (!pTag) {
6990 if (nTagIntent == icAbsoluteColorimetric)
6991 nTagIntent = icRelativeColorimetric;
6992 pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent);
6993 }
6994
6995 if (!pTag) {
6996 pTag = pProfile->FindTag(icSigBToA0Tag);
6997 }
6998 }
6999
7000 if (!pTag) {
7001 if (bUseColorimeticTags && pProfile->m_Header.colorSpace == icSigRgbData && pProfile->m_Header.version<icVersionNumberV50x05000000) {
7002 rv = new CIccXformMatrixTRC();
7003 }
7004 else
7005 return NULL__null;
7006 }
7007
7008 if (pTag->GetType()==icSigMultiProcessElementType) {
7009 rv = new CIccXformMpe(pTag);
7010 }
7011 else {
7012 switch(pProfile->m_Header.pcs) {
7013 case icSigXYZData:
7014 case icSigLabData:
7015 rv = new CIccXform3DLut(pTag);
7016
7017 default:
7018 break;
7019 }
7020 }
7021 }
7022 break;
7023
7024 case icXformLutNamedColor:
7025 {
7026 CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag);
7027 if (!pTag)
7028 return NULL__null;
7029
7030 rv = new CIccXformNamedColor(pTag, pProfile->m_Header.pcs, pProfile->m_Header.colorSpace,
7031 pProfile->m_Header.spectralPCS,
7032 &pProfile->m_Header.spectralRange,
7033 &pProfile->m_Header.biSpectralRange);
7034 }
7035 break;
7036
7037 case icXformLutPreview:
7038 {
7039 bInput = false;
7040 CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent);
7041 if (!pTag) {
7042 pTag = pProfile->FindTag(icSigPreview0Tag);
7043 }
7044 if (!pTag) {
7045 return NULL__null;
7046 }
7047 else {
7048 switch(pProfile->m_Header.pcs) {
7049 case icSigXYZData:
7050 case icSigLabData:
7051 rv = new CIccXform3DLut(pTag);
7052
7053 default:
7054 break;
7055 }
7056 }
7057 }
7058 break;
7059
7060 case icXformLutGamut:
7061 {
7062 bInput = false;
7063 CIccTag *pTag = pProfile->FindTag(icSigGamutTag);
7064 if (!pTag) {
7065 return NULL__null;
7066 }
7067 else {
7068 switch(pProfile->m_Header.pcs) {
7069 case icSigXYZData:
7070 case icSigLabData:
7071 rv = new CIccXform3DLut(pTag);
7072
7073 default:
7074 break;
7075 }
7076 }
7077 }
7078 break;
7079 }
7080
7081 if (rv) {
7082 rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel);
7083 }
7084
7085 return rv;
7086}
7087
7088/**
7089**************************************************************************
7090* Name: CIccXformMPE::IsLateBinding
7091*
7092* Purpose:
7093* Determines if any processing elements are late binding with connection
7094* conditions
7095**************************************************************************
7096*/
7097bool CIccXformMpe::IsLateBinding() const
7098{
7099 if (m_pTag)
7100 return m_pTag->IsLateBinding();
7101
7102 return false;
7103}
7104
7105/**
7106**************************************************************************
7107* Name: CIccXformMPE::IsLateBindingReflectance
7108*
7109* Purpose:
7110* Determines if any processing elements are late binding with connection
7111* conditions
7112**************************************************************************
7113*/
7114bool CIccXformMpe::IsLateBindingReflectance() const
7115{
7116 if (m_pTag)
7117 return m_pTag->IsLateBindingReflectance();
7118
7119 return false;
7120}
7121
7122/**
7123**************************************************************************
7124* Name: CIccXformMPE::GetConnectionConditions
7125*
7126* Purpose:
7127* Gets appropriate connection conditions
7128**************************************************************************
7129*/
7130IIccProfileConnectionConditions *CIccXformMpe::GetConnectionConditions() const
7131{
7132 if (m_pAppliedPCC)
7133 return m_pAppliedPCC;
7134
7135 return m_pConnectionConditions;
7136}
7137
7138/**
7139**************************************************************************
7140* Name: CIccXformMPE::SetAppliedCC
7141*
7142* Purpose:
7143* This creates combined connection conditions based on profile,
7144* alternate connection conditions and whether reflectance is used
7145* by any late binding processing elements.
7146**************************************************************************
7147*/
7148void CIccXformMpe::SetAppliedCC(IIccProfileConnectionConditions *pPCC)
7149{
7150 if (!pPCC) {
7151 if (m_pAppliedPCC && m_bDeleteAppliedPCC) {
7152 delete m_pAppliedPCC;
7153 }
7154 m_pAppliedPCC = NULL__null;
7155 m_bDeleteAppliedPCC = false;
7156 return;
7157 }
7158
7159 if (m_pTag) {
7160 bool bReflectance = m_pTag->IsLateBindingReflectance();
7161
7162 if (pPCC != (IIccProfileConnectionConditions *)m_pProfile) {
7163 if (!bReflectance) {
7164 const CIccTagSpectralViewingConditions *pViewPCC = pPCC ? pPCC->getPccViewingConditions() : NULL__null;
7165 const CIccTagSpectralViewingConditions *pViewProfile = m_pProfile ? m_pProfile->getPccViewingConditions() : NULL__null;
7166
7167 if (pViewPCC && pViewProfile &&
7168 pViewPCC->getStdIllumiant() == pViewProfile->getStdIllumiant() &&
7169 pViewPCC->getIlluminantCCT() == pViewProfile->getIlluminantCCT() &&
7170 pViewPCC->getStdIllumiant() != icIlluminantUnknown) {
7171 m_pAppliedPCC = pPCC;
7172 m_bDeleteAppliedPCC = false;
7173 }
7174 else {
7175 m_pAppliedPCC = new CIccCombinedConnectionConditions(m_pProfile, pPCC, bReflectance);
7176 m_bDeleteAppliedPCC = true;
7177 }
7178 }
7179 else {
7180 m_pAppliedPCC = new CIccCombinedConnectionConditions(m_pProfile, pPCC, bReflectance);
7181 m_bDeleteAppliedPCC = true;
7182 }
7183 }
7184 else {
7185 m_pAppliedPCC = NULL__null;
7186 }
7187 }
7188 else {
7189 m_pAppliedPCC = pPCC;
7190 m_bDeleteAppliedPCC = false;
7191 }
7192}
7193
7194
7195/**
7196**************************************************************************
7197* Name: CIccXformMPE::Begin
7198*
7199* Purpose:
7200* This function will be called before the xform is applied. Derived objects
7201* should also call the base class function to initialize for Absolute Colorimetric
7202* Intent handling which is performed through the use of the CheckSrcAbs and
7203* CheckDstAbs functions.
7204**************************************************************************
7205*/
7206icStatusCMM CIccXformMpe::Begin()
7207{
7208 icStatusCMM status;
7209 status = CIccXform::Begin();
7210
7211 if (status != icCmmStatOk)
7212 return status;
7213
7214 if (!m_pTag) {
7215 return icCmmStatInvalidLut;
7216 }
7217
7218 if (!m_pTag->Begin(icElemInterpLinear, GetProfileCC(), GetConnectionConditions(), GetCmmEnvVarLookup())) {
7219 return icCmmStatInvalidProfile;
7220 }
7221
7222 return icCmmStatOk;
7223}
7224
7225
7226/**
7227**************************************************************************
7228* Name: CIccXformMpe::GetNewApply
7229*
7230* Purpose:
7231* This Factory function allocates data specific for the application of the xform.
7232* This allows multiple threads to simultaneously use the same xform.
7233**************************************************************************
7234*/
7235CIccApplyXform *CIccXformMpe::GetNewApply(icStatusCMM &status)
7236{
7237 if (!m_pTag)
7238 return NULL__null;
7239
7240 CIccApplyXformMpe *rv= new CIccApplyXformMpe(this);
7241
7242 if (!rv) {
7243 status = icCmmStatAllocErr;
7244 return NULL__null;
7245 }
7246
7247 rv->m_pApply = m_pTag->GetNewApply();
7248 if (!rv->m_pApply) {
7249 status = icCmmStatAllocErr;
7250 delete rv;
7251 return NULL__null;
7252 }
7253
7254 status = icCmmStatOk;
7255 return rv;
7256}
7257
7258
7259/**
7260**************************************************************************
7261* Name: CIccXformMPE::Apply
7262*
7263* Purpose:
7264* Does the actual application of the Xform.
7265*
7266* Args:
7267* pApply = ApplyXform object containging temporary storage used during Apply
7268* DstPixel = Destination pixel where the result is stored,
7269* SrcPixel = Source pixel which is to be applied.
7270**************************************************************************
7271*/
7272void CIccXformMpe::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
7273{
7274 const CIccTagMultiProcessElement *pTag = m_pTag;
7275
7276 if (!m_bInput) { //PCS comming in?
7277 if (m_nIntent != icAbsoluteColorimetric || m_nIntent != m_nTagIntent) { //B2D3 tags don't need abs conversion
7278 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
7279 }
7280
7281 //Since MPE tags use "real" values for PCS we need to convert from
7282 //internal encoding used by IccProfLib
7283 icFloatNumber temp[3];
7284 switch (GetSrcSpace()) {
7285 case icSigXYZData:
7286 memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber));
7287 icXyzFromPcs(temp);
7288 SrcPixel = &temp[0];
7289 break;
7290
7291 case icSigLabData:
7292 memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber));
7293 icLabFromPcs(temp);
7294 SrcPixel = &temp[0];
7295 break;
7296
7297 default:
7298 break;
7299 }
7300 }
7301
7302 //Note: pApply should be a CIccApplyXformMpe type here
7303 CIccApplyXformMpe *pApplyMpe = (CIccApplyXformMpe *)pApply;
7304
7305 pTag->Apply(pApplyMpe->m_pApply, DstPixel, SrcPixel);
7306
7307 if (m_bInput) { //PCS going out?
7308 //Since MPE tags use "real" values for PCS we need to convert to
7309 //internal encoding used by IccProfLib
7310 switch(GetDstSpace()) {
7311 case icSigXYZData:
7312 icXyzToPcs(DstPixel);
7313 break;
7314
7315 case icSigLabData:
7316 icLabToPcs(DstPixel);
7317 break;
7318
7319 default:
7320 break;
7321 }
7322
7323 if (m_nIntent != icAbsoluteColorimetric || m_nIntent != m_nTagIntent) { //D2B3 tags don't need abs conversion
7324 CheckDstAbs(DstPixel);
7325 }
7326 }
7327}
7328
7329/**
7330**************************************************************************
7331* Name: CIccApplyXformMpe::CIccApplyXformMpe
7332*
7333* Purpose:
7334* Constructor
7335**************************************************************************
7336*/
7337CIccApplyXformMpe::CIccApplyXformMpe(CIccXformMpe *pXform) : CIccApplyXform(pXform)
7338{
7339}
7340
7341/**
7342**************************************************************************
7343* Name: CIccApplyXformMpe::~CIccApplyXformMpe
7344*
7345* Purpose:
7346* Destructor
7347**************************************************************************
7348*/
7349CIccApplyXformMpe::~CIccApplyXformMpe()
7350{
7351}
7352
7353
7354/**
7355**************************************************************************
7356* Name: CIccApplyCmm::CIccApplyCmm
7357*
7358* Purpose:
7359* Constructor
7360*
7361* Args:
7362* pCmm = ptr to CMM to apply against
7363**************************************************************************
7364*/
7365CIccApplyCmm::CIccApplyCmm(CIccCmm *pCmm)
7366{
7367 m_pCmm = pCmm;
7368 m_pPCS = m_pCmm->GetPCS();
7369
7370 m_Xforms = new CIccApplyXformList;
7371 m_Xforms->clear();
7372
7373 m_Pixel = NULL__null;
7374 m_Pixel2 = NULL__null;
7375}
7376
7377/**
7378**************************************************************************
7379* Name: CIccApplyCmm::~CIccApplyCmm
7380*
7381* Purpose:
7382* Destructor
7383**************************************************************************
7384*/
7385CIccApplyCmm::~CIccApplyCmm()
7386{
7387 if (m_Xforms) {
7388 CIccApplyXformList::iterator i;
7389
7390 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
7391 if (i->ptr)
7392 delete i->ptr;
7393 }
7394
7395 delete m_Xforms;
7396 }
7397
7398 if (m_pPCS)
7399 delete m_pPCS;
7400
7401 if (m_Pixel)
7402 free(m_Pixel);
7403 if (m_Pixel2)
7404 free(m_Pixel2);
7405}
7406
7407bool CIccApplyCmm::InitPixel()
7408{
7409 if (m_Pixel && m_Pixel2)
7410 return true;
7411
7412 icUInt16Number nSamples = 16;
7413 CIccApplyXformList::iterator i;
7414
7415 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
7416 if (i->ptr->GetXform()) {
7417 icUInt16Number nXformSamples = i->ptr->GetXform()->GetNumDstSamples();
7418 if (nXformSamples>nSamples)
7419 nSamples=nXformSamples;
7420 }
7421 }
7422 m_Pixel = (icFloatNumber*)malloc(nSamples*sizeof(icFloatNumber));
7423 m_Pixel2 = (icFloatNumber*)malloc(nSamples*sizeof(icFloatNumber));
7424
7425 if (!m_Pixel || !m_Pixel2)
7426 return false;
7427
7428 return true;
7429}
7430
7431
7432/**
7433**************************************************************************
7434* Name: CIccApplyCmm::Apply
7435*
7436* Purpose:
7437* Does the actual application of the Xforms in the list.
7438*
7439* Args:
7440* DstPixel = Destination pixel where the result is stored,
7441* SrcPixel = Source pixel which is to be applied.
7442**************************************************************************
7443*/
7444icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
7445{
7446 icFloatNumber *pDst, *pTmp;
7447 const icFloatNumber *pSrc;
7448 CIccApplyXformList::iterator i;
7449 const CIccXform *pLastXform;
7450 int j, n = (int)m_Xforms->size();
7451 bool bNoClip;
7452
7453 if (!n)
7454 return icCmmStatBadXform;
7455
7456 if (!m_Pixel && !InitPixel()) {
7457 return icCmmStatAllocErr;
7458 }
7459
7460 m_pPCS->Reset(m_pCmm->m_nSrcSpace);
7461
7462 pSrc = SrcPixel;
7463 pDst = m_Pixel;
7464
7465 if (n>1) {
7466 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
7467
7468 i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform()));
7469 pTmp = (icFloatNumber*)pSrc;
7470 pSrc = pDst;
7471 if (pTmp == SrcPixel)
7472 pDst = m_Pixel2;
7473 else
7474 pDst = pTmp;
7475 }
7476
7477 pLastXform = i->ptr->GetXform();
7478 i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, pLastXform));
7479 bNoClip = pLastXform->NoClipPCS();
7480 }
7481 else if (n==1) {
7482 i = m_Xforms->begin();
7483
7484 pLastXform = i->ptr->GetXform();
7485 i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, pLastXform));
7486 bNoClip = pLastXform->NoClipPCS();
7487 }
7488 else {
7489 bNoClip = true;
7490 }
7491
7492 m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace, bNoClip);
7493
7494 return icCmmStatOk;
7495}
7496
7497/**
7498**************************************************************************
7499* Name: CIccApplyCmm::Apply
7500*
7501* Purpose:
7502* Does the actual application of the Xforms in the list.
7503*
7504* Args:
7505* DstPixel = Destination pixel where the result is stored,
7506* SrcPixel = Source pixel which is to be applied.
7507**************************************************************************
7508*/
7509icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
7510{
7511 icFloatNumber *pDst, *pTmp;
7512 const icFloatNumber *pSrc;
7513 CIccApplyXformList::iterator i;
7514 int j, n = (int)m_Xforms->size();
7515 icUInt32Number k;
7516
7517 if (!n)
7518 return icCmmStatBadXform;
7519
7520 if (!m_Pixel && !InitPixel()) {
7521 return icCmmStatAllocErr;
7522 }
7523
7524 for (k=0; k<nPixels; k++) {
7525 m_pPCS->Reset(m_pCmm->m_nSrcSpace);
7526
7527 pSrc = SrcPixel;
7528 pDst = m_Pixel;
7529
7530 if (n>1) {
7531 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
7532
7533 i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform()));
7534 pTmp = (icFloatNumber*)pSrc;
7535 pSrc = pDst;
7536 if (pTmp==SrcPixel)
7537 pDst = m_Pixel2;
7538 else
7539 pDst = pTmp;
7540 }
7541
7542 i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, i->ptr->GetXform()));
7543 }
7544 else if (n==1) {
7545 i = m_Xforms->begin();
7546 i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, i->ptr->GetXform()));
7547 }
7548
7549 m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace);
7550
7551 DstPixel += m_pCmm->GetDestSamples();
7552 SrcPixel += m_pCmm->GetSourceSamples();
7553 }
7554
7555 return icCmmStatOk;
7556}
7557
7558void CIccApplyCmm::AppendApplyXform(CIccApplyXform *pApplyXform)
7559{
7560 CIccApplyXformPtr ptr;
7561 ptr.ptr = pApplyXform;
7562
7563 m_Xforms->push_back(ptr);
7564}
7565
7566/**
7567 **************************************************************************
7568 * Name: CIccCmm::CIccCmm
7569 *
7570 * Purpose:
7571 * Constructor
7572 *
7573 * Args:
7574 * nSrcSpace = signature of the source color space,
7575 * nDestSpace = signature of the destination color space,
7576 * bFirstInput = true if the first profile added is an input profile
7577 **************************************************************************
7578 */
7579CIccCmm::CIccCmm(icColorSpaceSignature nSrcSpace /*=icSigUnknownData*/,
7580 icColorSpaceSignature nDestSpace /*=icSigUnknownData*/,
7581 bool bFirstInput /*=true*/)
7582{
7583 m_bValid = false;
7584
7585 m_bLastInput = !bFirstInput;
7586 m_nSrcSpace = nSrcSpace;
7587 m_nDestSpace = nDestSpace;
7588
7589 m_nLastSpace = nSrcSpace;
7590 m_nLastIntent = icUnknownIntent((icRenderingIntent) 0x3f3f3f3f);
7591
7592 m_Xforms = new CIccXformList;
7593 m_Xforms->clear();
7594
7595 m_pApply = NULL__null;
7596}
7597
7598/**
7599 **************************************************************************
7600 * Name: CIccCmm::~CIccCmm
7601 *
7602 * Purpose:
7603 * Destructor
7604 **************************************************************************
7605 */
7606CIccCmm::~CIccCmm()
7607{
7608 if (m_Xforms) {
7609 CIccXformList::iterator i;
7610
7611 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
7612 if (i->ptr)
7613 delete i->ptr;
7614 }
7615
7616 delete m_Xforms;
7617 }
7618
7619 if (m_pApply)
7620 delete m_pApply;
7621}
7622
7623const icChar* CIccCmm::GetStatusText(icStatusCMM stat)
7624{
7625 switch (stat) {
7626 case icCmmStatBad:
7627 return "Bad CMM";
7628 case icCmmStatOk:
7629 return "OK";
7630 case icCmmStatCantOpenProfile:
7631 return "Cannot open profile";
7632 case icCmmStatBadSpaceLink:
7633 return "Invalid space link";
7634 case icCmmStatInvalidProfile:
7635 return "Invalid profile";
7636 case icCmmStatBadXform:
7637 return "Invalid profile transform";
7638 case icCmmStatInvalidLut:
7639 return "Invalid Look-Up Table";
7640 case icCmmStatProfileMissingTag:
7641 return "Missing tag in profile";
7642 case icCmmStatColorNotFound:
7643 return "Color not found";
7644 case icCmmStatIncorrectApply:
7645 return "Incorrect Apply object";
7646 case icCmmStatBadColorEncoding:
7647 return "Invalid color encoding used";
7648 case icCmmStatAllocErr:
7649 return "Memory allocation error";
7650 case icCmmStatBadLutType:
7651 return "Invalid Look-Up Table type";
7652 case icCmmStatIdentityXform:
7653 return "Identity transform used";
7654 case icCmmStatUnsupportedPcsLink:
7655 return "Unsupported PCS Link used";
7656 case icCmmStatBadConnection:
7657 return "Invalid profile connection";
7658 case icCmmStatBadTintXform:
7659 return "Invalid tint transform";
7660 case icCmmStatTooManySamples:
7661 return "Too many samples used";
7662 case icCmmStatBadMCSLink:
7663 return "Invalid MCS link connection";
7664 default:
7665 return "Unknown CMM Status value";
7666
7667 }
7668}
7669
7670/**
7671 **************************************************************************
7672 * Name: CIccCmm::AddXform
7673 *
7674 * Purpose:
7675 * Adds a profile at the end of the Xform list
7676 *
7677 * Args:
7678 * szProfilePath = file name of the profile to be added,
7679 * nIntent = rendering intent to be used with the profile,
7680 * nInterp = type of interpolation to be used with the profile,
7681 * nLutType = selection of which transform lut to use
7682 * pHintManager = hints for creating the xform
7683 *
7684 * Return:
7685 * icCmmStatOk, if the profile was added to the list succesfully
7686 **************************************************************************
7687 */
7688icStatusCMM CIccCmm::AddXform(const icChar *szProfilePath,
7689 icRenderingIntent nIntent /*=icUnknownIntent*/,
7690 icXformInterp nInterp /*icXformInterp*/,
7691 IIccProfileConnectionConditions *pPcc/*=NULL*/,
7692 icXformLutType nLutType /*=icXformLutColor*/,
7693 bool bUseD2BxB2DxTags /*=true*/,
7694 CIccCreateXformHintManager *pHintManager /*=NULL*/,
7695 bool bUseSubProfile /*=false*/)
7696{
7697 CIccProfile *pProfile = OpenIccProfile(szProfilePath, bUseSubProfile);
7698
7699 if (!pProfile)
7700 return icCmmStatCantOpenProfile;
7701
7702 icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
7703
7704 if (rv != icCmmStatOk)
7705 delete pProfile;
7706
7707 return rv;
7708}
7709
7710
7711/**
7712**************************************************************************
7713* Name: CIccCmm::AddXform
7714*
7715* Purpose:
7716* Adds a profile at the end of the Xform list
7717*
7718* Args:
7719* pProfileMem = ptr to profile loaded into memory. Note: this memory
7720* needs to be available until after the Begin() function is called.
7721* nProfileLen = size in bytes of profile loaded into memory
7722* nIntent = rendering intent to be used with the profile,
7723* nInterp = type of interpolation to be used with the profile,
7724* nLutType = selection of which transform lut to use
7725* bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
7726* pHintManager = hints for creating the xform
7727*
7728* Return:
7729* icCmmStatOk, if the profile was added to the list succesfully
7730**************************************************************************
7731*/
7732icStatusCMM CIccCmm::AddXform(icUInt8Number *pProfileMem,
7733 icUInt32Number nProfileLen,
7734 icRenderingIntent nIntent /*=icUnknownIntent*/,
7735 icXformInterp nInterp /*icXformInterp*/,
7736 IIccProfileConnectionConditions *pPcc/*=NULL*/,
7737 icXformLutType nLutType /*=icXformLutColor*/,
7738 bool bUseD2BxB2DxTags /*=true*/,
7739 CIccCreateXformHintManager *pHintManager /*=NULL*/,
7740 bool bUseSubProfile /*=false*/)
7741{
7742 CIccMemIO *pFile = new CIccMemIO;
7743
7744 if (!pFile || !pFile->Attach(pProfileMem, nProfileLen, bUseSubProfile))
7745 return icCmmStatCantOpenProfile;
7746
7747 CIccProfile *pProfile = new CIccProfile;
7748
7749 if (!pProfile)
7750 return icCmmStatCantOpenProfile;
7751
7752 if (!pProfile->Attach(pFile)) {
7753 delete pFile;
7754 delete pProfile;
7755 return icCmmStatCantOpenProfile;
7756 }
7757
7758 icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
7759
7760 if (rv != icCmmStatOk)
7761 delete pProfile;
7762
7763 return rv;
7764}
7765
7766
7767/**
7768 **************************************************************************
7769 * Name: CIccCmm::AddXform
7770 *
7771 * Purpose:
7772 * Adds a profile at the end of the Xform list
7773 *
7774 * Args:
7775 * pProfile = pointer to the CIccProfile object to be added,
7776 * nIntent = rendering intent to be used with the profile,
7777 * nInterp = type of interpolation to be used with the profile,
7778 * nLutType = selection of which transform lut to use
7779 * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
7780 * pHintManager = hints for creating the xform
7781 *
7782 * Return:
7783 * icCmmStatOk, if the profile was added to the list succesfully
7784 **************************************************************************
7785 */
7786icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile,
7787 icRenderingIntent nIntent /*=icUnknownIntent*/,
7788 icXformInterp nInterp /*=icInterpLinear*/,
7789 IIccProfileConnectionConditions *pPcc/*=NULL*/,
7790 icXformLutType nLutType /*=icXformLutColor*/,
7791 bool bUseD2BxB2DxTags /*=true*/,
7792 CIccCreateXformHintManager *pHintManager /*=NULL*/)
7793{
7794 icColorSpaceSignature nSrcSpace, nDstSpace;
7795 bool bInput = !m_bLastInput;
7796
7797 if (!pProfile)
7798 return icCmmStatInvalidProfile;
7799
7800 switch(pProfile->m_Header.deviceClass) {
7801 case icSigMaterialIdentificationClass:
7802 case icSigMaterialVisualizationClass:
7803 case icSigMaterialLinkClass:
7804 nIntent = icPerceptual;
7805 nLutType = icXformLutMCS;
7806
7807 default:
7808 break;
7809 }
7810
7811 switch (nLutType) {
7812 case icXformLutColor:
7813 case icXformLutColorimetric:
7814 case icXformLutSpectral:
7815 {
7816 //Check pProfile if nIntent and input can be found.
7817 if (bInput) {
7818 nSrcSpace = pProfile->m_Header.colorSpace;
7819
7820 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric))
7821 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
7822 else
7823 nDstSpace = pProfile->m_Header.pcs;
7824 }
7825 else {
7826 if (pProfile->m_Header.deviceClass == icSigLinkClass) {
7827 return icCmmStatBadSpaceLink;
7828 }
7829 if (pProfile->m_Header.deviceClass == icSigAbstractClass) {
7830 bInput = true;
7831 nIntent = icPerceptual; // Note: icPerceptualIntent = 0
7832 }
7833
7834 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric))
7835 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
7836 else
7837 nSrcSpace = pProfile->m_Header.pcs;
7838
7839 nDstSpace = pProfile->m_Header.colorSpace;
7840 }
7841 }
7842 break;
7843
7844 case icXformLutPreview:
7845 nSrcSpace = pProfile->m_Header.pcs;
7846 nDstSpace = pProfile->m_Header.pcs;
7847 bInput = false;
7848 break;
7849
7850 case icXformLutGamut:
7851 nSrcSpace = pProfile->m_Header.pcs;
7852 nDstSpace = icSigGamutData((icColorSpaceSignature) 0x67616D74);
7853 bInput = true;
7854 break;
7855
7856 case icXformLutBRDFParam:
7857 if (!bInput)
7858 return icCmmStatBadSpaceLink;
7859 nSrcSpace = pProfile->m_Header.colorSpace;
7860 nDstSpace = icSigBRDFParameters((icColorSpaceSignature) 0x62700000);
7861 bInput = true;
7862 break;
7863
7864 case icXformLutBRDFDirect:
7865 if (!bInput)
7866 return icCmmStatBadSpaceLink;
7867 nSrcSpace = icSigBRDFDirect((icColorSpaceSignature) 0x62640000);
7868 nDstSpace = pProfile->m_Header.pcs;
7869 bInput = true;
7870 break;
7871
7872 case icXformLutBRDFMcsParam:
7873 if (!bInput)
7874 return icCmmStatBadSpaceLink;
7875 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
7876 nDstSpace = icSigBRDFParameters((icColorSpaceSignature) 0x62700000);
7877 break;
7878
7879 case icXformLutMCS:
7880 if (bInput) {
7881 nSrcSpace = pProfile->m_Header.colorSpace;
7882 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
7883 }
7884 else {
7885 if (m_Xforms->size()) {
7886 CIccXformList::iterator prev = --(m_Xforms->end());
7887
7888 //Make sure previous profile connects with an icXformLutMCS
7889 if (prev->ptr->GetXformType()!=icXformLutMCS) {
7890 //check to see if we can convert previous xform to connect via an MCS
7891 if (!prev->ptr->GetProfile()->m_Header.mcs) {
7892 return icCmmStatBadMCSLink;
7893 }
7894
7895 CIccXform *pPrev = prev->ptr;
7896 CIccXform *pNew = CIccXform::Create(pPrev->GetProfilePtr(), pPrev->IsInput(), pPrev->GetIntent(), pPrev->GetInterp(),
7897 pPrev->GetConnectionConditions(), icXformLutMCS, bUseD2BxB2DxTags, pHintManager);
7898
7899 if (pNew) {
7900 pPrev->DetachAll();
7901 delete pPrev;
7902 }
7903
7904 prev->ptr = pNew;
7905
7906 }
7907 }
7908 else {
7909 return icCmmStatBadMCSLink;
7910 }
7911
7912 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
7913 if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) {
7914 if (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS) {
7915 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
7916 }
7917 else {
7918 nDstSpace = pProfile->m_Header.pcs;
7919 }
7920 }
7921 else if (pProfile->m_Header.deviceClass==icSigMaterialLinkClass) {
7922 nDstSpace = pProfile->m_Header.colorSpace;
7923 }
7924 else {
7925 return icCmmStatBadSpaceLink;
7926 }
7927 }
7928 break;
7929
7930 default:
7931 return icCmmStatBadLutType;
7932 }
7933
7934 //Make sure colorspaces match with previous xforms
7935 if (!m_Xforms->size()) {
7936 if (m_nSrcSpace == icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) {
7937 m_nLastSpace = nSrcSpace;
7938 m_nSrcSpace = nSrcSpace;
7939 }
7940 else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)((m_nSrcSpace)==(nSrcSpace) || ((((m_nSrcSpace)==icSigXYZData
|| (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace
)) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData
) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature
)(((icUInt32Number)m_nSrcSpace)&0xffff0000))==icSigSrcMCSChannelData
) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace
)&0xffff0000))==icSigSrcMCSChannelData)) )
) {
7941 return icCmmStatBadSpaceLink;
7942 }
7943 }
7944 else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)((m_nLastSpace)==(nSrcSpace) || ((((m_nLastSpace)==icSigXYZData
|| (m_nLastSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace
)) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData
) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature
)(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData
) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace
)&0xffff0000))==icSigSrcMCSChannelData)) )
) {
7945 return icCmmStatBadSpaceLink;
7946 }
7947
7948 if (nSrcSpace==icSigNamedData)
7949 return icCmmStatBadSpaceLink;
7950
7951 //Automatic creation of intent from header/last profile
7952 if (nIntent==icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) {
7953 if (bInput) {
7954 nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent;
7955 }
7956 else {
7957 nIntent = m_nLastIntent;
7958 }
7959 if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f))
7960 nIntent = icPerceptual;
7961 }
7962
7963 CIccXformPtr Xform;
7964
7965 Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
7966
7967 if (!Xform.ptr) {
7968 return icCmmStatBadXform;
7969 }
7970
7971 if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) {
7972 bInput = true;
7973 }
7974
7975 m_nLastSpace = nDstSpace;
7976 m_nLastIntent = nIntent;
7977 m_bLastInput = bInput;
7978
7979 m_Xforms->push_back(Xform);
7980
7981 return icCmmStatOk;
7982}
7983
7984/**
7985**************************************************************************
7986* Name: CIccCmm::AddXform
7987*
7988* Purpose:
7989* Adds a profile at the end of the Xform list
7990*
7991* Args:
7992* pProfile = pointer to the CIccProfile object to be added,
7993* nIntent = rendering intent to be used with the profile,
7994* nInterp = type of interpolation to be used with the profile,
7995* nLutType = selection of which transform lut to use
7996* bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
7997* pHintManager = hints for creating the xform
7998*
7999* Return:
8000* icCmmStatOk, if the profile was added to the list succesfully
8001**************************************************************************
8002*/
8003icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile,
8004 CIccTag *pXformTag,
8005 icRenderingIntent nIntent/*= icUnknownIntent*/,
8006 icXformInterp nInterp /*=icInterpLinear*/,
8007 IIccProfileConnectionConditions *pPcc/*=NULL*/,
8008 bool bUseSpectralPCS /*=false*/,
8009 CIccCreateXformHintManager *pHintManager /*=NULL*/)
8010{
8011 icColorSpaceSignature nSrcSpace, nDstSpace;
8012 bool bInput = !m_bLastInput;
8013
8014 if (!pProfile)
8015 return icCmmStatInvalidProfile;
8016
8017 switch (pProfile->m_Header.deviceClass) {
8018 case icSigMaterialIdentificationClass:
8019 case icSigMaterialVisualizationClass:
8020 case icSigMaterialLinkClass:
8021 return icCmmStatBadLutType;
8022
8023 default:
8024 break;
8025 }
8026
8027 //Check pProfile if nIntent and input can be found.
8028 if (bInput) {
8029 nSrcSpace = pProfile->m_Header.colorSpace;
8030
8031 if (bUseSpectralPCS && pProfile->m_Header.spectralPCS)
8032 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
8033 else {
8034 nDstSpace = pProfile->m_Header.pcs;
8035 bUseSpectralPCS = false;
8036 }
8037 }
8038 else {
8039 if (pProfile->m_Header.deviceClass == icSigLinkClass) {
8040 return icCmmStatBadSpaceLink;
8041 }
8042 if (pProfile->m_Header.deviceClass == icSigAbstractClass) {
8043 bInput = true;
8044 nIntent = icPerceptual; // Note: icPerceptualIntent = 0
8045 }
8046
8047 if (bUseSpectralPCS && pProfile->m_Header.spectralPCS)
8048 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
8049 else {
8050 nSrcSpace = pProfile->m_Header.pcs;
8051 bUseSpectralPCS = false;
8052 }
8053
8054 nDstSpace = pProfile->m_Header.colorSpace;
8055 }
8056
8057 //Make sure colorspaces match with previous xforms
8058 if (!m_Xforms->size()) {
8059 if (m_nSrcSpace == icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) {
8060 m_nLastSpace = nSrcSpace;
8061 m_nSrcSpace = nSrcSpace;
8062 }
8063 else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)((m_nSrcSpace)==(nSrcSpace) || ((((m_nSrcSpace)==icSigXYZData
|| (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace
)) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData
) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature
)(((icUInt32Number)m_nSrcSpace)&0xffff0000))==icSigSrcMCSChannelData
) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace
)&0xffff0000))==icSigSrcMCSChannelData)) )
) {
8064 return icCmmStatBadSpaceLink;
8065 }
8066 }
8067 else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)((m_nLastSpace)==(nSrcSpace) || ((((m_nLastSpace)==icSigXYZData
|| (m_nLastSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace
)) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData
) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature
)(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData
) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace
)&0xffff0000))==icSigSrcMCSChannelData)) )
) {
8068 return icCmmStatBadSpaceLink;
8069 }
8070
8071 if (nSrcSpace == icSigNamedData)
8072 return icCmmStatBadSpaceLink;
8073
8074 //Automatic creation of intent from header/last profile
8075 if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) {
8076 if (bInput) {
8077 nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent;
8078 }
8079 else {
8080 nIntent = m_nLastIntent;
8081 }
8082 if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f))
8083 nIntent = icPerceptual;
8084 }
8085
8086 CIccXformPtr Xform;
8087
8088 Xform.ptr = CIccXform::Create(pProfile, pXformTag, bInput, nIntent, nInterp, pPcc, bUseSpectralPCS, pHintManager);
8089
8090 if (!Xform.ptr) {
8091 return icCmmStatBadXform;
8092 }
8093
8094 m_nLastSpace = nDstSpace;
8095 m_nLastIntent = nIntent;
8096 m_bLastInput = bInput;
8097
8098 m_Xforms->push_back(Xform);
8099
8100 return icCmmStatOk;
8101}
8102
8103/**
8104 **************************************************************************
8105 * Name: CIccCmm::AddXform
8106 *
8107 * Purpose:
8108 * Adds a profile at the end of the Xform list
8109 *
8110 * Args:
8111 * Profile = reference a CIccProfile object that will be copies and added,
8112 * nIntent = rendering intent to be used with the profile,
8113 * nInterp = type of interpolation to be used with the profile,
8114 * nLutType = selection of which transform lut to use
8115 * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
8116 * pHintManager = hints for creating the xform
8117 *
8118 * Return:
8119 * icCmmStatOk, if the profile was added to the list succesfully
8120 **************************************************************************
8121 */
8122icStatusCMM CIccCmm::AddXform(CIccProfile &Profile,
8123 icRenderingIntent nIntent /*=icUnknownIntent*/,
8124 icXformInterp nInterp /*=icInterpLinear*/,
8125 IIccProfileConnectionConditions *pPcc/*=NULL*/,
8126 icXformLutType nLutType /*=icXformLutColor*/,
8127 bool bUseD2BxB2DxTags /*=true*/,
8128 CIccCreateXformHintManager *pHintManager /*=NULL*/)
8129{
8130 CIccProfile *pProfile = new CIccProfile(Profile);
8131
8132 if (!pProfile)
8133 return icCmmStatAllocErr;
8134
8135 icStatusCMM stat = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
8136
8137 if (stat != icCmmStatOk)
8138 delete pProfile;
8139
8140 return stat;
8141}
8142
8143icStatusCMM CIccCmm::CheckPCSConnections(bool bUsePCSConversions/*=false*/)
8144{
8145 icStatusCMM rv = icCmmStatOk;
8146
8147 CIccXformList::iterator last, next;
8148 CIccXformList xforms;
8149 CIccXformPtr ptr;
8150 bool bUsesPcsXforms = false;
8151
8152 next=m_Xforms->begin();
8153
8154 if (next!=m_Xforms->end()) {
8155 last = next;
8156 next++;
8157
8158 xforms.push_back(*last);
8159
8160 for (;next!=m_Xforms->end(); last=next, next++) {
8161 if ((last->ptr->IsInput() && last->ptr->IsMCS() && next->ptr->IsMCS()) ||
8162 (IsSpaceSpectralPCS(last->ptr->GetDstSpace()) || IsSpaceSpectralPCS(next->ptr->GetSrcSpace())) ||
8163 (!bUsePCSConversions &&
8164 (IsSpaceColorimetricPCS(last->ptr->GetDstSpace())((last->ptr->GetDstSpace())==icSigXYZData || (last->
ptr->GetDstSpace())==icSigLabData)
|| IsSpaceColorimetricPCS(next->ptr->GetSrcSpace())((next->ptr->GetSrcSpace())==icSigXYZData || (next->
ptr->GetSrcSpace())==icSigLabData)
))) {
8165 last->ptr->SetDstPCSConversion(false);
8166 next->ptr->SetSrcPCSConversion(false);
8167 CIccPcsXform *pPcs = new CIccPcsXform();
8168
8169 if (!pPcs) {
8170 return icCmmStatAllocErr;
8171 }
8172
8173 rv = pPcs->Connect(last->ptr, next->ptr);
8174
8175 if (rv!=icCmmStatOk && rv!=icCmmStatIdentityXform)
8176 return rv;
8177
8178 if (rv!=icCmmStatIdentityXform) {
8179 ptr.ptr = pPcs;
8180 xforms.push_back(ptr);
8181 }
8182 else {
8183 delete pPcs;
8184 }
8185
8186 bUsesPcsXforms = true;
8187 }
8188 xforms.push_back(*next);
8189 }
8190 }
8191
8192 if (bUsesPcsXforms) {
8193 *m_Xforms = xforms;
8194 }
8195
8196 return rv;
8197}
8198
8199/**
8200**************************************************************************
8201* Name: CIccCmm::SetLateBindingCC
8202*
8203* Purpose:
8204* Initializes the LateBinding Connection Conditions used by
8205* colorimetric based transforms
8206*
8207**************************************************************************
8208*/
8209void CIccCmm::SetLateBindingCC()
8210{
8211 CIccXformList::iterator i;
8212 CIccXform *pLastXform = NULL__null;
8213
8214 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
8215 if (i->ptr->IsInput()) {
8216 if (i->ptr->IsLateBinding()) {
8217 CIccXformList::iterator j=i;
8218 j++;
8219 if (j!=m_Xforms->end()) {
8220 if (j->ptr->IsLateBinding()) {
8221 i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8222 j->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8223 pLastXform = i->ptr;
8224 }
8225 else {
8226 i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8227 j->ptr->SetAppliedCC(j->ptr->GetConnectionConditions());
8228 pLastXform = NULL__null;
8229 }
8230 }
8231 else {
8232 i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8233 pLastXform = NULL__null;
8234 }
8235 }
8236 else if (IsSpaceSpectralPCS(i->ptr->GetDstSpace())) {
8237 CIccXformList::iterator j=i;
8238 j++;
8239 if (j!=m_Xforms->end()) {
8240 if (j->ptr->IsLateBinding()) {
8241 j->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8242 pLastXform = i->ptr;
8243 }
8244 else if (!j->ptr->IsAbstract()){
8245 j->ptr->SetAppliedCC(j->ptr->GetConnectionConditions());
8246 pLastXform = NULL__null;
8247 }
8248 }
8249 }
8250 else {
8251 pLastXform = NULL__null;
8252 }
8253 }
8254 else {
8255 if (!pLastXform)
8256 i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8257 else
8258 pLastXform = NULL__null;
8259 }
8260 }
8261}
8262
8263
8264/**
8265**************************************************************************
8266* Name: CIccCmm::Begin
8267*
8268* Purpose:
8269* Does the initialization of the Xforms before Apply() is called.
8270* Must be called before Apply().
8271*
8272**************************************************************************
8273*/
8274icStatusCMM CIccCmm::Begin(bool bAllocApplyCmm/*=true*/, bool bUsePCSConversions/*=false*/)
8275{
8276 if (m_pApply)
8277 return icCmmStatOk;
8278
8279 if (m_nDestSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) {
8280 m_nDestSpace = m_nLastSpace;
8281 }
8282 else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)((m_nDestSpace)==(m_nLastSpace) || ((((m_nDestSpace)==icSigXYZData
|| (m_nDestSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nDestSpace
)) && (((m_nLastSpace)==icSigXYZData || (m_nLastSpace
)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace))) || (((
(icColorSpaceSignature)(((icUInt32Number)m_nDestSpace)&0xffff0000
))==icSigSrcMCSChannelData) && (((icColorSpaceSignature
)(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData
)) )
) {
8283 return icCmmStatBadSpaceLink;
8284 }
8285
8286 if (m_nSrcSpace==icSigNamedData || m_nDestSpace==icSigNamedData) {
8287 return icCmmStatBadSpaceLink;
8288 }
8289
8290 SetLateBindingCC();
8291
8292 icStatusCMM rv;
8293 CIccXformList::iterator i;
8294
8295 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
8296
8297 rv = i->ptr->Begin();
8298
8299 if (rv!= icCmmStatOk)
8300 return rv;
8301 }
8302
8303 rv = CheckPCSConnections(bUsePCSConversions);
8304 if (rv != icCmmStatOk && rv!=icCmmStatIdentityXform)
8305 return rv;
8306
8307 if (bAllocApplyCmm) {
8308 m_pApply = GetNewApplyCmm(rv);
8309 }
8310 else
8311 rv = icCmmStatOk;
8312
8313 return rv;
8314}
8315
8316
8317/**
8318 **************************************************************************
8319 * Name: CIccCmm::GetNewApplyCmm
8320 *
8321 * Purpose:
8322 * Allocates an CIccApplyCmm object that does the initialization of the Xforms
8323 * that provides an Apply() function.
8324 * Multiple CIccApplyCmm objects can be allocated and used in separate threads.
8325 *
8326 **************************************************************************
8327 */
8328CIccApplyCmm *CIccCmm::GetNewApplyCmm(icStatusCMM &status)
8329{
8330 CIccApplyCmm *pApply = new CIccApplyCmm(this);
8331
8332 if (!pApply) {
8333 status = icCmmStatAllocErr;
8334 return NULL__null;
8335 }
8336
8337 CIccXformList::iterator i;
8338 CIccApplyXform *pXform;
8339
8340 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
8341 pXform = i->ptr->GetNewApply(status);
8342 if (!pXform || status != icCmmStatOk) {
8343 delete pApply;
8344 return NULL__null;
8345 }
8346 pApply->AppendApplyXform(pXform);
8347 }
8348
8349 m_bValid = true;
8350
8351 status = icCmmStatOk;
8352
8353 return pApply;
8354}
8355
8356
8357/**
8358**************************************************************************
8359* Name: CIccCmm::Apply
8360*
8361* Purpose:
8362* Uses the m_pApply object allocated during Begin to Apply the transformations
8363* associated with the CMM.
8364*
8365**************************************************************************
8366*/
8367icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
8368{
8369 return m_pApply->Apply(DstPixel, SrcPixel);
8370}
8371
8372
8373/**
8374**************************************************************************
8375* Name: CIccCmm::Apply
8376*
8377* Purpose:
8378* Uses the m_pApply object allocated during Begin to Apply the transformations
8379* associated with the CMM.
8380*
8381**************************************************************************
8382*/
8383icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
8384{
8385 return m_pApply->Apply(DstPixel, SrcPixel, nPixels);
8386}
8387
8388
8389/**
8390**************************************************************************
8391* Name: CIccCmm::RemoveAllIO()
8392*
8393* Purpose:
8394* Remove any attachments to CIccIO objects associated with the profiles
8395* related to the transforms attached to the CMM.
8396* Must be called after Begin().
8397*
8398* Return:
8399* icCmmStatOK - All IO objects removed
8400* icCmmStatBadXform - Begin() has not been performed.
8401**************************************************************************
8402*/
8403icStatusCMM CIccCmm::RemoveAllIO()
8404{
8405 if (!Valid())
8406 return icCmmStatBadXform;
8407
8408 CIccXformList::iterator i;
8409
8410 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
8411 i->ptr->RemoveIO();
8412 }
8413
8414 return icCmmStatOk;
8415}
8416
8417/**
8418 *************************************************************************
8419 ** Name: CIccCmm::IsInGamut
8420 **
8421 ** Purpose:
8422 ** Function to check if internal representation of gamut is in gamut. Note
8423 ** since gamut table is 8 bit and a color is considered to be in out of gamut
8424 ** if the value is not zero. Then we need to check where the 8 bit representation
8425 ** of the internal value is not zero.
8426 **
8427 ** Args:
8428 ** pInternal = internal pixel representation of gamut value
8429 **
8430 ** Return:
8431 ** true if in gamut, false if out of gamut
8432 **************************************************************************/
8433bool CIccCmm::IsInGamut(icFloatNumber *pInternal)
8434{
8435 if (!((unsigned int)((*pInternal)*255.0)))
8436 return true;
8437 return false;
8438}
8439
8440
8441/**
8442 **************************************************************************
8443 * Name: CIccCmm::ToInternalEncoding
8444 *
8445 * Purpose:
8446 * Functions for converting to Internal representation of pixel colors.
8447 *
8448 * Args:
8449 * nSpace = color space signature of the data,
8450 * nEncode = icFloatColorEncoding type of the data,
8451 * pInternal = converted data is stored here,
8452 * pData = the data to be converted
8453 * bClip = flag to clip to internal range
8454 **************************************************************************
8455 */
8456icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode,
8457 icFloatNumber *pInternal, const icFloatNumber *pData,
8458 bool bClip)
8459{
8460 int nSamples = icGetSpaceSamples(nSpace);
8461 if (!nSamples)
8462 return icCmmStatBadColorEncoding;
8463
8464
8465 icUInt16Number i;
8466 CIccPixelBuf pInput(nSamples);
8467
8468 if (!pInput.get())
8469 return icCmmStatAllocErr;
8470
8471 memcpy(pInput, pData, nSamples*sizeof(icFloatNumber));
8472 bool bCLRspace = icIsSpaceCLR(nSpace);
8473
8474 switch(icGetColorSpaceType(nSpace)((icColorSpaceSignature)(((icUInt32Number)nSpace)&0xffff0000
))
)
8475 {
8476 case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData):
8477 case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData):
8478 case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData):
8479 case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData):
8480 bCLRspace = true;
8481 break;
8482 }
8483
8484 switch(nSpace) {
8485
8486 case icSigLabData:
8487 {
8488 switch(nEncode) {
8489 case icEncodeValue:
8490 {
8491 icLabToPcs(pInput);
8492 break;
8493 }
8494 case icEncodeFloat:
8495 {
8496 break;
8497 }
8498 case icEncode8Bit:
8499 {
8500 pInput[0] = icU8toF((icUInt8Number)pInput[0])*100.0f;
8501 pInput[1] = icU8toAB((icUInt8Number)pInput[1]);
8502 pInput[2] = icU8toAB((icUInt8Number)pInput[2]);
8503
8504 icLabToPcs(pInput);
8505 break;
8506 }
8507 case icEncode16Bit:
8508 {
8509 pInput[0] = icU16toF((icUInt16Number)pInput[0]);
8510 pInput[1] = icU16toF((icUInt16Number)pInput[1]);
8511 pInput[2] = icU16toF((icUInt16Number)pInput[2]);
8512 break;
8513 }
8514 case icEncode16BitV2:
8515 {
8516 pInput[0] = icU16toF((icUInt16Number)pInput[0]);
8517 pInput[1] = icU16toF((icUInt16Number)pInput[1]);
8518 pInput[2] = icU16toF((icUInt16Number)pInput[2]);
8519
8520 CIccPCS::Lab2ToLab4(pInput, pInput);
8521 break;
8522 }
8523 default:
8524 return icCmmStatBadColorEncoding;
8525 break;
8526 }
8527 break;
8528 }
8529
8530 case icSigXYZData:
8531 {
8532 switch(nEncode) {
8533 case icEncodeValue:
8534 {
8535 pInput[0] = (icFloatNumber)pInput[0];
8536 pInput[1] = (icFloatNumber)pInput[1];
8537 pInput[2] = (icFloatNumber)pInput[2];
8538 icXyzToPcs(pInput);
8539 break;
8540 }
8541 case icEncodePercent:
8542 {
8543 pInput[0] = (icFloatNumber)(pInput[0] / 100.0);
8544 pInput[1] = (icFloatNumber)(pInput[1] / 100.0);
8545 pInput[2] = (icFloatNumber)(pInput[2] / 100.0);
8546 icXyzToPcs(pInput);
8547 break;
8548 }
8549 case icEncodeFloat:
8550 {
8551 icXyzToPcs(pInput);
8552 break;
8553 }
8554
8555 case icEncode16Bit:
8556 case icEncode16BitV2:
8557 {
8558 pInput[0] = icUSFtoD((icU1Fixed15Number)pInput[0]);
8559 pInput[1] = icUSFtoD((icU1Fixed15Number)pInput[1]);
8560 pInput[2] = icUSFtoD((icU1Fixed15Number)pInput[2]);
8561 break;
8562 }
8563
8564 default:
8565 return icCmmStatBadColorEncoding;
8566 break;
8567 }
8568 break;
8569 }
8570
8571 case icSigNamedData:
8572 return icCmmStatBadColorEncoding;
8573
8574 default:
8575 {
8576 switch(nEncode) {
8577 case icEncodeValue:
8578 {
8579 if (!bCLRspace || nSamples<3) {
8580 return icCmmStatBadColorEncoding;
8581 }
8582 if (nSamples==3)
8583 icLabToPcs(pInput);
8584 break;
8585 }
8586
8587 case icEncodePercent:
8588 {
8589 if (bClip) {
8590 for(i=0; i<nSamples; i++) {
8591 pInput[i] = (icFloatNumber)(pInput[i]/100.0);
8592 if (pInput[i] < 0.0) pInput[i] = 0.0;
8593 if (pInput[i] > 1.0) pInput[i] = 1.0;
8594 }
8595 }
8596 else {
8597 for(i=0; i<nSamples; i++) {
8598 pInput[i] = (icFloatNumber)(pInput[i]/100.0);
8599 }
8600 }
8601 break;
8602 }
8603
8604 case icEncodeFloat:
8605 {
8606 if (bClip) {
8607 for(i=0; i<nSamples; i++) {
8608 if (pInput[i] < 0.0) pInput[i] = 0.0;
8609 if (pInput[i] > 1.0) pInput[i] = 1.0;
8610 }
8611 }
8612 break;
8613 }
8614
8615 case icEncode8Bit:
8616 {
8617 for(i=0; i<nSamples; i++) {
8618 pInput[i] = icU8toF((icUInt8Number)pInput[i]);
8619 }
8620 break;
8621 }
8622
8623 case icEncode16Bit:
8624 case icEncode16BitV2:
8625 {
8626 for(i=0; i<nSamples; i++) {
8627 pInput[i] = icU16toF((icUInt16Number)pInput[i]);
8628 }
8629 break;
8630 }
8631
8632 default:
8633 return icCmmStatBadColorEncoding;
8634 break;
8635 }
8636 break;
8637 }
8638 }
8639
8640 memcpy(pInternal, pInput, nSamples*sizeof(icFloatNumber));
8641 return icCmmStatOk;
8642}
8643
8644
8645/**
8646**************************************************************************
8647* Name: CIccCmm::ToInternalEncoding
8648*
8649* Purpose:
8650* Functions for converting to Internal representation of 8 bit pixel colors.
8651*
8652* Args:
8653* nSpace = color space signature of the data,
8654* nEncode = icFloatColorEncoding type of the data,
8655* pInternal = converted data is stored here,
8656* pData = the data to be converted
8657* bClip = flag to clip to internal range
8658**************************************************************************
8659*/
8660icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal,
8661 const icUInt8Number *pData)
8662{
8663 switch(nSpace) {
8664 case icSigRgbData:
8665 {
8666 pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 255.0);
8667 pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 255.0);
8668 pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 255.0);
8669
8670 return icCmmStatOk;
8671 }
8672 case icSigCmykData:
8673 {
8674 pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 255.0);
8675 pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 255.0);
8676 pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 255.0);
8677 pInternal[3] = (icFloatNumber)((icFloatNumber)pData[3] / 255.0);
8678 return icCmmStatOk;
8679 }
8680 default:
8681 {
8682 icUInt32Number i;
8683 icUInt32Number nSamples = icGetSpaceSamples(nSpace);
8684 CIccPixelBuf FloatPixel(nSamples);
8685 if (!FloatPixel.get())
8686 return icCmmStatAllocErr;
8687
8688 for(i=0; i<nSamples; i++) {
8689 FloatPixel[i] = (icFloatNumber)pData[i];
8690 }
8691 return ToInternalEncoding(nSpace, icEncode8Bit, pInternal, FloatPixel);
8692 }
8693 }
8694
8695}
8696
8697
8698/**
8699**************************************************************************
8700* Name: CIccCmm::ToInternalEncoding
8701*
8702* Purpose:
8703* Functions for converting to Internal representation of 16 bit pixel colors.
8704*
8705* Args:
8706* nSpace = color space signature of the data,
8707* nEncode = icFloatColorEncoding type of the data,
8708* pInternal = converted data is stored here,
8709* pData = the data to be converted
8710* bClip = flag to clip to internal range
8711**************************************************************************
8712*/
8713icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal,
8714 const icUInt16Number *pData)
8715{
8716 switch(nSpace) {
8717 case icSigRgbData:
8718 {
8719 pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 65535.0);
8720 pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 65535.0);
8721 pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 65535.0);
8722
8723 return icCmmStatOk;
8724 }
8725 case icSigCmykData:
8726 {
8727 pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 65535.0);
8728 pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 65535.0);
8729 pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 65535.0);
8730 pInternal[3] = (icFloatNumber)((icFloatNumber)pData[3] / 65535.0);
8731 return icCmmStatOk;
8732 }
8733 default:
8734 {
8735 icUInt32Number i;
8736 icUInt32Number nSamples = icGetSpaceSamples(nSpace);
8737 CIccPixelBuf pFloatPixel(nSamples);
8738 if (!pFloatPixel.get())
8739 return icCmmStatAllocErr;
8740
8741 for(i=0; i<nSamples; i++) {
8742 pFloatPixel[i] = (icFloatNumber)pData[i];
8743 }
8744 return ToInternalEncoding(nSpace, icEncode16Bit, pInternal, pFloatPixel);
8745 }
8746 }
8747}
8748
8749
8750/**
8751 **************************************************************************
8752 * Name: CIccCmm::FromInternalEncoding
8753 *
8754 * Purpose:
8755 * Functions for converting from Internal representation of pixel colors.
8756 *
8757 * Args:
8758 * nSpace = color space signature of the data,
8759 * nEncode = icFloatColorEncoding type of the data,
8760 * pData = converted data is stored here,
8761 * pInternal = the data to be converted
8762 * bClip = flag to clip data to internal range
8763 **************************************************************************
8764 */
8765icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode,
8766 icFloatNumber *pData, const icFloatNumber *pInternal, bool bClip)
8767{
8768 int nSamples = icGetSpaceSamples(nSpace);
8769 if (!nSamples)
8770 return icCmmStatBadColorEncoding;
8771
8772 icUInt16Number i;
8773 CIccPixelBuf pInput(nSamples);
8774
8775 if (!pInput.get())
8776 return icCmmStatAllocErr;
8777
8778 memcpy(pInput, pInternal, nSamples*sizeof(icFloatNumber));
8779 bool bCLRspace = (icIsSpaceCLR(nSpace) || (nSpace == icSigDevLabData((icColorSpaceSignature) 0x644C6162)) || (nSpace==icSigDevXYZData((icColorSpaceSignature) 0x6458595A)));
8780
8781 switch(nSpace) {
8782
8783 case icSigLabData:
8784 {
8785 switch(nEncode) {
8786 case icEncodeValue:
8787 {
8788 icLabFromPcs(pInput);
8789 break;
8790 }
8791 case icEncodeUnitFloat:
8792 case icEncodeFloat:
8793 {
8794 break;
8795 }
8796 case icEncode8Bit:
8797 {
8798 icLabFromPcs(pInput);
8799
8800 pInput[0] = (icUInt8Number)(pInput[0]/100.0 * 255.0 + 0.5);
8801 pInput[1] = icABtoU8(pInput[1]);
8802 pInput[2] = icABtoU8(pInput[2]);
8803 break;
8804 }
8805 case icEncode16Bit:
8806 {
8807 pInput[0] = icFtoU16(pInput[0]);
8808 pInput[1] = icFtoU16(pInput[1]);
8809 pInput[2] = icFtoU16(pInput[2]);
8810 break;
8811 }
8812 case icEncode16BitV2:
8813 {
8814 CIccPCS::Lab4ToLab2(pInput, pInput);
8815
8816 pInput[0] = icFtoU16(pInput[0]);
8817 pInput[1] = icFtoU16(pInput[1]);
8818 pInput[2] = icFtoU16(pInput[2]);
8819 break;
8820 }
8821 default:
8822 return icCmmStatBadColorEncoding;
8823 break;
8824 }
8825 break;
8826 }
8827
8828 case icSigXYZData:
8829 {
8830 switch(nEncode) {
8831 case icEncodeValue:
8832 {
8833 icXyzFromPcs(pInput);
8834 break;
8835 }
8836 case icEncodePercent:
8837 {
8838 icXyzFromPcs(pInput);
8839 pInput[0] = (icFloatNumber)(pInput[0] * 100.0);
8840 pInput[1] = (icFloatNumber)(pInput[1] * 100.0);
8841 pInput[2] = (icFloatNumber)(pInput[2] * 100.0);
8842 break;
8843 }
8844 case icEncodeFloat:
8845 case icEncodeUnitFloat:
8846 {
8847 icXyzFromPcs(pInput);
8848 break;
8849 }
8850
8851 case icEncode16Bit:
8852 case icEncode16BitV2:
8853 {
8854 icXyzFromPcs(pInput);
8855 pInput[0] = icDtoUSF(pInput[0]);
8856 pInput[1] = icDtoUSF(pInput[1]);
8857 pInput[2] = icDtoUSF(pInput[2]);
8858 break;
8859 }
8860
8861 default:
8862 return icCmmStatBadColorEncoding;
8863 break;
8864 }
8865 break;
8866 }
8867
8868 case icSigNamedData:
8869 return icCmmStatBadColorEncoding;
8870
8871 default:
8872 {
8873 switch(nEncode) {
8874 case icEncodeValue:
8875 {
8876 if (nSpace == icSigDevXYZData((icColorSpaceSignature) 0x6458595A)) {
8877 icXyzFromPcs(pInput);
8878 }
8879 else if (bCLRspace && nSamples >=3) {
8880 icLabFromPcs(pInput);
8881 }
8882 break;
8883 }
8884 case icEncodePercent:
8885 {
8886 if (bClip) {
8887 for(i=0; i<nSamples; i++) {
8888 if (pInput[i] < 0.0) pInput[i] = 0.0;
8889 if (pInput[i] > 1.0) pInput[i] = 1.0;
8890 pInput[i] = (icFloatNumber)(pInput[i]*100.0);
8891 }
8892 }
8893 else {
8894 for(i=0; i<nSamples; i++) {
8895 pInput[i] = (icFloatNumber)(pInput[i]*100.0);
8896 }
8897 }
8898 break;
8899 }
8900
8901 case icEncodeFloat:
8902 break;
8903
8904 case icEncodeUnitFloat:
8905 {
8906 if (bClip) {
8907 for(i=0; i<nSamples; i++) {
8908 if (pInput[i] < 0.0) pInput[i] = 0.0;
8909 if (pInput[i] > 1.0) pInput[i] = 1.0;
8910 }
8911 }
8912 break;
8913 }
8914
8915 case icEncode8Bit:
8916 {
8917 for(i=0; i<nSamples; i++) {
8918 pInput[i] = icFtoU8(pInput[i]);
8919 }
8920 break;
8921 }
8922
8923 case icEncode16Bit:
8924 case icEncode16BitV2:
8925 {
8926 for(i=0; i<nSamples; i++) {
8927 pInput[i] = icFtoU16(pInput[i]);
8928 }
8929 break;
8930 }
8931
8932 default:
8933 return icCmmStatBadColorEncoding;
8934 break;
8935 }
8936 break;
8937 }
8938 }
8939
8940 memcpy(pData, pInput, nSamples*sizeof(icFloatNumber));
8941 return icCmmStatOk;
8942}
8943
8944
8945/**
8946**************************************************************************
8947* Name: CIccCmm::FromInternalEncoding
8948*
8949* Purpose:
8950* Functions for converting from Internal representation of 8 bit pixel colors.
8951*
8952* Args:
8953* nSpace = color space signature of the data,
8954* nEncode = icFloatColorEncoding type of the data,
8955* pData = converted data is stored here,
8956* pInternal = the data to be converted
8957* bClip = flag to clip data to internal range
8958**************************************************************************
8959*/
8960icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icUInt8Number *pData,
8961 const icFloatNumber *pInternal)
8962{
8963 switch(nSpace) {
8964 case icSigRgbData:
8965 {
8966 pData[0] = icFtoU8(pInternal[0]);
8967 pData[1] = icFtoU8(pInternal[1]);
8968 pData[2] = icFtoU8(pInternal[2]);
8969
8970 return icCmmStatOk;
8971 }
8972 case icSigCmykData:
8973 {
8974 pData[0] = icFtoU8(pInternal[0]);
8975 pData[1] = icFtoU8(pInternal[1]);
8976 pData[2] = icFtoU8(pInternal[2]);
8977 pData[3] = icFtoU8(pInternal[3]);
8978
8979 return icCmmStatOk;
8980 }
8981 default:
8982 {
8983 icUInt32Number i;
8984 icUInt32Number nSamples = icGetSpaceSamples(nSpace);
8985
8986 CIccPixelBuf pFloatPixel(nSamples);
8987 icStatusCMM convertStat;
8988
8989 if (!pFloatPixel.get())
8990 return icCmmStatAllocErr;
8991
8992 convertStat = FromInternalEncoding(nSpace, icEncode8Bit, pFloatPixel, pInternal);
8993 if (convertStat)
8994 return convertStat;
8995 for(i=0; i<nSamples; i++) {
8996 pData[i] = (icUInt8Number)(pFloatPixel[i] + 0.5);
8997 }
8998
8999 return icCmmStatOk;
9000 }
9001 }
9002}
9003
9004
9005/**
9006**************************************************************************
9007* Name: CIccCmm::FromInternalEncoding
9008*
9009* Purpose:
9010* Functions for converting from Internal representation of 16 bit pixel colors.
9011*
9012* Args:
9013* nSpace = color space signature of the data,
9014* nEncode = icFloatColorEncoding type of the data,
9015* pData = converted data is stored here,
9016* pInternal = the data to be converted
9017* bClip = flag to clip data to internal range
9018**************************************************************************
9019*/
9020icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icUInt16Number *pData,
9021 const icFloatNumber *pInternal)
9022{
9023 switch(nSpace) {
9024 case icSigRgbData:
9025 {
9026 pData[0] = icFtoU16(pInternal[0]);
9027 pData[1] = icFtoU16(pInternal[1]);
9028 pData[2] = icFtoU16(pInternal[2]);
9029
9030 return icCmmStatOk;
9031 }
9032 case icSigCmykData:
9033 {
9034 pData[0] = icFtoU16(pInternal[0]);
9035 pData[1] = icFtoU16(pInternal[1]);
9036 pData[2] = icFtoU16(pInternal[2]);
9037 pData[3] = icFtoU16(pInternal[3]);
9038
9039 return icCmmStatOk;
9040 }
9041 default:
9042 {
9043 icUInt32Number i;
9044 icUInt32Number nSamples = icGetSpaceSamples(nSpace);
9045 CIccPixelBuf pFloatPixel(nSamples);
9046 icStatusCMM convertStat;
9047
9048 if (!pFloatPixel.get())
9049 return icCmmStatAllocErr;
9050
9051 convertStat = FromInternalEncoding(nSpace, icEncode16Bit, pFloatPixel, pInternal);
9052 if (convertStat)
9053 return convertStat;
9054 for(i=0; i<nSamples; i++) {
9055 pData[i] = (icUInt16Number)(pFloatPixel[i] + 0.5);
9056 }
9057
9058 return icCmmStatOk;
9059 }
9060 }
9061}
9062
9063
9064/**
9065 **************************************************************************
9066 * Name: CIccCmm::GetFloatColorEncoding
9067 *
9068 * Purpose:
9069 * Converts the encoding type to characters for printing
9070 *
9071 * Args:
9072 * val = encoding type
9073 *
9074 * Return:
9075 * characters for printing
9076 **************************************************************************
9077 */
9078const icChar* CIccCmm::GetFloatColorEncoding(icFloatColorEncoding val)
9079{
9080 switch(val) {
9081
9082 case icEncodeValue:
9083 return "icEncodeValue";
9084
9085 case icEncodeFloat:
9086 return "icEncodeFloat";
9087
9088 case icEncodeUnitFloat:
9089 return "icEncodeUnitFloat";
9090
9091 case icEncodePercent:
9092 return "icEncodePercent";
9093
9094 case icEncode8Bit:
9095 return "icEncode8Bit";
9096
9097 case icEncode16Bit:
9098 return "icEncode16Bit";
9099
9100 case icEncode16BitV2:
9101 return "icEncode16BitV2";
9102
9103 default:
9104 return "icEncodeUnknown";
9105 }
9106}
9107
9108/**
9109 **************************************************************************
9110 * Name: CIccCmm::GetFloatColorEncoding
9111 *
9112 * Purpose:
9113 * Converts the string containing encoding type to icFloatColorEncoding
9114 *
9115 * Args:
9116 * val = string containing encoding type
9117 *
9118 * Return:
9119 * encoding type
9120 **************************************************************************
9121 */
9122icFloatColorEncoding CIccCmm::GetFloatColorEncoding(const icChar* val)
9123{
9124 if (!stricmpstrcasecmp(val, "icEncodePercent")) {
9125 return icEncodePercent;
9126 }
9127 else if (!stricmpstrcasecmp(val, "icEncodeUnitFloat")) {
9128 return icEncodeUnitFloat;
9129 }
9130 else if (!stricmpstrcasecmp(val, "icEncodeFloat")) {
9131 return icEncodeFloat;
9132 }
9133 else if (!stricmpstrcasecmp(val, "icEncode8Bit")) {
9134 return icEncode8Bit;
9135 }
9136 else if (!stricmpstrcasecmp(val, "icEncode16Bit")) {
9137 return icEncode16Bit;
9138 }
9139 else if (!stricmpstrcasecmp(val, "icEncode16BitV2")) {
9140 return icEncode16BitV2;
9141 }
9142 else if (!stricmpstrcasecmp(val, "icEncodeValue")) {
9143 return icEncodeValue;
9144 }
9145 else {
9146 return icEncodeUnknown;
9147 }
9148
9149}
9150
9151/**
9152 **************************************************************************
9153 * Name: CIccCmm::GetNumXforms
9154 *
9155 * Purpose:
9156 * Get number of xforms in the xform list
9157 *
9158 * Return:
9159 * number of m_Xforms
9160 **************************************************************************
9161 */
9162icUInt32Number CIccCmm::GetNumXforms() const
9163{
9164 return (icUInt32Number)m_Xforms->size();
9165}
9166
9167
9168/**
9169**************************************************************************
9170* Name: CIccCmm::GetFirstXformSource
9171*
9172* Purpose:
9173* Get source colorspace of first transform (similar to m_nSrcSpace with differences in dev colorimetric spaces)
9174*
9175* Return:
9176* colorspace
9177**************************************************************************
9178*/
9179icColorSpaceSignature CIccCmm::GetFirstXformSource()
9180{
9181 if (!m_Xforms->size())
9182 return m_nSrcSpace;
9183
9184 return m_Xforms->begin()->ptr->GetSrcSpace();
9185}
9186
9187/**
9188**************************************************************************
9189* Name: CIccCmm::GetNumXforms
9190*
9191* Purpose:
9192* Get source colorspace of last transform (similar to m_nSrcSpace with differences in dev colorimetric spaces)
9193*
9194* Return:
9195* colorspace
9196**************************************************************************
9197*/
9198icColorSpaceSignature CIccCmm::GetLastXformDest()
9199{
9200 if (!m_Xforms->size())
9201 return m_nDestSpace;
9202
9203 return m_Xforms->rbegin()->ptr->GetDstSpace();
9204}
9205
9206/**
9207**************************************************************************
9208* Name: CIccApplyCmm::CIccApplyCmm
9209*
9210* Purpose:
9211* Constructor
9212*
9213* Args:
9214* pCmm = ptr to CMM to apply against
9215**************************************************************************
9216*/
9217CIccApplyNamedColorCmm::CIccApplyNamedColorCmm(CIccNamedColorCmm *pCmm) : CIccApplyCmm(pCmm)
9218{
9219}
9220
9221
9222/**
9223**************************************************************************
9224* Name: CIccApplyCmm::CIccApplyCmm
9225*
9226* Purpose:
9227* Destructor
9228**************************************************************************
9229*/
9230CIccApplyNamedColorCmm::~CIccApplyNamedColorCmm()
9231{
9232}
9233
9234
9235/**
9236**************************************************************************
9237* Name: CIccApplyNamedColorCmm::Apply
9238*
9239* Purpose:
9240* Does the actual application of the Xforms in the list.
9241*
9242* Args:
9243* DstPixel = Destination pixel where the result is stored,
9244* SrcPixel = Source pixel which is to be applied.
9245**************************************************************************
9246*/
9247icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
9248{
9249 icFloatNumber *pDst, *pTmp;
9250 const icFloatNumber *pSrc;
9251 CIccApplyXformList::iterator i;
9252 int j, n = (int)m_Xforms->size();
9253 CIccApplyXform *pApply;
9254 const CIccXform *pApplyXform;
9255 CIccXformNamedColor *pXform;
9256
9257 if (!n)
9258 return icCmmStatBadXform;
9259
9260 if (!m_Pixel && !InitPixel()) {
9261 return icCmmStatAllocErr;
9262 }
9263
9264 icChar NamedColor[256];
9265 icStatusCMM rv;
9266
9267 m_pPCS->Reset(m_pCmm->GetSourceSpace());
9268
9269 pSrc = SrcPixel;
9270 pDst = m_Pixel;
9271
9272 if (n>1) {
9273 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
9274
9275 pApply = i->ptr;
9276 pApplyXform = pApply->GetXform();
9277 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9278 pXform = (CIccXformNamedColor*)pApplyXform;
9279
9280 switch(pXform->GetInterface()) {
9281 case icApplyPixel2Pixel:
9282 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9283 break;
9284
9285 case icApplyPixel2Named:
9286 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
9287 break;
9288
9289 case icApplyNamed2Pixel:
9290 if (j==0) {
9291 return icCmmStatIncorrectApply;
9292 }
9293
9294 rv = pXform->Apply(pApply, pDst, NamedColor);
9295
9296 if (rv) {
9297 return rv;
9298 }
9299 break;
9300
9301 default:
9302 break;
9303 }
9304 }
9305 else {
9306 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
9307 }
9308 pTmp = (icFloatNumber*)pSrc;
9309 pSrc = pDst;
9310 if (pTmp==SrcPixel)
9311 pDst = m_Pixel2;
9312 else
9313 pDst = pTmp;
9314 }
9315
9316 pApply = i->ptr;
9317 pApplyXform = pApply->GetXform();
9318 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9319 pXform = (CIccXformNamedColor*)pApplyXform;
9320
9321 switch(pXform->GetInterface()) {
9322 case icApplyPixel2Pixel:
9323 pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform));
9324 break;
9325
9326 case icApplyPixel2Named:
9327 default:
9328 return icCmmStatIncorrectApply;
9329 break;
9330
9331 case icApplyNamed2Pixel:
9332 rv = pXform->Apply(pApply, DstPixel, NamedColor);
9333 if (rv) {
9334 return rv;
9335 }
9336 break;
9337
9338 }
9339 }
9340 else {
9341 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9342 }
9343
9344 }
9345 else if (n==1) {
9346 i = m_Xforms->begin();
9347
9348 pApply = i->ptr;
9349 pApplyXform = pApply->GetXform();
9350 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9351 return icCmmStatIncorrectApply;
9352 }
9353
9354 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9355 }
9356
9357 m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace(), true);
9358
9359 return icCmmStatOk;
9360}
9361
9362
9363/**
9364**************************************************************************
9365* Name: CIccApplyNamedColorCmm::Apply
9366*
9367* Purpose:
9368* Does the actual application of the Xforms in the list.
9369*
9370* Args:
9371* DstPixel = Destination pixel where the result is stored,
9372* SrcPixel = Source pixel which is to be applied.
9373**************************************************************************
9374*/
9375icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
9376{
9377 icFloatNumber *pDst;
9378 const icFloatNumber *pSrc;
9379 CIccApplyXformList::iterator i;
9380 int j, n = (int)m_Xforms->size();
9381 CIccApplyXform *pApply;
9382 const CIccXform *pApplyXform;
9383 CIccXformNamedColor *pXform;
9384 icUInt32Number k;
9385
9386 if (!n)
9387 return icCmmStatBadXform;
9388
9389 if (!m_Pixel && !InitPixel()) {
9390 return icCmmStatAllocErr;
9391 }
9392
9393 icChar NamedColor[255];
9394 icStatusCMM rv;
9395
9396 for (k=0; k<nPixels; k++) {
9397 m_pPCS->Reset(m_pCmm->GetSourceSpace());
9398
9399 pSrc = SrcPixel;
9400 pDst = m_Pixel;
9401
9402 if (n>1) {
9403 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
9404
9405 pApply = i->ptr;
9406 pApplyXform = pApply->GetXform();
9407 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9408 pXform = (CIccXformNamedColor*)pApplyXform;
9409
9410 switch(pXform->GetInterface()) {
9411 case icApplyPixel2Pixel:
9412 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9413 break;
9414
9415 case icApplyPixel2Named:
9416 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
9417 break;
9418
9419 case icApplyNamed2Pixel:
9420 if (j==0) {
9421 return icCmmStatIncorrectApply;
9422 }
9423
9424 rv = pXform->Apply(pApply, pDst, NamedColor);
9425
9426 if (rv) {
9427 return rv;
9428 }
9429 break;
9430
9431 default:
9432 break;
9433 }
9434 }
9435 else {
9436 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
9437 }
9438 pSrc = pDst;
9439 }
9440
9441 pApply = i->ptr;
9442 pApplyXform = pApply->GetXform();
9443 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9444 pXform = (CIccXformNamedColor*)pApplyXform;
9445
9446 switch(pXform->GetInterface()) {
9447 case icApplyPixel2Pixel:
9448 pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform));
9449 break;
9450
9451 case icApplyPixel2Named:
9452 default:
9453 return icCmmStatIncorrectApply;
9454 break;
9455
9456 case icApplyNamed2Pixel:
9457 rv = pXform->Apply(pApply, DstPixel, NamedColor);
9458 if (rv) {
9459 return rv;
9460 }
9461 break;
9462
9463 }
9464 }
9465 else {
9466 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9467 }
9468
9469 }
9470 else if (n==1) {
9471 i = m_Xforms->begin();
9472
9473 pApply = i->ptr;
9474 pApplyXform = pApply->GetXform();
9475 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9476 return icCmmStatIncorrectApply;
9477 }
9478
9479 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9480 }
9481
9482 m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace());
9483
9484 SrcPixel += m_pCmm->GetSourceSamples();
9485 DstPixel += m_pCmm->GetDestSamples();
9486 }
9487
9488 return icCmmStatOk;
9489}
9490
9491
9492/**
9493**************************************************************************
9494* Name: CIccApplyNamedColorCmm::Apply
9495*
9496* Purpose:
9497* Does the actual application of the Xforms in the list.
9498*
9499* Args:
9500* DstColorName = Destination string where the result is stored,
9501* SrcPixel = Source pixel which is to be applied.
9502**************************************************************************
9503*/
9504icStatusCMM CIccApplyNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel)
9505{
9506 icFloatNumber *pDst, *pTmp;
9507 const icFloatNumber *pSrc;
9508 CIccApplyXformList::iterator i;
9509 int j, n = (int)m_Xforms->size();
9510 CIccApplyXform *pApply;
9511 const CIccXform *pApplyXform;
9512 CIccXformNamedColor *pXform;
9513
9514 if (!n)
9515 return icCmmStatBadXform;
9516
9517 if (!m_Pixel && !InitPixel()) {
9518 return icCmmStatAllocErr;
9519 }
9520
9521 icChar NamedColor[256];
9522 icStatusCMM rv;
9523
9524 m_pPCS->Reset(m_pCmm->GetSourceSpace());
9525
9526 pSrc = SrcPixel;
9527 pDst = m_Pixel;
9528
9529 if (n>1) {
9530 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
9531
9532 pApply = i->ptr;
9533 pApplyXform = pApply->GetXform();
9534 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9535 pXform = (CIccXformNamedColor*)pApplyXform;
9536 switch(pXform->GetInterface()) {
9537 case icApplyPixel2Pixel:
9538 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9539 break;
9540
9541 case icApplyPixel2Named:
9542 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
9543 break;
9544
9545 case icApplyNamed2Pixel:
9546 if (j==0) {
9547 return icCmmStatIncorrectApply;
9548 }
9549 rv = pXform->Apply(pApply, pDst, NamedColor);
9550 if (rv) {
9551 return rv;
9552 }
9553 break;
9554
9555 default:
9556 break;
9557 }
9558 }
9559 else {
9560 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
9561 }
9562 pTmp = (icFloatNumber*)pSrc;
9563 pSrc = pDst;
9564 if (pTmp==SrcPixel)
9565 pDst = m_Pixel2;
9566 else
9567 pDst = pTmp;
9568 }
9569
9570 pApply = i->ptr;
9571 pApplyXform = pApply->GetXform();
9572 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9573 pXform = (CIccXformNamedColor*)pApplyXform;
9574 switch(pXform->GetInterface()) {
9575
9576 case icApplyPixel2Named:
9577 pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform));
9578 break;
9579
9580 case icApplyPixel2Pixel:
9581 case icApplyNamed2Pixel:
9582 default:
9583 return icCmmStatIncorrectApply;
9584 break;
9585 }
9586 }
9587 else {
9588 return icCmmStatIncorrectApply;
9589 }
9590
9591 }
9592 else if (n==1) {
9593 i = m_Xforms->begin();
9594 pApply = i->ptr;
9595 pApplyXform = pApply->GetXform();
9596 if (pApplyXform->GetXformType()!=icXformTypeNamedColor) {
9597 return icCmmStatIncorrectApply;
9598 }
9599
9600 pXform = (CIccXformNamedColor*)pApplyXform;
9601 pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform));
9602 }
9603
9604 return icCmmStatOk;
9605}
9606
9607
9608/**
9609**************************************************************************
9610* Name: CIccApplyNamedColorCmm::Apply
9611*
9612* Purpose:
9613* Does the actual application of the Xforms in the list.
9614*
9615* Args:
9616* DstPixel = Destination pixel where the result is stored,
9617* SrcColorName = Source color name which is to be searched.
9618**************************************************************************
9619*/
9620icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/)
9621{
9622 icFloatNumber *pDst, *pTmp;
9623 const icFloatNumber *pSrc;
9624 CIccApplyXformList::iterator i;
9625 int j, n = (int)m_Xforms->size();
9626 CIccApplyXform *pApply;
9627 const CIccXform *pApplyXform;
9628 CIccXformNamedColor *pXform;
9629
9630 if (!n)
9631 return icCmmStatBadXform;
9632
9633 if (!m_Pixel && !InitPixel()) {
9634 return icCmmStatAllocErr;
9635 }
9636
9637 icChar NamedColor[255];
9638 icStatusCMM rv;
9639
9640 i=m_Xforms->begin();
9641 pApply = i->ptr;
9642 pApplyXform = pApply->GetXform();
9643 if (pApplyXform->GetXformType()!=icXformTypeNamedColor)
9644 return icCmmStatIncorrectApply;
9645
9646 pXform = (CIccXformNamedColor*)pApplyXform;
9647 m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS());
9648
9649 pDst = m_Pixel;
9650
9651 if (n>1) {
9652 rv = pXform->Apply(pApply, pDst, SrcColorName, tint);
9653 if (rv) {
9654 return rv;
9655 }
9656
9657 pSrc = pDst;
9658 pDst = m_Pixel2;
9659
9660 for (j=0, i++; j<n-2 && i!=m_Xforms->end(); i++, j++) {
9661
9662 pApply = i->ptr;
9663 pApplyXform = pApply->GetXform();
9664 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9665 CIccXformNamedColor *pXform = (CIccXformNamedColor*)pApplyXform;
9666 switch(pXform->GetInterface()) {
9667 case icApplyPixel2Pixel:
9668 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9669 break;
9670
9671 case icApplyPixel2Named:
9672 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
9673 break;
9674
9675 case icApplyNamed2Pixel:
9676 rv = pXform->Apply(pApply, pDst, NamedColor);
9677 if (rv) {
9678 return rv;
9679 }
9680 break;
9681
9682 default:
9683 break;
9684 }
9685 }
9686 else {
9687 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
9688 }
9689 pTmp = (icFloatNumber*)pSrc;
9690 pSrc = pDst;
9691 pDst = pTmp;
9692 }
9693
9694 pApply = i->ptr;
9695 pApplyXform = pApply->GetXform();
9696 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9697 pXform = (CIccXformNamedColor*)pApplyXform;
9698 switch(pXform->GetInterface()) {
9699 case icApplyPixel2Pixel:
9700 pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform));
9701 break;
9702
9703 case icApplyPixel2Named:
9704 default:
9705 return icCmmStatIncorrectApply;
9706 break;
9707
9708 case icApplyNamed2Pixel:
9709 rv = pXform->Apply(pApply, DstPixel, NamedColor);
9710 if (rv) {
9711 return rv;
9712 }
9713 break;
9714
9715 }
9716 }
9717 else {
9718 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9719 }
9720
9721 }
9722 else if (n==1) {
9723 rv = pXform->Apply(pApply, DstPixel, SrcColorName, tint);
9724 if (rv) {
9725 return rv;
9726 }
9727 m_pPCS->Check(DstPixel, pXform);
9728 }
9729
9730 m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace());
9731
9732 return icCmmStatOk;
9733}
9734
9735/**
9736**************************************************************************
9737* Name: CIccApplyNamedColorCmm::Apply
9738*
9739* Purpose:
9740* Does the actual application of the Xforms in the list.
9741*
9742* Args:
9743* DstColorName = Destination string where the result is stored,
9744* SrcColorName = Source color name which is to be searched.
9745**************************************************************************
9746*/
9747icStatusCMM CIccApplyNamedColorCmm::Apply(icChar *DstColorName, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/)
9748{
9749 icFloatNumber *pDst, *pTmp;
9750 const icFloatNumber *pSrc;
9751 CIccApplyXformList::iterator i;
9752 int j, n = (int)m_Xforms->size();
9753 icChar NamedColor[256];
9754 icStatusCMM rv;
9755 CIccApplyXform *pApply;
9756 const CIccXform *pApplyXform;
9757 CIccXformNamedColor *pXform;
9758
9759 if (!n)
9760 return icCmmStatBadXform;
9761
9762 if (!m_Pixel && !InitPixel()) {
9763 return icCmmStatAllocErr;
9764 }
9765
9766 i=m_Xforms->begin();
9767
9768 pApply = i->ptr;
9769 pApplyXform = pApply->GetXform();
9770 if (pApplyXform->GetXformType()!=icXformTypeNamedColor)
9771 return icCmmStatIncorrectApply;
9772
9773 pXform = (CIccXformNamedColor*)pApplyXform;
9774
9775 m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS());
9776
9777 pDst = m_Pixel;
9778
9779 if (n>1) {
9780 rv = pXform->Apply(pApply, pDst, SrcColorName, tint);
9781
9782 if (rv) {
9783 return rv;
9784 }
9785
9786 pSrc = pDst;
9787 pDst = m_Pixel2;
9788
9789 for (j=0, i++; j<n-2 && i!=m_Xforms->end(); i++, j++) {
9790
9791 pApply = i->ptr;
9792 pApplyXform = pApply->GetXform();
9793 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9794 pXform = (CIccXformNamedColor*)pApplyXform;
9795 switch(pXform->GetInterface()) {
9796 case icApplyPixel2Pixel:
9797 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9798 break;
9799
9800
9801 case icApplyPixel2Named:
9802 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
9803 break;
9804
9805 case icApplyNamed2Pixel:
9806 rv = pXform->Apply(pApply, pDst, NamedColor);
9807 if (rv) {
9808 return rv;
9809 }
9810 break;
9811
9812 default:
9813 break;
9814 }
9815 }
9816 else {
9817 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9818 }
9819 pTmp = (icFloatNumber*)pSrc;
9820 pSrc = pDst;
9821 pDst = pTmp;
9822 }
9823
9824 pApply = i->ptr;
9825 pApplyXform = pApply->GetXform();
9826 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9827 pXform = (CIccXformNamedColor*)pApplyXform;
9828 switch(pXform->GetInterface()) {
9829 case icApplyPixel2Named:
9830 pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform));
9831 break;
9832
9833 case icApplyPixel2Pixel:
9834 case icApplyNamed2Pixel:
9835 default:
9836 return icCmmStatIncorrectApply;
9837 break;
9838 }
9839 }
9840 else {
9841 return icCmmStatIncorrectApply;
9842 }
9843
9844 }
9845 else if (n==1) {
9846 return icCmmStatIncorrectApply;
9847 }
9848
9849 return icCmmStatOk;
9850}
9851
9852/**
9853 **************************************************************************
9854 * Name: CIccNamedColorCmm::CIccNamedColorCmm
9855 *
9856 * Purpose:
9857 * Constructor
9858 *
9859 * Args:
9860 * nSrcSpace = signature of the source color space,
9861 * nDestSpace = signature of the destination color space,
9862 * bFirstInput = true if the first profile added is an input profile
9863 **************************************************************************
9864 */
9865CIccNamedColorCmm::CIccNamedColorCmm(icColorSpaceSignature nSrcSpace, icColorSpaceSignature nDestSpace,
9866 bool bFirstInput) : CIccCmm(nSrcSpace, nDestSpace, bFirstInput)
9867{
9868 m_nApplyInterface = icApplyPixel2Pixel;
9869}
9870
9871/**
9872 **************************************************************************
9873 * Name: CIccNamedColorCmm::~CIccNamedColorCmm
9874 *
9875 * Purpose:
9876 * Destructor
9877 **************************************************************************
9878 */
9879CIccNamedColorCmm::~CIccNamedColorCmm()
9880{
9881}
9882
9883
9884/**
9885 **************************************************************************
9886 * Name: CIccNamedColorCmm::AddXform
9887 *
9888 * Purpose:
9889 * Adds a profile at the end of the Xform list
9890 *
9891 * Args:
9892 * szProfilePath = file name of the profile to be added,
9893 * nIntent = rendering intent to be used with the profile,
9894 * nInterp = type of interpolation to be used with the profile
9895 * pHintManager = hints for creating the xform
9896 *
9897 * Return:
9898 * icCmmStatOk, if the profile was added to the list succesfully
9899 **************************************************************************
9900 */
9901icStatusCMM CIccNamedColorCmm::AddXform(const icChar *szProfilePath,
9902 icRenderingIntent nIntent /*=icUnknownIntent*/,
9903 icXformInterp nInterp /*icXformInterp*/,
9904 IIccProfileConnectionConditions *pPcc/*=NULL*/,
9905 icXformLutType nLutType /*=icXformLutColor*/,
9906 bool bUseD2BxB2DxTags /*=true*/,
9907 CIccCreateXformHintManager *pHintManager /*=NULL*/,
9908 bool bUseSubProfile /*=false*/)
9909{
9910 CIccProfile *pProfile = OpenIccProfile(szProfilePath, bUseSubProfile);
9911
9912 if (!pProfile)
9913 return icCmmStatCantOpenProfile;
9914
9915 icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
9916
9917 if (rv != icCmmStatOk)
9918 delete pProfile;
9919
9920 return rv;
9921}
9922
9923/**
9924 **************************************************************************
9925 * Name: CIccNamedColorCmm::AddXform
9926 *
9927 * Purpose:
9928 * Adds a profile at the end of the Xform list
9929 *
9930 * Args:
9931 * pProfile = pointer to the CIccProfile object to be added,
9932 * nIntent = rendering intent to be used with the profile,
9933 * nInterp = type of interpolation to be used with the profile
9934 * nLutType = type of lut to use from the profile
9935 * pHintManager = hints for creating the xform
9936 *
9937 * Return:
9938 * icCmmStatOk, if the profile was added to the list succesfully
9939 **************************************************************************
9940 */
9941icStatusCMM CIccNamedColorCmm::AddXform(CIccProfile *pProfile,
9942 icRenderingIntent nIntent /*=icUnknownIntent*/,
9943 icXformInterp nInterp /*=icInterpLinear*/,
9944 IIccProfileConnectionConditions *pPcc/*=NULL*/,
9945 icXformLutType nLutType /*=icXformLutColor*/,
9946 bool bUseD2BxB2DxTags /*=true*/,
9947 CIccCreateXformHintManager *pHintManager /*=NULL*/)
9948{
9949 icColorSpaceSignature nSrcSpace, nDstSpace;
9950 CIccXformPtr Xform;
9951 bool bInput = !m_bLastInput;
9952 icStatusCMM rv;
9953 icXformLutType nUseLutType = nLutType;
9954
9955 switch(pProfile->m_Header.deviceClass) {
9956 case icSigMaterialIdentificationClass:
9957 case icSigMaterialLinkClass:
9958 nIntent = icPerceptual;
9959 nLutType = icXformLutMCS;
9960 break;
9961
9962 case icSigMaterialVisualizationClass:
9963 nLutType = icXformLutMCS;
9964 break;
9965
9966 default:
9967 break;
9968 }
9969
9970 Xform.ptr = NULL__null;
9971 switch (nUseLutType) {
9972 //Automatically choose which one
9973 case icXformLutColor:
9974 case icXformLutColorimetric:
9975 case icXformLutSpectral:
9976 case icXformLutNamedColor:
9977 {
9978 CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag);
9979
9980 if (pTag && (pProfile->m_Header.deviceClass==icSigNamedColorClass || nLutType == icXformLutNamedColor)) {
9981 if (bInput) {
9982 nSrcSpace = icSigNamedData;
9983 }
9984 else if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) {
9985 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
9986 bUseD2BxB2DxTags = true;
9987 }
9988 else {
9989 nSrcSpace = pProfile->m_Header.pcs;
9990 }
9991
9992 if (!m_Xforms->size()) {
9993 if (m_nSrcSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) {
9994 m_nSrcSpace = nSrcSpace;
9995 }
9996 else {
9997 nSrcSpace = m_nSrcSpace;
9998 }
9999 }
10000 else {
10001 if (m_nLastSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) {
10002 m_nLastSpace = nSrcSpace;
10003 }
10004 else {
10005 nSrcSpace = m_nLastSpace;
10006 }
10007 }
10008
10009 if (nSrcSpace==icSigNamedData) {
10010 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) {
10011 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
10012 bUseD2BxB2DxTags = true;
10013 }
10014 else {
10015 nDstSpace = pProfile->m_Header.pcs;
10016 }
10017 bInput = true;
10018 }
10019 else {
10020 nDstSpace = icSigNamedData;
10021 bInput = false;
10022 }
10023
10024 Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, icXformLutNamedColor, bUseD2BxB2DxTags, pHintManager);
10025 if (!Xform.ptr) {
10026 return icCmmStatBadXform;
10027 }
10028 CIccXformNamedColor *pXform = (CIccXformNamedColor *)Xform.ptr;
10029 rv = pXform->SetSrcSpace(nSrcSpace);
10030 if (rv)
10031 return rv;
10032
10033 rv = pXform->SetDestSpace(nDstSpace);
10034 if (rv)
10035 return rv;
10036 }
10037 else {
10038 //It isn't named color so make we will use color lut.
10039 if (nUseLutType==icXformLutNamedColor)
10040 nUseLutType = icXformLutColor;
10041
10042 //Check pProfile if nIntent and input can be found.
10043 if (bInput) {
10044 nSrcSpace = pProfile->m_Header.colorSpace;
10045
10046 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) {
10047 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
10048 bUseD2BxB2DxTags = true;
10049 }
10050 else
10051 nDstSpace = pProfile->m_Header.pcs;
10052 }
10053 else {
10054 if (pProfile->m_Header.deviceClass == icSigLinkClass) {
10055 return icCmmStatBadSpaceLink;
10056 }
10057 if (pProfile->m_Header.deviceClass == icSigAbstractClass) {
10058 bInput = true;
10059 nIntent = icPerceptual; // Note: icPerceptualIntent = 0
10060 }
10061
10062 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) {
10063 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
10064 bUseD2BxB2DxTags = true;
10065 }
10066 else
10067 nSrcSpace = pProfile->m_Header.pcs;
10068
10069 nDstSpace = pProfile->m_Header.colorSpace;
10070 }
10071 }
10072 }
10073 break;
10074
10075 case icXformLutPreview:
10076 nSrcSpace = pProfile->m_Header.pcs;
10077 nDstSpace = pProfile->m_Header.pcs;
10078 bInput = false;
10079 break;
10080
10081 case icXformLutGamut:
10082 nSrcSpace = pProfile->m_Header.pcs;
10083 nDstSpace = icSigGamutData((icColorSpaceSignature) 0x67616D74);
10084 bInput = true;
10085 break;
10086
10087 case icXformLutBRDFParam:
10088 nSrcSpace = pProfile->m_Header.colorSpace;
10089 nDstSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f);
10090 break;
10091
10092 case icXformLutBRDFDirect:
10093 nSrcSpace = pProfile->m_Header.colorSpace;
10094 nDstSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f);
10095 break;
10096
10097 case icXformLutMCS:
10098 switch(pProfile->m_Header.deviceClass)
10099 {
10100 case icSigInputClass:
10101 case icSigMaterialIdentificationClass:
10102 nSrcSpace = pProfile->m_Header.colorSpace;
10103 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
10104 break;
10105 case icSigMaterialVisualizationClass:
10106 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
10107 if (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS) {
10108 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
10109 }
10110 else {
10111 nDstSpace = pProfile->m_Header.pcs;
10112 }
10113 bInput = true;
10114 break;
10115
10116 case icSigMaterialLinkClass:
10117 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
10118 nDstSpace = pProfile->m_Header.colorSpace;
10119 break;
10120
10121 default:
10122 return icCmmStatBadLutType;
10123 }
10124 break;
10125
10126 default:
10127 return icCmmStatBadLutType;
10128 }
10129
10130 //Make sure color spaces match with previous xforms
10131 if (!m_Xforms->size()) {
10132 if (m_nSrcSpace == icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) {
10133 m_nLastSpace = nSrcSpace;
10134 m_nSrcSpace = nSrcSpace;
10135 }
10136 else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)((m_nSrcSpace)==(nSrcSpace) || ((((m_nSrcSpace)==icSigXYZData
|| (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace
)) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData
) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature
)(((icUInt32Number)m_nSrcSpace)&0xffff0000))==icSigSrcMCSChannelData
) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace
)&0xffff0000))==icSigSrcMCSChannelData)) )
&& !IsNChannelCompat(m_nSrcSpace, nSrcSpace)(((((icColorSpaceSignature)(((icUInt32Number)m_nSrcSpace)&
0xffff0000))==icSigNChannelData) && (((icUInt32Number
)m_nSrcSpace)&0x0000ffff)==icGetSpaceSamples(nSrcSpace)) ||
((((icColorSpaceSignature)(((icUInt32Number)nSrcSpace)&0xffff0000
))==icSigNChannelData) && (((icUInt32Number)nSrcSpace
)&0x0000ffff)==icGetSpaceSamples(m_nSrcSpace)))
) {
10137 return icCmmStatBadSpaceLink;
10138 }
10139 }
10140 else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)((m_nLastSpace)==(nSrcSpace) || ((((m_nLastSpace)==icSigXYZData
|| (m_nLastSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace
)) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData
) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature
)(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData
) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace
)&0xffff0000))==icSigSrcMCSChannelData)) )
&& !IsNChannelCompat(m_nSrcSpace, nSrcSpace)(((((icColorSpaceSignature)(((icUInt32Number)m_nSrcSpace)&
0xffff0000))==icSigNChannelData) && (((icUInt32Number
)m_nSrcSpace)&0x0000ffff)==icGetSpaceSamples(nSrcSpace)) ||
((((icColorSpaceSignature)(((icUInt32Number)nSrcSpace)&0xffff0000
))==icSigNChannelData) && (((icUInt32Number)nSrcSpace
)&0x0000ffff)==icGetSpaceSamples(m_nSrcSpace)))
) {
10141 return icCmmStatBadSpaceLink;
10142 }
10143
10144 //Automatic creation of intent from header/last profile
10145 if (nIntent==icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) {
10146 if (bInput) {
10147 nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent;
10148 }
10149 else {
10150 nIntent = m_nLastIntent;
10151 }
10152 if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f))
10153 nIntent = icPerceptual;
10154 }
10155
10156 if (!Xform.ptr)
10157 Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, nUseLutType, bUseD2BxB2DxTags, pHintManager);
10158
10159 if (!Xform.ptr) {
10160 return icCmmStatBadXform;
10161 }
10162
10163 m_nLastSpace = Xform.ptr->GetDstSpace();
10164 m_nLastIntent = nIntent;
10165
10166 if (pProfile->m_Header.deviceClass == icSigLinkClass)
10167 bInput = false;
10168 m_bLastInput = bInput;
10169
10170 m_Xforms->push_back(Xform);
10171
10172 return icCmmStatOk;
10173}
10174
10175/**
10176 **************************************************************************
10177 * Name: CIccNamedColorCmm::Begin
10178 *
10179 * Purpose:
10180 * Does the initialization of the Xforms in the list before Apply() is called.
10181 * Must be called before Apply().
10182 *
10183 **************************************************************************
10184 */
10185 icStatusCMM CIccNamedColorCmm::Begin(bool bAllocNewApply/* =true */, bool bUsePcsConversion/*=false*/)
10186{
10187 if (m_nDestSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) {
10188 m_nDestSpace = m_nLastSpace;
10189 }
10190 else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)((m_nDestSpace)==(m_nLastSpace) || ((((m_nDestSpace)==icSigXYZData
|| (m_nDestSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nDestSpace
)) && (((m_nLastSpace)==icSigXYZData || (m_nLastSpace
)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace))) || (((
(icColorSpaceSignature)(((icUInt32Number)m_nDestSpace)&0xffff0000
))==icSigSrcMCSChannelData) && (((icColorSpaceSignature
)(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData
)) )
) {
10191 return icCmmStatBadSpaceLink;
10192 }
10193
10194 if (m_nSrcSpace != icSigNamedData) {
10195 if (m_nDestSpace != icSigNamedData) {
10196 m_nApplyInterface = icApplyPixel2Pixel;
10197 }
10198 else {
10199 m_nApplyInterface = icApplyPixel2Named;
10200 }
10201 }
10202 else {
10203 if (m_nDestSpace != icSigNamedData) {
10204 m_nApplyInterface = icApplyNamed2Pixel;
10205 }
10206 else {
10207 m_nApplyInterface = icApplyNamed2Named;
10208 }
10209 }
10210
10211 SetLateBindingCC();
10212
10213 icStatusCMM rv;
10214 CIccXformList::iterator i;
10215
10216 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
10217 rv = i->ptr->Begin();
10218
10219 if (rv!= icCmmStatOk) {
10220 return rv;
10221 }
10222 }
10223
10224 rv = CheckPCSConnections(bUsePcsConversion);
10225 if (rv != icCmmStatOk && rv!=icCmmStatIdentityXform)
10226 return rv;
10227
10228 if (bAllocNewApply) {
10229 rv = icCmmStatOk;
10230
10231 m_pApply = GetNewApplyCmm(rv);
10232 }
10233 else
10234 rv = icCmmStatOk;
10235
10236 return rv;
10237}
10238
10239 /**
10240 **************************************************************************
10241 * Name: CIccNamedColorCmm::GetNewApplyCmm
10242 *
10243 * Purpose:
10244 * Allocates a CIccApplyCmm object that allows one to call apply from
10245 * multiple threads.
10246 *
10247 **************************************************************************
10248 */
10249 CIccApplyCmm *CIccNamedColorCmm::GetNewApplyCmm(icStatusCMM &status)
10250 {
10251 CIccApplyCmm *pApply = new CIccApplyNamedColorCmm(this);
10252
10253 CIccXformList::iterator i;
10254
10255 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
10256 CIccApplyXform *pXform = i->ptr->GetNewApply(status);
10257 if (status != icCmmStatOk || !pXform) {
10258 delete pApply;
10259 return NULL__null;
10260 }
10261 pApply->AppendApplyXform(pXform);
10262 }
10263
10264 m_bValid = true;
10265
10266 status = icCmmStatOk;
10267 return pApply;
10268}
10269
10270
10271 /**
10272 **************************************************************************
10273 * Name: CIccApplyNamedColorCmm::Apply
10274 *
10275 * Purpose:
10276 * Does the actual application of the Xforms in the list.
10277 *
10278 * Args:
10279 * DstColorName = Destination string where the result is stored,
10280 * SrcPoxel = Source pixel
10281 **************************************************************************
10282 */
10283icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel)
10284{
10285 return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcPixel);
10286}
10287
10288
10289/**
10290**************************************************************************
10291* Name: CIccApplyNamedColorCmm::Apply
10292*
10293* Purpose:
10294* Does the actual application of the Xforms in the list.
10295*
10296* Args:
10297* DestPixel = Destination pixel where the result is stored,
10298* SrcColorName = Source color name which is to be searched.
10299**************************************************************************
10300*/
10301icStatusCMM CIccNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/)
10302{
10303 return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstPixel, SrcColorName, tint);
10304}
10305
10306
10307/**
10308**************************************************************************
10309* Name: CIccApplyNamedColorCmm::Apply
10310*
10311* Purpose:
10312* Does the actual application of the Xforms in the list.
10313*
10314* Args:
10315* DstColorName = Destination string where the result is stored,
10316* SrcColorName = Source color name which is to be searched.
10317**************************************************************************
10318*/
10319icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/)
10320{
10321 return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcColorName, tint);
10322}
10323
10324
10325/**
10326 **************************************************************************
10327 * Name: CIccNamedColorCmm::SetLastXformDest
10328 *
10329 * Purpose:
10330 * Sets the destination Color space of the last Xform in the list
10331 *
10332 * Args:
10333 * nDestSpace = signature of the color space to be set
10334 **************************************************************************
10335 */
10336icStatusCMM CIccNamedColorCmm::SetLastXformDest(icColorSpaceSignature nDestSpace)
10337{
10338 int n = (int)m_Xforms->size();
10339 CIccXformPtr *pLastXform;
10340
10341 if (!n)
10342 return icCmmStatBadXform;
10343
10344 pLastXform = &m_Xforms->back();
10345
10346 if (pLastXform->ptr->GetXformType()==icXformTypeNamedColor) {
10347 CIccXformNamedColor *pXform = (CIccXformNamedColor *)pLastXform->ptr;
10348 if (pXform->GetSrcSpace() == icSigNamedData &&
10349 nDestSpace == icSigNamedData) {
10350 return icCmmStatBadSpaceLink;
10351 }
10352
10353 if (nDestSpace != icSigNamedData &&
10354 pXform->GetDstSpace() == icSigNamedData) {
10355 return icCmmStatBadSpaceLink;
10356 }
10357
10358 return pXform->SetDestSpace(nDestSpace);
10359 }
10360
10361 return icCmmStatBadXform;
10362}
10363
10364
10365/**
10366****************************************************************************
10367* Name: CIccMruCmm::CIccMruCmm
10368*
10369* Purpose: private constructor - Use Attach to create CIccMruCmm objects
10370*****************************************************************************
10371*/
10372CIccMruCmm::CIccMruCmm()
10373{
10374 m_pCmm = NULL__null;
10375 m_bDeleteCmm = false;
10376}
10377
10378
10379/**
10380****************************************************************************
10381* Name: CIccMruCmm::~CIccMruCmm
10382*
10383* Purpose: destructor
10384*****************************************************************************
10385*/
10386CIccMruCmm::~CIccMruCmm()
10387{
10388 if (m_pCmm && m_bDeleteCmm)
10389 delete m_pCmm;
10390}
10391
10392
10393/**
10394****************************************************************************
10395* Name: CIccMruCmm::Attach
10396*
10397* Purpose: Create a Cmm decorator object that implements a cache of most
10398* recently used pixel transformations.
10399*
10400* Args:
10401* pCmm - pointer to cmm object that we are attaching to.
10402* nCacheSize - number of most recently used transformations to cache
10403* bDeleteCmm - flag to indicate whether cmm should be deleted when
10404* this is destroyed.
10405*
10406* Return:
10407* A CIccMruCmm object that represents a cached form of the pCmm passed in.
10408* The pCmm will be owned by the returned object unless.
10409*
10410* If this function fails the pCmm object will be deleted.
10411*****************************************************************************
10412*/
10413CIccMruCmm* CIccMruCmm::Attach(CIccCmm *pCmm, icUInt8Number nCacheSize/* =4 */, bool bDeleteCmm/*=true*/)
10414{
10415 if (!pCmm || !nCacheSize)
10416 return NULL__null;
10417
10418 if (!pCmm->Valid()) {
10419 if (bDeleteCmm)
10420 delete pCmm;
10421 return NULL__null;
10422 }
10423
10424 CIccMruCmm *rv = new CIccMruCmm();
10425
10426 rv->m_pCmm = pCmm;
10427 rv->m_nCacheSize = nCacheSize;
10428 rv->m_bDeleteCmm = bDeleteCmm;
10429
10430 rv->m_nSrcSpace = pCmm->GetSourceSpace();
10431 rv->m_nDestSpace = pCmm->GetDestSpace();
10432 rv->m_nLastSpace = pCmm->GetLastSpace();
10433 rv->m_nLastIntent = pCmm->GetLastIntent();
10434
10435 if (rv->Begin()!=icCmmStatOk) {
10436 delete rv;
10437 return NULL__null;
10438 }
10439
10440 return rv;
10441}
10442
10443CIccApplyCmm *CIccMruCmm::GetNewApplyCmm(icStatusCMM &status)
10444{
10445 CIccApplyMruCmm *rv = new CIccApplyMruCmm(this);
10446
10447 if (!rv) {
10448 status = icCmmStatAllocErr;
10449 return NULL__null;
10450 }
10451
10452 if (!rv->Init(m_pCmm, m_nCacheSize)) {
10453 delete rv;
10454 status = icCmmStatBad;
10455 return NULL__null;
10456 }
10457
10458 return rv;
10459}
10460
10461/**
10462****************************************************************************
10463* Name: CIccMruCache::CIccMruCache
10464*
10465* Purpose: constructor
10466*****************************************************************************
10467*/
10468template<class T>
10469CIccMruCache<T>::CIccMruCache()
10470{
10471 m_cache = NULL__null;
10472
10473 m_pixelData = NULL__null;
10474}
10475
10476/**
10477****************************************************************************
10478* Name: CIccMruCache::~CIccMruCache
10479*
10480* Purpose: destructor
10481*****************************************************************************
10482*/
10483template<class T>
10484CIccMruCache<T>::~CIccMruCache()
10485{
10486 if (m_cache)
10487 delete[] m_cache;
10488
10489 if (m_pixelData)
10490 free(m_pixelData);
10491}
10492
10493/**
10494****************************************************************************
10495* Name: CIccMruCache::Init
10496*
10497* Purpose: Initialize the object and set up the cache
10498*
10499* Args:
10500* pCmm - pointer to cmm object that we are attaching to.
10501* nCacheSize - number of most recently used transformations to cache
10502*
10503* Return:
10504* true if successful
10505*****************************************************************************
10506*/
10507template<class T>
10508bool CIccMruCache<T>::Init(icUInt16Number nSrcSamples, icUInt16Number nDstSamples, icUInt16Number nCacheSize)
10509{
10510 m_nSrcSamples = nSrcSamples;
10511 m_nSrcSize = nSrcSamples * sizeof(T);
10512 m_nDstSize = nDstSamples * sizeof(T);
10513
10514 m_nTotalSamples = m_nSrcSamples + nDstSamples;
10515
10516 m_nNumPixel = 0;
10517 m_nCacheSize = nCacheSize;
10518
10519 m_pFirst = NULL__null;
10520 m_cache = new CIccMruPixel<T>[nCacheSize];
10521
10522 if (!m_cache)
10523 return false;
10524
10525 m_pixelData = (T*)malloc(nCacheSize * m_nTotalSamples * sizeof(T));
10526
10527 if (!m_pixelData)
10528 return false;
10529
10530 return true;
10531}
10532
10533template<class T>
10534CIccMruCache<T> *CIccMruCache<T>::NewMruCache(icUInt16Number nSrcSamples, icUInt16Number nDstSamples, icUInt16Number nCacheSize /* = 4 */)
10535{
10536 CIccMruCache<T> *rv = new CIccMruCache<T>;
10537
10538 if (!rv->Init(nSrcSamples, nDstSamples, nCacheSize)) {
10539 delete rv;
10540 return NULL__null;
10541 }
10542
10543 return rv;
10544}
10545
10546/**
10547****************************************************************************
10548* Name: CIccMruCache::Apply
10549*
10550* Purpose: Apply a transformation to a pixel.
10551*
10552* Args:
10553* DstPixel - Location to store pixel results
10554* SrcPixel - Location to get pixel values from
10555*
10556* Return:
10557* true if SrcPixel found in cache and DstPixel initialized with value
10558* fails if SrcPixel not found (DstPixel not touched)
10559*****************************************************************************
10560*/
10561template<class T>
10562bool CIccMruCache<T>::Apply(T *DstPixel, const T *SrcPixel)
10563{
10564 CIccMruPixel<T> *ptr, *prev = NULL__null, *last = NULL__null;
10565 int i;
10566 T *pixel;
10567
10568 for (ptr = m_pFirst, i = 0; ptr; ptr = ptr->pNext, i++) {
10569 if (!memcmp(SrcPixel, ptr->pPixelData, m_nSrcSize)) {
10570 memcpy(DstPixel, &ptr->pPixelData[m_nSrcSamples], m_nDstSize);
10571 if (ptr != m_pFirst) {
10572 last->pNext = ptr->pNext;
10573
10574 ptr->pNext = m_pFirst;
10575 m_pFirst = ptr;
10576 }
10577 return true;
10578 }
10579 prev = last;
10580 last = ptr;
10581 }
10582
10583 //If we get here SrcPixel is not in the cache
10584 if (i < m_nCacheSize) {
10585 pixel = &m_pixelData[i*m_nTotalSamples];
10586
10587 ptr = &m_cache[i];
10588 ptr->pPixelData = pixel;
10589
10590 if (m_pFirst) {
10591 ptr->pNext = m_pFirst;
10592 }
10593 m_pFirst = ptr;
10594 }
10595 else { //Reuse oldest value and put it at the front of the list
10596 prev->pNext = NULL__null;
10597 last->pNext = m_pFirst;
10598
10599 m_pFirst = last;
10600 pixel = last->pPixelData;
10601 }
10602 T *dest = &pixel[m_nSrcSamples];
10603
10604 memcpy(pixel, SrcPixel, m_nSrcSize);
10605
10606 return false;
10607}
10608
10609template<class T>
10610void CIccMruCache<T>::Update(T* DstPixel)
10611{
10612 memcpy(&m_pFirst->pPixelData[m_nSrcSamples], DstPixel, m_nDstSize);
10613}
10614
10615//Make sure typedef classes get built
10616template class CIccMruCache<icFloatNumber>;
10617template class CIccMruCache<icUInt8Number>;
10618template class CIccMruCache<icUInt16Number>;
10619
10620
10621CIccApplyMruCmm::CIccApplyMruCmm(CIccMruCmm *pCmm) : CIccApplyCmm(pCmm)
10622{
10623 m_pCachedCmm = NULL__null;
10624 m_pCache = NULL__null;
10625}
10626
10627/**
10628****************************************************************************
10629* Name: CIccApplyMruCmm::~CIccApplyMruCmm
10630*
10631* Purpose: destructor
10632*****************************************************************************
10633*/
10634CIccApplyMruCmm::~CIccApplyMruCmm()
10635{
10636 if (m_pCache)
10637 delete m_pCache;
10638
10639}
10640
10641/**
10642****************************************************************************
10643* Name: CIccApplyMruCmm::Init
10644*
10645* Purpose: Initialize the object and set up the cache
10646*
10647* Args:
10648* pCmm - pointer to cmm object that we are attaching to.
10649* nCacheSize - number of most recently used transformations to cache
10650*
10651* Return:
10652* true if successful
10653*****************************************************************************
10654*/
10655bool CIccApplyMruCmm::Init(CIccCmm *pCachedCmm, icUInt16Number nCacheSize)
10656{
10657 m_pCachedCmm = pCachedCmm;
10658
10659 m_pCache = CIccMruCacheFloat::NewMruCache(m_pCmm->GetSourceSamples(), m_pCmm->GetDestSamples(), nCacheSize);
10660
10661 if (!m_pCache)
10662 return false;
10663
10664 return true;
10665}
10666
10667/**
10668****************************************************************************
10669* Name: CIccMruCmm::Apply
10670*
10671* Purpose: Apply a transformation to a pixel.
10672*
10673* Args:
10674* DstPixel - Location to store pixel results
10675* SrcPixel - Location to get pixel values from
10676*
10677* Return:
10678* icCmmStatOk if successful
10679*****************************************************************************
10680*/
10681icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
10682{
10683#if defined(_DEBUG)
10684 if (!m_pCache)
10685 return icCmmStatInvalidLut;
10686#endif
10687
10688 if (!m_pCache->Apply(DstPixel, SrcPixel)) {
10689
10690 m_pCachedCmm->Apply(DstPixel, SrcPixel);
10691
10692 m_pCache->Update(DstPixel);
10693 }
10694
10695 return icCmmStatOk;
10696}
10697
10698/**
10699****************************************************************************
10700* Name: CIccMruCmm::Apply
10701*
10702* Purpose: Apply a transformation to a pixel.
10703*
10704* Args:
10705* DstPixel - Location to store pixel results
10706* SrcPixel - Location to get pixel values from
10707* nPixels - number of pixels to convert
10708*
10709* Return:
10710* icCmmStatOk if successful
10711*****************************************************************************
10712*/
10713icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
10714{
10715 icUInt32Number k;
10716
10717#if defined(_DEBUG)
10718 if (!m_pCache)
10719 return icCmmStatInvalidLut;
10720#endif
10721
10722 for (k=0; k<nPixels;k++) {
10723 if (!m_pCache->Apply(DstPixel, SrcPixel)) {
10724 m_pCachedCmm->Apply(DstPixel, SrcPixel);
10725 m_pCache->Update(DstPixel);
10726 }
10727 SrcPixel += m_pCmm->GetSourceSamples();
10728 DstPixel += m_pCmm->GetDestSamples();
10729 }
10730
10731 return icCmmStatOk;
10732}
10733
10734
10735#ifdef USEREFICCMAXNAMESPACE
10736} //namespace refIccMAX
10737#endif