Hoyt's FORK of DemoIccMAX 2.1.17.hoyt
Documentation for Hoyt's FORK of DemoIccMAX
Loading...
Searching...
No Matches
IccCmm.cpp
Go to the documentation of this file.
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
106
107#define IsSpaceColorimetricPCS(x) ((x)==icSigXYZPcsData || (x)==icSigLabPcsData)
108#define IsSpaceNChannel(x) (icGetColorSpaceType(x)==icSigNChannelData)
109#define IsSpacePCS(x) (IsSpaceColorimetricPCS(x) || IsSpaceSpectralPCS(x))
110#define IsSpaceMCS(x) (icGetColorSpaceType(x)==icSigSrcMCSChannelData)
111#define IsSpaceCMYK(x) ((x)==icSigCmykData || (x)==icSig4colorData)
112
113#define IsNChannelCompat(x, y) ((IsSpaceNChannel(x) && icNumColorSpaceChannels(x)==icGetSpaceSamples(y)) || (IsSpaceNChannel(y) && icNumColorSpaceChannels(y)==icGetSpaceSamples(x)))
114
115#define IsCompatSpace(x, y) ((x)==(y) || (IsSpacePCS(x) && IsSpacePCS(y)) || (IsSpaceMCS(x) && IsSpaceMCS(y))/* || (IsSpaceCMYK(x) && IsSpaceCMYK(y))*/)
116
117
118#define ICCPCSSTEPDUMPFMT ICCMTXSTEPDUMPFMT
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() : m_Convert{}
135{
136 m_bIsV2Lab = false;
137 m_Space = icSigUnknownData;
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) && 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;
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;
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;
570 m_bOwnsProfile = true;
571 m_bInput = true;
572 m_nIntent = icUnknownIntent;
573 m_pAdjustPCS = NULL;
574 m_bAdjustPCS = false;
575 m_bAbsToRel = false;
576 m_nMCS = icNoMCS;
577 m_bUseSpectralPCS = false;
578 m_bSrcPcsConversion = true;
579 m_bDstPcsConversion = true;
580 m_pConnectionConditions = NULL;
581 m_bDeleteEnvLooup = true;
582 m_pCmmEnvVarLookup = NULL;
583 m_nTagIntent = icPerceptual;
584 m_MediaXYZ = {};
585 m_nInterp = icInterpLinear;
586 m_bUseD2BTags = false;
587 m_bLuminanceMatching = false;
588 m_PCSOffset[0] = m_PCSOffset[1] = m_PCSOffset[2] = 0;
589}
590
591
592/**
593 **************************************************************************
594 * Name: CIccXform::~CIccXform
595 *
596 * Purpose:
597 * Destructor
598 **************************************************************************
599 */
600CIccXform::~CIccXform()
601{
602 if (m_pProfile && m_bOwnsProfile)
603 delete m_pProfile;
604
605 if (m_pAdjustPCS) {
606 delete m_pAdjustPCS;
607 }
608
609 if (m_pCmmEnvVarLookup && m_bDeleteEnvLooup) {
610 delete m_pCmmEnvVarLookup;
611 }
612
613}
614
615
616void CIccXform::DetachAll()
617{
618 m_pProfile = NULL;
619 m_bOwnsProfile = true;
620 m_pConnectionConditions = NULL;
621}
622
623/**
624 **************************************************************************
625 * Name: CIccXform::Create
626 *
627 * Purpose:
628 * This is a static Creation function that creates derived CIccXform objects and
629 * initializes them.
630 *
631 * Args:
632 * pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will
633 * be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile
634 * object needs to be allocated on the heap.
635 * bInput = flag to indicate whether to use the input or output side of the profile,
636 * nIntent = the rendering intent to apply to the profile,
637 * nInterp = the interpolation algorithm to use for N-D luts.
638 * nLutType = selection of which transform lut to use
639 * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
640 * pHintManager = pointer to object that contains xform creation hints
641 *
642 * Return:
643 * A suitable pXform object
644 **************************************************************************
645 */
646CIccXform *CIccXform::Create(CIccProfile *pProfile,
647 bool bInput/* =true */,
648 icRenderingIntent nIntent/* =icUnknownIntent */,
649 icXformInterp nInterp/* =icInterpLinear */,
650 IIccProfileConnectionConditions *pPcc/*=NULL*/,
651 icXformLutType nLutType/* =icXformLutColor */,
652 bool bUseD2BTags/* =true */, CIccCreateXformHintManager *pHintManager/* =NULL */)
653{
654 CIccXform *rv = NULL;
655 icRenderingIntent nTagIntent = nIntent;
656 bool bUseSpectralPCS = false;
657 bool bAbsToRel = false;
658 bool bRelToAbs = false;
660 icXformLutType nUseLutType = nLutType;
661 bool bUseColorimeticTags = true;
662
663 if (nLutType == icXformLutSpectral) {
664 nUseLutType = icXformLutColor;
665 bUseD2BTags = true;
666 bUseColorimeticTags = false;
667 }
668 else if (nLutType == icXformLutColorimetric) {
669 nUseLutType = icXformLutColor;
670 }
671
672 if (pProfile->m_Header.deviceClass==icSigColorEncodingClass) {
673 CIccProfile *pEncProfile;
674 if (icConvertEncodingProfile(pEncProfile, pProfile)!=icEncConvertOk)
675 return NULL;
676 delete pProfile;
677 pProfile = pEncProfile;
678 }
679 if (pProfile->m_Header.deviceClass==icSigLinkClass/* && nIntent==icAbsoluteColorimetric*/) {
680 nIntent = icPerceptual;
681 }
682
683 if (nTagIntent == icUnknownIntent)
684 nTagIntent = icPerceptual;
685
686 switch (nUseLutType) {
687 case icXformLutColor:
688 if (bInput) {
689 CIccTag *pTag = NULL;
690 if (bUseD2BTags) {
691 if (pProfile->m_Header.spectralPCS && nLutType!=icXformLutColorimetric) {
692 pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent);
693
694 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
695 pTag = pProfile->FindTag(icSigDToB1Tag);
696 if (pTag)
697 nTagIntent = icRelativeColorimetric;
698 }
699 else if (!pTag && nTagIntent == icRelativeColorimetric) {
700 pTag = pProfile->FindTag(icSigDToB3Tag);
701 if (pTag) {
702 nTagIntent = icAbsoluteColorimetric;
703 bAbsToRel = true;
704 }
705 }
706
707 if (pTag)
708 bUseSpectralPCS = true;
709
710 if (!pTag) {
711 pTag = pProfile->FindTag(icSigDToB0Tag);
712 }
713 if (!pTag) {
714 pTag = pProfile->FindTag(icSigDToB1Tag);
715 }
716 if (!pTag) {
717 pTag = pProfile->FindTag(icSigDToB3Tag);
718 if (pTag) {
719 nTagIntent = icAbsoluteColorimetric;
720 bAbsToRel = true;
721 }
722 }
723 }
724 else if (pProfile->m_Header.version < icVersionNumberV5) {
725 pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent);
726
727 if (!pTag && nTagIntent ==icAbsoluteColorimetric) {
728 pTag = pProfile->FindTag(icSigDToB1Tag);
729 if (pTag)
730 nTagIntent = icRelativeColorimetric;
731 }
732
733 //Apparently Using DtoB0 is not prescribed here by the v4 ICC Specification
734 if (!pTag && pProfile->m_Header.version >= icVersionNumberV5) {
735 pTag = pProfile->FindTag(icSigDToB0Tag);
736 }
737 }
738 }
739
740 if (bUseColorimeticTags) {
741 if (!pTag) {
742 pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent);
743 }
744
745 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
746 pTag = pProfile->FindTag(icSigAToB1Tag);
747 if (pTag)
748 nTagIntent = icRelativeColorimetric;
749 }
750 else if (!pTag && nTagIntent == icRelativeColorimetric) {
751 pTag = pProfile->FindTag(icSigAToB3Tag);
752 if (pTag) {
753 nTagIntent = icAbsoluteColorimetric;
754 bAbsToRel = true;
755 }
756 }
757
758 if (!pTag) {
759 pTag = pProfile->FindTag(icSigAToB0Tag);
760 }
761 if (!pTag) {
762 pTag = pProfile->FindTag(icSigAToB1Tag);
763 }
764 if (!pTag) {
765 pTag = pProfile->FindTag(icSigAToB3Tag);
766 if (pTag) {
767 nTagIntent = icAbsoluteColorimetric;
768 bAbsToRel = true;
769 }
770 }
771 }
772
773 //Unsupported elements cause fall back behavior
774 if (pTag && !pTag->IsSupported())
775 pTag = NULL;
776
777 if (!pTag) {
778 if (pProfile->m_Header.version < icVersionNumberV5) {
779 //Matrix/TRC profiles are deprecated in v5 profiles
780 if (pProfile->m_Header.colorSpace == icSigRgbData) {
781 rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, NULL, pHintManager);
782 }
783 else if (pProfile->m_Header.colorSpace == icSigGrayData) {
785 }
786 else
787 return NULL;
788 }
789 else
790 return NULL;
791 }
792 else if (pTag->GetType()==icSigMultiProcessElementType) {
793 rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager);
794 }
795 else {
796 switch(pProfile->m_Header.colorSpace) {
797 case icSigXYZData:
798 case icSigLabData:
799 case icSigLuvData:
800 case icSigYCbCrData:
801 case icSigYxyData:
802 case icSigRgbData:
803 case icSigHsvData:
804 case icSigHlsData:
805 case icSigCmyData:
806 case icSig3colorData:
807 rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
808 break;
809
810 case icSigCmykData:
811 case icSig4colorData:
812 rv = CIccXformCreator::CreateXform(icXformType4DLut, pTag, pHintManager);
813 break;
814
815 default:
816 rv = CIccXformCreator::CreateXform(icXformTypeNDLut, pTag, pHintManager);
817 break;
818 }
819 }
820 }
821 else {
822 CIccTag *pTag = NULL;
823
824 if (nLutType == icXformLutColorimetric && pProfile->m_Header.version >= icVersionNumberV5) {
825 bUseD2BTags = false;
826 }
827
828 if (bUseD2BTags) {
829 pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent);
830
831 //Additional precedence not prescribed by the v4 ICC Specification
832 if (!pTag && pProfile->m_Header.version >= icVersionNumberV5) {
833 pTag = pProfile->FindTag(icSigBToD0Tag);
834
835 if (!pTag) {
836 pTag = pProfile->FindTag(icSigBToD1Tag);
837 if (pTag) {
838 nTagIntent = icRelativeColorimetric;
839 if (nTagIntent==icAbsoluteColorimetric)
840 bRelToAbs = true;
841 }
842 }
843
844 if (!pTag) {
845 pTag = pProfile->FindTag(icSigBToD3Tag);
846 if (pTag) {
847 nTagIntent = icAbsoluteColorimetric;
848 bAbsToRel = true;
849 }
850 }
851 }
852
853 //Unsupported elements cause fall back behavior
854 if (pTag && !pTag->IsSupported())
855 pTag = NULL;
856
857 if (pTag)
858 bUseSpectralPCS = true;
859
860 if (!pTag && nTagIntent == icAbsoluteColorimetric && pProfile->m_Header.version < icVersionNumberV5) {
861 pTag = pProfile->FindTag(icSigBToD1Tag);
862
863 //Unsupported elements cause fall back behavior
864 if (pTag && !pTag->IsSupported())
865 pTag = NULL;
866
867 if (pTag)
868 nTagIntent = icRelativeColorimetric;
869 }
870 }
871
872 if (bUseColorimeticTags) {
873
874 if (!pTag) {
875 pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent);
876 }
877
878 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
879 pTag = pProfile->FindTag(icSigBToA1Tag);
880 if (pTag)
881 nTagIntent = icRelativeColorimetric;
882 }
883
884 if (!pTag) {
885 pTag = pProfile->FindTag(icSigBToA0Tag);
886 }
887
888 //Additional precedence not prescribed by the v4 ICC Specification
889 if (!pTag && pProfile->m_Header.version >= icVersionNumberV5) {
890
891 pTag = pProfile->FindTag(icSigBToA1Tag);
892 if (pTag) {
893 nTagIntent = icRelativeColorimetric;
894 if (nTagIntent == icAbsoluteColorimetric)
895 bRelToAbs = true;
896 }
897
898 if (!pTag) {
899 pTag = pProfile->FindTag(icSigBToA3Tag);
900 if (pTag) {
901 nTagIntent = icAbsoluteColorimetric;
902 bAbsToRel = true;
903 }
904 }
905 }
906 }
907
908 if (!pTag) {
909 if (pProfile->m_Header.version < icVersionNumberV5) {
910 if (pProfile->m_Header.colorSpace == icSigRgbData) {
911 rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, pTag, pHintManager);
912 }
913 else if (pProfile->m_Header.colorSpace == icSigGrayData) {
915 }
916 else
917 return NULL;
918 }
919 else
920 return NULL;
921 }
922 else if (pTag->GetType()==icSigMultiProcessElementType) {
923 rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager);
924 }
925 else {
926 switch(pProfile->m_Header.pcs) {
927 case icSigXYZData:
928 case icSigLabData:
929 rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
930 break;
931
932 default:
933 break;
934 }
935 }
936 }
937 break;
938
940 {
941 CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag);
942 if (!pTag)
943 return NULL;
944
945 CIccCreateNamedColorXformHint* pNamedColorHint = new CIccCreateNamedColorXformHint();
946 pNamedColorHint->csPcs = pProfile->m_Header.pcs;
947 pNamedColorHint->csDevice = pProfile->m_Header.colorSpace;
948 pNamedColorHint->csSpectralPcs = pProfile->m_Header.spectralPCS;
949 pNamedColorHint->spectralRange = pProfile->m_Header.spectralRange;
950 pNamedColorHint->biSpectralRange = pProfile->m_Header.biSpectralRange;
951 if (pHintManager) {
952 pHintManager->AddHint(pNamedColorHint);
954 pHintManager->DeleteHint(pNamedColorHint);
955 }
956 else {
957 CIccCreateXformHintManager HintManager;
958 HintManager.AddHint(pNamedColorHint);
960 }
961
962 if (pProfile->m_Header.spectralPCS)
963 bUseSpectralPCS = true;
964 }
965 break;
966
968 {
969 bInput = false;
970 CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent);
971 if (!pTag) {
972 pTag = pProfile->FindTag(icSigPreview0Tag);
973 }
974 if (!pTag) {
975 return NULL;
976 }
977 else {
978 switch(pProfile->m_Header.pcs) {
979 case icSigXYZData:
980 case icSigLabData:
981 rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
982
983 default:
984 break;
985 }
986 }
987 }
988 break;
989
990 case icXformLutGamut:
991 {
992 bInput = false;
993 CIccTag *pTag = pProfile->FindTag(icSigGamutTag);
994 if (!pTag) {
995 return NULL;
996 }
997 else {
998 switch(pProfile->m_Header.pcs) {
999 case icSigXYZData:
1000 case icSigLabData:
1001 rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
1002
1003 default:
1004 break;
1005 }
1006 }
1007 }
1008 break;
1009
1011 {
1012 // get the correct tag first
1013
1014 CIccTag *pTag = NULL;
1015 if (bUseD2BTags) {
1016 if (pProfile->m_Header.spectralPCS) {
1017
1018 pTag = pProfile->FindTag(icSigBrdfSpectralParameter0Tag + nTagIntent);
1019
1020 if (pTag)
1021 bUseSpectralPCS = true;
1022 }
1023 }
1024 else
1025 {
1026 pTag = pProfile->FindTag(icSigBrdfColorimetricParameter0Tag + nTagIntent);
1027
1028 //Unsupported elements cause fall back behavior
1029 if (pTag && !pTag->IsSupported())
1030 pTag = NULL;
1031 }
1032
1033 // now extract the correct part from the structure
1034 CIccStructBRDF* pStructTag = dynamic_cast<CIccStructBRDF*>(pTag);
1035
1036 if (pStructTag != NULL)
1037 {
1038 CIccTag *pTag2 = NULL;
1039
1040 switch (nLutType) {
1042 pTag2 = pStructTag->GetElem(icSigBrdfTransformMbr);
1043 break;
1044 default:
1045 // can't get here, get rid of warning
1046 break;
1047 }
1048 if (pTag2)
1049 rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag2, pHintManager);
1050 }
1051 }
1052 break;
1053
1055 {
1056 // get the correct tag first
1057
1058 CIccTag *pTag = NULL;
1059 if (bUseD2BTags) {
1060 if (pProfile->m_Header.spectralPCS) {
1061
1062 pTag = pProfile->FindTag(icSigBRDFDToB0Tag + nTagIntent);
1063
1064 if (pTag)
1065 bUseSpectralPCS = true;
1066 }
1067 }
1068 else
1069 {
1070 pTag = pProfile->FindTag(icSigBRDFAToB0Tag + nTagIntent);
1071
1072 //Unsupported elements cause fall back behavior
1073 if (pTag && !pTag->IsSupported())
1074 pTag = NULL;
1075 }
1076
1077 if (pTag != NULL)
1078 {
1079 rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager);
1080 }
1081 }
1082 break;
1083
1085 {
1086 CIccTag *pTag = NULL;
1087 if (pProfile->m_Header.deviceClass == icSigMaterialVisualizationClass) {
1088 bInput = true;
1089 nMCS = icFromMCS;
1090
1091 if (pProfile->m_Header.spectralPCS) {
1092 pTag = pProfile->FindTag(icSigBRDFMToS0Tag + nTagIntent);
1093
1094 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
1095 pTag = pProfile->FindTag(icSigBRDFMToS1Tag);
1096 if (pTag)
1097 nTagIntent = icRelativeColorimetric;
1098 }
1099 else if (!pTag && nTagIntent != icAbsoluteColorimetric) {
1100 pTag = pProfile->FindTag(icSigBRDFMToS3Tag);
1101 if (pTag) {
1102 nTagIntent = icAbsoluteColorimetric;
1103 bAbsToRel = true;
1104 }
1105 }
1106
1107 if (!pTag) {
1108 pTag = pProfile->FindTag(icSigBRDFMToS0Tag);
1109 }
1110 if (!pTag) {
1111 pTag = pProfile->FindTag(icSigBRDFMToS1Tag);
1112 }
1113 if (!pTag) {
1114 pTag = pProfile->FindTag(icSigBRDFMToS3Tag);
1115 if (pTag) {
1116 nTagIntent = icAbsoluteColorimetric;
1117 bAbsToRel = true;
1118 }
1119 }
1120
1121 if (pTag)
1122 bUseSpectralPCS = true;
1123 }
1124 if (!pTag && pProfile->m_Header.pcs != 0) {
1125 pTag = pProfile->FindTag(icSigBRDFMToB0Tag + nTagIntent);
1126
1127 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
1128 pTag = pProfile->FindTag(icSigBRDFMToB1Tag);
1129 if (pTag)
1130 nTagIntent = icRelativeColorimetric;
1131 }
1132 else if (!pTag && nTagIntent != icAbsoluteColorimetric) {
1133 pTag = pProfile->FindTag(icSigBRDFMToB3Tag);
1134 if (pTag) {
1135 nTagIntent = icAbsoluteColorimetric;
1136 bAbsToRel = true;
1137 }
1138 }
1139 if (!pTag) {
1140 pTag = pProfile->FindTag(icSigBRDFMToB0Tag);
1141 }
1142 if (!pTag) {
1143 pTag = pProfile->FindTag(icSigBRDFMToB1Tag);
1144 }
1145 if (!pTag) {
1146 pTag = pProfile->FindTag(icSigBRDFMToB3Tag);
1147 if (pTag) {
1148 nTagIntent = icAbsoluteColorimetric;
1149 bAbsToRel = true;
1150 }
1151 }
1152 }
1153
1154 //Unsupported elements cause fall back behavior
1155 if (pTag && !pTag->IsSupported())
1156 pTag = NULL;
1157
1158 //Unsupported elements cause fall back behavior
1159 if (pTag && !pTag->IsSupported())
1160 pTag = NULL;
1161 }
1162 if (pTag && pProfile->m_Header.mcs) {
1163 rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager);
1164 }
1165 else
1166 rv = NULL;
1167 }
1168 break;
1169
1170 case icXformLutMCS:
1171 {
1172 CIccTag *pTag = NULL;
1173 if (pProfile->m_Header.deviceClass==icSigMaterialIdentificationClass ||
1174 pProfile->m_Header.deviceClass==icSigInputClass) {
1175 bInput = true;
1176 nMCS = icToMCS;
1177 pTag = pProfile->FindTag(icSigAToM0Tag);
1178 }
1179 else if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) {
1180 bInput = true;
1181 nMCS = icFromMCS;
1182
1183 if (pProfile->m_Header.spectralPCS) {
1184 pTag = pProfile->FindTag(icSigMToS0Tag + nTagIntent);
1185
1186 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
1187 pTag = pProfile->FindTag(icSigMToS1Tag);
1188 if (pTag)
1189 nTagIntent = icRelativeColorimetric;
1190 }
1191 else if (!pTag && nTagIntent != icAbsoluteColorimetric) {
1192 pTag = pProfile->FindTag(icSigMToS3Tag);
1193 if (pTag) {
1194 nTagIntent = icAbsoluteColorimetric;
1195 bAbsToRel = true;
1196 }
1197 }
1198
1199 if (!pTag) {
1200 pTag = pProfile->FindTag(icSigMToS0Tag);
1201 }
1202 if (!pTag) {
1203 pTag = pProfile->FindTag(icSigMToS1Tag);
1204 }
1205 if (!pTag) {
1206 pTag = pProfile->FindTag(icSigMToS3Tag);
1207 if (pTag) {
1208 nTagIntent = icAbsoluteColorimetric;
1209 bAbsToRel = true;
1210 }
1211 }
1212
1213 if (pTag)
1214 bUseSpectralPCS = true;
1215 }
1216 if (!pTag && pProfile->m_Header.pcs!=0) {
1217 pTag = pProfile->FindTag(icSigMToB0Tag + nTagIntent);
1218
1219 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
1220 pTag = pProfile->FindTag(icSigMToB1Tag);
1221 if (pTag)
1222 nTagIntent = icRelativeColorimetric;
1223 }
1224 else if (!pTag && nTagIntent != icAbsoluteColorimetric) {
1225 pTag = pProfile->FindTag(icSigMToB3Tag);
1226 if (pTag) {
1227 nTagIntent = icAbsoluteColorimetric;
1228 bAbsToRel = true;
1229 }
1230 }
1231
1232 if (!pTag) {
1233 pTag = pProfile->FindTag(icSigMToB0Tag);
1234 }
1235 if (!pTag) {
1236 pTag = pProfile->FindTag(icSigMToB1Tag);
1237 }
1238 if (!pTag) {
1239 pTag = pProfile->FindTag(icSigMToB3Tag);
1240 if (pTag) {
1241 nTagIntent = icAbsoluteColorimetric;
1242 bAbsToRel = true;
1243 }
1244 }
1245 }
1246
1247 //Unsupported elements cause fall back behavior
1248 if (pTag && !pTag->IsSupported())
1249 pTag = NULL;
1250 }
1251 else if (pProfile->m_Header.deviceClass==icSigMaterialLinkClass) {
1252 bInput = false;
1253 nMCS = icFromMCS;
1254 pTag = pProfile->FindTag(icSigMToA0Tag);
1255 }
1256 if (pTag && pProfile->m_Header.mcs) {
1257 rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager);
1258 }
1259 else
1260 rv = NULL;
1261 }
1262 break;
1263
1264 }
1265
1266 if (rv) {
1267 if (pPcc)
1268 rv->m_pConnectionConditions = pPcc;
1269 else
1270 rv->m_pConnectionConditions = pProfile;
1271
1272 rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel, nMCS);
1273 }
1274
1275 return rv;
1276}
1277
1278/**
1279**************************************************************************
1280* Name: CIccXform::Create
1281*
1282* Purpose:
1283* This is a static Creation function that creates derived CIccXform objects and
1284* initializes them.
1285*
1286* Args:
1287* pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will
1288* be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile
1289* object needs to be allocated on the heap.
1290* pTag = tag that specifies transform to use. It is assumed to use colorimetric PCS and have a lut type of icXformLutColor.
1291* bInput = flag to indicate whether to use the input or output side of the profile,
1292* nIntent = the rendering intent to apply to the profile,
1293* nInterp = the interpolation algorithm to use for N-D luts.
1294* pPcc = pointer to profile connection conditions to associate with transform
1295* pHintManager = pointer to object that contains xform creation hints
1296*
1297* Return:
1298* A suitable pXform object
1299**************************************************************************
1300*/
1301CIccXform *CIccXform::Create(CIccProfile *pProfile,
1302 CIccTag *pTag,
1303 bool bInput/* =true */,
1304 icRenderingIntent nIntent/* =icUnknownIntent */,
1305 icXformInterp nInterp/* =icInterpLinear */,
1306 IIccProfileConnectionConditions *pPcc/*=NULL*/,
1307 bool bUseSpectralPCS/* =false*/,
1308 CIccCreateXformHintManager *pHintManager/* =NULL */)
1309{
1310 CIccXform *rv = NULL;
1311 icRenderingIntent nTagIntent = nIntent;
1312 bool bAbsToRel = false;
1313 bool bRelToAbs = false;
1315
1316 if (pProfile->m_Header.deviceClass == icSigColorEncodingClass) {
1317 return NULL;
1318 }
1319
1320 if (pProfile->m_Header.deviceClass == icSigLinkClass/* && nIntent==icAbsoluteColorimetric*/) {
1321 nIntent = icPerceptual;
1322 }
1323
1324 if (nTagIntent == icUnknownIntent)
1325 nTagIntent = icPerceptual;
1326
1327 //Unsupported elements cause fall back behavior
1328 if (pTag == NULL)
1329 return NULL;
1330 if (pTag && !pTag->IsSupported())
1331 return NULL;
1332
1333 if (bInput) {
1334 if (pTag->GetType() == icSigMultiProcessElementType) {
1335 rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager);
1336 }
1337 else {
1338 switch (pProfile->m_Header.colorSpace) {
1339 case icSigXYZData:
1340 case icSigLabData:
1341 case icSigLuvData:
1342 case icSigYCbCrData:
1343 case icSigYxyData:
1344 case icSigRgbData:
1345 case icSigHsvData:
1346 case icSigHlsData:
1347 case icSigCmyData:
1348 case icSig3colorData:
1349 rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
1350 break;
1351
1352 case icSigCmykData:
1353 case icSig4colorData:
1354 rv = CIccXformCreator::CreateXform(icXformType4DLut, pTag, pHintManager);
1355 break;
1356
1357 default:
1358 rv = CIccXformCreator::CreateXform(icXformTypeNDLut, pTag, pHintManager);
1359 break;
1360 }
1361 }
1362 }
1363 else {
1364 if (pTag->GetType() == icSigMultiProcessElementType) {
1365 rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager);
1366 }
1367 else {
1368 switch (pProfile->m_Header.pcs) {
1369 case icSigXYZData:
1370 case icSigLabData:
1371 rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager);
1372 break;
1373
1374 default:
1375 break;
1376 }
1377 }
1378 }
1379
1380 if (rv) {
1381 if (pPcc)
1382 rv->m_pConnectionConditions = pPcc;
1383 else
1384 rv->m_pConnectionConditions = pProfile;
1385
1386 rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel, nMCS);
1387 }
1388
1389 return rv;
1390}
1391
1392/**
1393 ******************************************************************************
1394 * Name: CIccXform::SetParams
1395 *
1396 * Purpose:
1397 * This is an accessor function to set private values.
1398 *
1399 * Args:
1400 * pProfile = pointer to profile associated with transform
1401 * bInput = indicates whether profile is input profile
1402 * nIntent = rendering intent to apply to the profile
1403 * nInterp = the interpolation algorithm to use for N-D luts
1404 ******************************************************************************/
1405void CIccXform::SetParams(CIccProfile *pProfile, bool bInput, icRenderingIntent nIntent, icRenderingIntent nTagIntent,
1406 bool bUseSpectralPCS, icXformInterp nInterp, CIccCreateXformHintManager *pHintManager/* =NULL */,
1407 bool bAbsToRel/*=false*/, icMCSConnectionType nMCS/*=icNoMCS*/)
1408{
1409 m_pProfile = pProfile;
1410 m_bInput = bInput;
1411 m_nIntent = nIntent;
1412 m_nTagIntent = nTagIntent;
1413 m_nInterp = nInterp;
1414 m_pAdjustPCS = NULL;
1415 m_bUseSpectralPCS = bUseSpectralPCS;
1416 m_bAbsToRel = bAbsToRel;
1417 m_nMCS = nMCS;
1418 m_bLuminanceMatching = false;
1419
1420 if (pHintManager) {
1421 IIccCreateXformHint *pHint=NULL;
1422
1423 pHint = pHintManager->GetHint("CIccCreateAdjustPCSXformHint");
1424 if (pHint) {
1425 CIccCreateAdjustPCSXformHint *pAdjustPCSHint = (CIccCreateAdjustPCSXformHint*)pHint;
1426 m_pAdjustPCS = pAdjustPCSHint->GetNewAdjustPCSXform();
1427 }
1428
1429 pHint = pHintManager->GetHint("CIccCreateCmmEnvVarXformHint");
1430 if (pHint) {
1431 CIccCreateCmmEnvVarXformHint *pCmmEnvVarHint = (CIccCreateCmmEnvVarXformHint*)pHint;
1432 m_pCmmEnvVarLookup = pCmmEnvVarHint->GetNewCmmEnvVarLookup();
1433 }
1434
1435 pHint = pHintManager->GetHint("CIccLuminanceMatchingHint");
1436 if (pHint) {
1437 m_bLuminanceMatching = true;
1438 }
1439 }
1440}
1441
1442/**
1443 **************************************************************************
1444 * Name: CIccXform::Create
1445 *
1446 * Purpose:
1447 * This is a static Creation function that creates derived CIccXform objects and
1448 * initializes them.
1449 *
1450 * Args:
1451 * Profile = reference to a CIccProfile object that will be used to create the transform.
1452 * A copy of the CIccProfile object will be created and passed to the pointer based Create().
1453 * The copied object will be destroyed when the returned CIccXform object is destroyed.
1454 * bInput = flag to indicate whether to use the input or output side of the profile,
1455 * nIntent = the rendering intent to apply to the profile,
1456 * nInterp = the interpolation algorithm to use for N-D luts.
1457 * nLutType = selection of which transform lut to use
1458 * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
1459 * pHint = pointer to object passed to CIccXform creation functionality
1460 *
1461 * Return:
1462 * A suitable pXform object
1463 **************************************************************************
1464 */
1465CIccXform *CIccXform::Create(CIccProfile &Profile,
1466 bool bInput/* =true */,
1467 icRenderingIntent nIntent/* =icUnknownIntent */,
1468 icXformInterp nInterp/* =icInterpLinear */,
1469 IIccProfileConnectionConditions *pPcc/*=NULL*/,
1470 icXformLutType nLutType/* =icXformLutColor */,
1471 bool bUseD2BxB2DxTags/* =true */,
1472 CIccCreateXformHintManager *pHintManager/* =NULL */)
1473{
1474 CIccProfile *pProfile = new CIccProfile(Profile);
1475 CIccXform *pXform = Create(pProfile, bInput, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
1476
1477 if (!pXform)
1478 delete pProfile;
1479
1480 return pXform;
1481}
1482
1483
1484/**
1485 **************************************************************************
1486 * Name: CIccXform::Begin
1487 *
1488 * Purpose:
1489 * This function will be called before the xform is applied. Derived objects
1490 * should also call this base class function to initialize for Absolute Colorimetric
1491 * Intent handling which is performed through the use of the CheckSrcAbs and
1492 * CheckDstAbs functions.
1493 **************************************************************************
1494 */
1495icStatusCMM CIccXform::Begin()
1496{
1497 IIccProfileConnectionConditions *pCond = GetConnectionConditions();
1498
1499 icFloatNumber mediaXYZ[3];
1500 icFloatNumber illumXYZ[3];
1501
1502 if (m_nIntent==icAbsoluteColorimetric) {
1503 if (pCond) {
1504 pCond->getMediaWhiteXYZ(mediaXYZ);
1505
1506 m_MediaXYZ.X = icFtoF16(mediaXYZ[0]);
1507 m_MediaXYZ.Y = icFtoF16(mediaXYZ[1]);
1508 m_MediaXYZ.Z = icFtoF16(mediaXYZ[2]);
1509 }
1510 else {
1511 CIccTag *pTag = m_pProfile->FindTag(icSigMediaWhitePointTag);
1512
1513 if (!pTag || pTag->GetType()!=icSigXYZType)
1515
1516 CIccTagXYZ *pXyzTag = (CIccTagXYZ*)pTag;
1517
1518 m_MediaXYZ = (*pXyzTag)[0];
1519 mediaXYZ[0] = icFtoD(m_MediaXYZ.X);
1520 mediaXYZ[1] = icFtoD(m_MediaXYZ.Y);
1521 mediaXYZ[2] = icFtoD(m_MediaXYZ.Z);
1522 }
1523 }
1524
1525 icXYZNumber illXYZ;
1526 if (pCond) {
1527 pCond->getNormIlluminantXYZ(illumXYZ);
1528 illXYZ.X = icDtoF(illumXYZ[0]);
1529 illXYZ.Y = icDtoF(illumXYZ[1]);
1530 illXYZ.Z = icDtoF(illumXYZ[2]);
1531 }
1532 else {
1533 illXYZ = m_pProfile->m_Header.illuminant;
1534 illumXYZ[0] = icFtoD(illXYZ.X);
1535 illumXYZ[1] = icFtoD(illXYZ.Y);
1536 illumXYZ[2] = icFtoD(illXYZ.Z);
1537 }
1538
1539 // set up for any needed PCS adjustment
1540 if (m_nIntent == icAbsoluteColorimetric &&
1541 (m_MediaXYZ.X != illXYZ.X ||
1542 m_MediaXYZ.Y != illXYZ.Y ||
1543 m_MediaXYZ.Z != illXYZ.Z)) {
1544
1545 icColorSpaceSignature Space = m_pProfile->m_Header.pcs;
1546
1547 if (IsSpacePCS(Space)) {
1548 m_bAdjustPCS = true; // turn ON PCS adjustment
1549
1550 // scale factors depend upon media white point
1551 // set up for input transform
1552 if (!m_bInput) {
1553 m_PCSScale[0] = illumXYZ[0] / mediaXYZ[0];
1554 m_PCSScale[1] = illumXYZ[1] / mediaXYZ[1];
1555 m_PCSScale[2] = illumXYZ[2] / mediaXYZ[2];
1556 }
1557 else {
1558 m_PCSScale[0] = mediaXYZ[0] / illumXYZ[0];
1559 m_PCSScale[1] = mediaXYZ[1] / illumXYZ[1];
1560 m_PCSScale[2] = mediaXYZ[2] / illumXYZ[2];
1561
1562 }
1563
1564 m_PCSOffset[0] = 0.0;
1565 m_PCSOffset[1] = 0.0;
1566 m_PCSOffset[2] = 0.0;
1567 }
1568 }
1569 else if (m_nIntent == icPerceptual && (IsVersion2() || !HasPerceptualHandling())) {
1570 icColorSpaceSignature Space = m_pProfile->m_Header.pcs;
1571
1572 if (IsSpacePCS(Space) && m_pProfile->m_Header.deviceClass!=icSigAbstractClass) {
1573 m_bAdjustPCS = true; // turn ON PCS adjustment
1574
1575 // set up for input transform, which needs version 2 black point to version 4
1576 m_PCSScale[0] = (icFloatNumber) (1.0 - icPerceptualRefBlackX / icPerceptualRefWhiteX); // scale factors
1577 m_PCSScale[1] = (icFloatNumber) (1.0 - icPerceptualRefBlackY / icPerceptualRefWhiteY);
1578 m_PCSScale[2] = (icFloatNumber) (1.0 - icPerceptualRefBlackZ / icPerceptualRefWhiteZ);
1579
1580 m_PCSOffset[0] = (icFloatNumber) (icPerceptualRefBlackX * 32768.0 / 65535.0); // offset factors
1581 m_PCSOffset[1] = (icFloatNumber) (icPerceptualRefBlackY * 32768.0 / 65535.0);
1582 m_PCSOffset[2] = (icFloatNumber) (icPerceptualRefBlackZ * 32768.0 / 65535.0);
1583
1584 if (!m_bInput) { // output transform must convert version 4 black point to version 2
1585 m_PCSScale[0] = (icFloatNumber) 1.0 / m_PCSScale[0]; // invert scale factors
1586 m_PCSScale[1] = (icFloatNumber) 1.0 / m_PCSScale[1];
1587 m_PCSScale[2] = (icFloatNumber) 1.0 / m_PCSScale[2];
1588
1589 m_PCSOffset[0] = - m_PCSOffset[0] * m_PCSScale[0]; // negate offset factors
1590 m_PCSOffset[1] = - m_PCSOffset[1] * m_PCSScale[1];
1591 m_PCSOffset[2] = - m_PCSOffset[2] * m_PCSScale[2];
1592 }
1593 }
1594 }
1595
1596
1597 if (m_pAdjustPCS) {
1598 CIccProfile ProfileCopy(*m_pProfile);
1599
1600 // need to read in all the tags, so that a copy of the profile can be made
1601 if (!ProfileCopy.ReadTags(m_pProfile)) {
1603 }
1604
1605 if (!m_pAdjustPCS->CalcFactors(&ProfileCopy, this, m_PCSScale, m_PCSOffset)) {
1607 }
1608
1609 m_bAdjustPCS = true;
1610 delete m_pAdjustPCS;
1611 m_pAdjustPCS = NULL;
1612 }
1613
1614 return icCmmStatOk;
1615}
1616
1617/**
1618**************************************************************************
1619* Name: CIccXform::GetNewApply
1620*
1621* Purpose:
1622* This Factory function allocates data specific for the application of the xform.
1623* This allows multiple threads to simultaneously use the same xform.
1624**************************************************************************
1625*/
1626CIccApplyXform *CIccXform::GetNewApply(icStatusCMM &status)
1627{
1628 CIccApplyXform *rv = new CIccApplyXform(this);
1629
1630 if (!rv) {
1631 status = icCmmStatAllocErr;
1632 return NULL;
1633 }
1634
1635 status = icCmmStatOk;
1636 return rv;
1637}
1638
1639/**
1640 **************************************************************************
1641* Name: CIccXform::AdjustPCS
1642 *
1643 * Purpose:
1644* This function will take care of any PCS adjustments
1645* needed by the xform (the PCS is always version 4 relative).
1646 *
1647 * Args:
1648* DstPixel = Destination pixel where the result is stored,
1649* SrcPixel = Source pixel which is to be applied.
1650 *
1651 **************************************************************************
1652 */
1653void CIccXform::AdjustPCS(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
1654{
1655 icColorSpaceSignature Space = m_pProfile->m_Header.pcs;
1656
1657 if (Space==icSigLabData) {
1658 if (UseLegacyPCS()) {
1659 CIccPCS::Lab2ToXyz(DstPixel, SrcPixel, true);
1660 }
1661 else {
1662 CIccPCS::LabToXyz(DstPixel, SrcPixel, true);
1663 }
1664 }
1665 else {
1666 DstPixel[0] = SrcPixel[0];
1667 DstPixel[1] = SrcPixel[1];
1668 DstPixel[2] = SrcPixel[2];
1669 }
1670
1671 DstPixel[0] = DstPixel[0] * m_PCSScale[0] + m_PCSOffset[0];
1672 DstPixel[1] = DstPixel[1] * m_PCSScale[1] + m_PCSOffset[1];
1673 DstPixel[2] = DstPixel[2] * m_PCSScale[2] + m_PCSOffset[2];
1674
1675 if (Space==icSigLabData) {
1676 if (UseLegacyPCS()) {
1677
1678 CIccPCS::XyzToLab2(DstPixel, DstPixel, true);
1679 }
1680 else {
1681 CIccPCS::XyzToLab(DstPixel, DstPixel, true);
1682 }
1683 }
1684#ifndef SAMPLEICC_NOCLIPLABTOXYZ
1685 else {
1686 DstPixel[0] = CIccPCS::NegClip(DstPixel[0]);
1687 DstPixel[1] = CIccPCS::NegClip(DstPixel[1]);
1688 DstPixel[2] = CIccPCS::NegClip(DstPixel[2]);
1689 }
1690#endif
1691}
1692
1693/**
1694 **************************************************************************
1695 * Name: CIccXform::CheckSrcAbs
1696 *
1697 * Purpose:
1698 * This function will be called by a derived CIccXform object's Apply() function
1699 * BEFORE the actual xform is performed to take care of Absolute to Relative
1700 * adjustments needed by the xform (IE the PCS is always version 4 relative).
1701 *
1702 * Args:
1703 * Pixel = src pixel data (will not be modified)
1704 *
1705 * Return:
1706 * returns Pixel or adjusted pixel data.
1707 **************************************************************************
1708 */
1709const icFloatNumber *CIccXform::CheckSrcAbs(CIccApplyXform *pApply, const icFloatNumber *Pixel) const
1710{
1711 if (m_bAdjustPCS && !m_bInput && m_bSrcPcsConversion) {
1712 icFloatNumber *pAbsLab = pApply->m_AbsLab;
1713 AdjustPCS(pAbsLab, Pixel);
1714 return pAbsLab;
1715 }
1716
1717 return Pixel;
1718}
1719
1720/**
1721 **************************************************************************
1722 * Name: CIccXform::CheckDstAbs
1723 *
1724 * Purpose:
1725 * This function will be called by a derived CIccXform object's Apply() function
1726 * AFTER the actual xform is performed to take care of Absolute to Relative
1727 * adjustments needed by the xform (IE the PCS is always version 4 relative).
1728 *
1729 * Args:
1730 * Pixel = source pixel data which will be modified
1731 *
1732 **************************************************************************
1733 */
1734void CIccXform::CheckDstAbs(icFloatNumber *Pixel) const
1735{
1736 if (m_bAdjustPCS && m_bInput && m_bDstPcsConversion) {
1737 AdjustPCS(Pixel, Pixel);
1738 }
1739}
1740
1741/**
1742**************************************************************************
1743* Name: CIccXform::GetSrcSpace
1744*
1745* Purpose:
1746* Return the color space that is input to the transform.
1747* If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid
1748* confusion with PCS encoding of these spaces. Device encoding of XYZ
1749* and Lab spaces left to the device.
1750**************************************************************************
1751*/
1752icColorSpaceSignature CIccXform::GetSrcSpace() const
1753{
1755 icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass;
1756
1757 if (m_bInput) {
1758 if (m_bPcsAdjustXform)
1759 rv = m_pProfile->m_Header.pcs;
1760 else {
1761 rv = m_pProfile->m_Header.colorSpace;
1762
1763 if (deviceClass != icSigAbstractClass) {
1764 //convert signature to device colorspace signature (avoid confusion about encoding).
1765 if (rv == icSigXYZData) {
1766 rv = icSigDevXYZData;
1767 }
1768 else if (rv == icSigLabData) {
1769 rv = icSigDevLabData;
1770 }
1771 }
1772 }
1773 }
1774 else if (!m_bUseSpectralPCS || !m_pProfile->m_Header.spectralPCS) {
1775 rv = m_pProfile->m_Header.pcs;
1776 }
1777 else {
1778 rv = icGetColorSpaceType(m_pProfile->m_Header.spectralPCS);
1779 }
1780
1781 return rv;
1782}
1783
1784/**
1785**************************************************************************
1786* Name: CIccXform::GetNumSrcSamples
1787*
1788* Purpose:
1789* Return the color space that is input to the transform.
1790* If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid
1791* confusion with PCS encoding of these spaces. Device encoding of XYZ
1792* and Lab spaces left to the device.
1793**************************************************************************
1794*/
1795icUInt16Number CIccXform::GetNumSrcSamples() const
1796{
1797 icUInt16Number rv;
1798
1799 if (m_nMCS==icFromMCS) {
1800 rv = (icUInt16Number)icGetSpaceSamples((icColorSpaceSignature)m_pProfile->m_Header.mcs);
1801 }
1802 else if (m_bInput) {
1803 rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.colorSpace);
1804 }
1805 else if (!m_bUseSpectralPCS || !m_pProfile->m_Header.spectralPCS) {
1806 rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.pcs);
1807 }
1808 else {
1809 rv = (icUInt16Number)icGetSpectralSpaceSamples(&m_pProfile->m_Header);
1810 }
1811
1812 return rv;
1813}
1814
1815/**
1816**************************************************************************
1817* Name: CIccXform::GetDstSpace
1818*
1819* Purpose:
1820* Return the color space that is output by the transform.
1821* If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid
1822* confusion with PCS encoding of these spaces. Device encoding of XYZ
1823* and Lab spaces left to the device.
1824**************************************************************************
1825*/
1826icColorSpaceSignature CIccXform::GetDstSpace() const
1827{
1829 icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass;
1830
1831 if (m_nMCS==icToMCS) {
1832 rv = (icColorSpaceSignature)m_pProfile->m_Header.mcs;
1833 }
1834 else if (m_bInput) {
1835 if (m_bUseSpectralPCS && m_pProfile->m_Header.spectralPCS)
1836 rv = icGetColorSpaceType(m_pProfile->m_Header.spectralPCS);
1837 else
1838 rv = m_pProfile->m_Header.pcs;
1839 }
1840 else {
1841 rv = m_pProfile->m_Header.colorSpace;
1842
1843 //convert signature to device colorspace signature (avoid confusion about encoding).
1844 if (deviceClass != icSigAbstractClass) {
1845 if (rv==icSigXYZData) {
1846 rv = icSigDevXYZData;
1847 }
1848 else if (rv==icSigLabData) {
1849 rv = icSigDevLabData;
1850 }
1851 }
1852 }
1853
1854 return rv;
1855}
1856
1857/**
1858**************************************************************************
1859* Name: CIccXform::GetNumDstSamples
1860*
1861* Purpose:
1862* Return the color space that is input to the transform.
1863* If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid
1864* confusion with PCS encoding of these spaces. Device encoding of XYZ
1865* and Lab spaces left to the device.
1866**************************************************************************
1867*/
1868icUInt16Number CIccXform::GetNumDstSamples() const
1869{
1870 icUInt16Number rv;
1871
1872 if (m_nMCS==icToMCS) {
1873 rv = (icUInt16Number)icGetSpaceSamples((icColorSpaceSignature)m_pProfile->m_Header.mcs);
1874 }
1875 else if (!m_bInput) {
1876 rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.colorSpace);
1877 }
1878 else if (!m_bUseSpectralPCS || !m_pProfile->m_Header.spectralPCS) {
1879 rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.pcs);
1880 }
1881 else {
1882 rv = (icUInt16Number)icGetSpectralSpaceSamples(&m_pProfile->m_Header);
1883 }
1884
1885 return rv;
1886}
1887
1888
1889/**
1890**************************************************************************
1891* Name: CIccApplyXform::CIccApplyXform
1892*
1893* Purpose:
1894* Constructor
1895**************************************************************************
1896*/
1897CIccApplyXform::CIccApplyXform(CIccXform *pXform) : m_AbsLab{}
1898{
1899 m_pXform = pXform;
1900}
1901
1902/**
1903**************************************************************************
1904* Name: CIccApplyXform::CIccApplyXform
1905*
1906* Purpose:
1907* Destructor
1908**************************************************************************
1909*/
1910CIccApplyXform::~CIccApplyXform()
1911{
1912}
1913
1914
1915/**
1916**************************************************************************
1917* Name: CIccApplyNDLutXform::CIccApplyNDLutXform
1918*
1919* Purpose:
1920* Constructor
1921**************************************************************************
1922*/
1923CIccApplyNDLutXform::CIccApplyNDLutXform(CIccXformNDLut* pXform, CIccApplyCLUT *pApply) : CIccApplyXform(pXform)
1924{
1925 m_pApply = pApply;
1926}
1927
1928
1929/**
1930**************************************************************************
1931* Name: CIccApplyNDLutXform::~CIccApplyNDLutXform
1932*
1933* Purpose:
1934* Destructor
1935**************************************************************************
1936*/
1937CIccApplyNDLutXform::~CIccApplyNDLutXform()
1938{
1939 if (m_pApply)
1940 delete m_pApply;
1941}
1942
1943
1944/**
1945**************************************************************************
1946* Name: CIccApplyPcsXform::CIccApplyPcsXform
1947*
1948* Purpose:
1949* Constructor
1950**************************************************************************
1951*/
1952CIccApplyPcsXform::CIccApplyPcsXform(CIccXform *pXform) : CIccApplyXform(pXform)
1953{
1954 m_list = new CIccApplyPcsStepList();
1955 m_temp1 = NULL;
1956 m_temp2 = NULL;
1957}
1958
1959/**
1960**************************************************************************
1961* Name: CIccApplyPcsXform::~CIccApplyPcsXform
1962*
1963* Purpose:
1964* Destructor
1965**************************************************************************
1966*/
1967CIccApplyPcsXform::~CIccApplyPcsXform()
1968{
1969
1970 if (m_list) {
1971 CIccApplyPcsStepList::iterator i;
1972 for (i=m_list->begin(); i!=m_list->end(); i++) {
1973 if (i->ptr)
1974 delete i->ptr;
1975 }
1976
1977 delete m_list;
1978 }
1979
1980 if (m_temp1)
1981 delete m_temp1;
1982 if (m_temp2)
1983 delete m_temp2;
1984}
1985
1986/**
1987**************************************************************************
1988* Name: CIccApplyPcsXform::Init
1989*
1990* Purpose:
1991* Initialize temporary variables used during pcs processing
1992**************************************************************************
1993*/
1994bool CIccApplyPcsXform::Init()
1995{
1996 CIccPcsXform *pXform = (CIccPcsXform*)m_pXform;
1997 icUInt16Number nChan = pXform->MaxChannels();
1998
1999 if (nChan) {
2000 m_temp1 = new icFloatNumber[nChan];
2001 m_temp2 = new icFloatNumber[nChan];
2002 }
2003
2004 return m_temp1!=NULL && m_temp2!=NULL;
2005}
2006
2007
2008void CIccApplyPcsXform::AppendApplyStep(CIccApplyPcsStep *pStep)
2009{
2010 CIccApplyPcsStepPtr ptr;
2011
2012 if (pStep && m_list) {
2013 ptr.ptr = pStep;
2014 m_list->push_back(ptr);
2015 }
2016}
2017
2018
2019/**
2020**************************************************************************
2021* Name: CIccPcsXform::CIccPcsXform
2022*
2023* Purpose:
2024* Constructor
2025**************************************************************************
2026*/
2027CIccPcsXform::CIccPcsXform()
2028{
2029 m_list = new CIccPcsStepList();
2030
2031 m_srcSpace = icSigUnknownData;
2032 m_nSrcSamples = 0;
2033
2034 m_dstSpace = icSigUnknownData;
2035 m_nDstSamples = 0;
2036}
2037
2038/**
2039**************************************************************************
2040* Name: CIccPcsXform::~CIccPcsXform
2041*
2042* Purpose:
2043* Destructor
2044**************************************************************************
2045*/
2046CIccPcsXform::~CIccPcsXform()
2047{
2048 if (m_list) {
2049 CIccPcsStepList::iterator step;
2050 for (step=m_list->begin(); step!=m_list->end(); step++) {
2051 if (step->ptr) {
2052 delete step->ptr;
2053 step->ptr = NULL;
2054 }
2055 }
2056 delete m_list;
2057 }
2058}
2059
2060/**
2061 **************************************************************************
2062 * Name: CIccPcsXform::Connect
2063 *
2064 * Purpose:
2065 * Insert PCS transform operations to perform PCS processing between
2066 * pFromXform and pToXform
2067 **************************************************************************
2068 */
2069icStatusCMM CIccPcsXform::Connect(CIccXform *pFromXform, CIccXform *pToXform)
2070{
2071 icStatusCMM stat;
2072
2073 if (!pFromXform || !pToXform)
2074 return icCmmStatBadXform;
2075
2076 if (pFromXform->IsMCS() && pToXform->IsMCS()) {
2077 CIccProfile *pFromProfile = pFromXform->GetProfilePtr();
2078 CIccProfile *pToProfile = pToXform->GetProfilePtr();
2079
2080 if (!pFromProfile || !pToProfile) {
2081 return icCmmStatBadSpaceLink;
2082 }
2083 CIccTagArray *pFromChannels = (CIccTagArray*)(pFromProfile->FindTagOfType(icSigMaterialTypeArrayTag, icSigTagArrayType));
2084 CIccTagArray *pToChannels = (CIccTagArray*)(pToProfile->FindTagOfType(icSigMaterialTypeArrayTag, icSigTagArrayType));
2085
2086 if (!pFromChannels || !pToChannels) {
2087 return icCmmStatBadSpaceLink;
2088 }
2089 if (pFromChannels->GetTagArrayType()!=icSigUtf8TextTypeArray ||
2090 pToChannels->GetTagArrayType()!=icSigUtf8TextTypeArray ||
2091 !pFromChannels->AreAllOfType(icSigUtf8TextType) ||
2092 !pToChannels->AreAllOfType(icSigUtf8TextType)) {
2093 return icCmmStatBadSpaceLink;
2094 }
2095
2096 m_nSrcSamples = pFromXform->GetNumDstSamples();
2097 m_nDstSamples = pToXform->GetNumSrcSamples();
2098
2099 if (pFromChannels->GetSize() != m_nSrcSamples || pToChannels->GetSize() != m_nDstSamples) {
2100 return icCmmStatBadSpaceLink;
2101 }
2102 int i, j;
2103
2104 if (pFromProfile->m_Header.flags&icMCSNeedsSubsetTrue) {
2105 for (i=0; i<m_nSrcSamples; i++) {
2106 const icUChar *szSrcChan = ((CIccTagUtf8Text*)pFromChannels->GetIndex(i))->GetText();
2107 for (j=0; j<m_nDstSamples; j++) {
2108 const icUChar *szDstChan = ((CIccTagUtf8Text*)pToChannels->GetIndex(i))->GetText();
2109 if (!icUtf8StrCmp(szSrcChan, szDstChan))
2110 break;
2111 }
2112 if (j==m_nDstSamples)
2113 return icCmmStatBadMCSLink;
2114 }
2115 }
2116
2117 if (pToProfile->m_Header.flags&icMCSNeedsSubsetTrue) {
2118 for (i=0; i<m_nDstSamples; i++) {
2119 const icUChar *szDstChan = ((CIccTagUtf8Text*)pToChannels->GetIndex(i))->GetText();
2120 for (j=0; j<m_nSrcSamples; j++) {
2121 const icUChar *szSrcChan = ((CIccTagUtf8Text*)pFromChannels->GetIndex(i))->GetText();
2122 if (!icUtf8StrCmp(szSrcChan, szDstChan))
2123 break;
2124 }
2125 if (j==m_nSrcSamples)
2126 return icCmmStatBadMCSLink;
2127 }
2128 }
2129 CIccTag *pTag = pToProfile->FindTag(icSigMaterialDefaultValuesTag);
2130 CIccTagNumArray *pDefaults = NULL;
2131 if (pTag && pTag->IsNumArrayType()) {
2132 pDefaults = (CIccTagNumArray *)pTag;
2133 }
2134
2135 pushRouteMcs(pFromChannels, pToChannels, pDefaults);
2136 }
2137 else {
2138 if (!pFromXform->IsInput() || (pToXform->IsInput() && !pToXform->IsAbstract())) {
2139 return icCmmStatBadSpaceLink;
2140 }
2141
2142 m_srcSpace = pFromXform->GetDstSpace();
2143 if (IsSpaceSpectralPCS(m_srcSpace))
2144 m_srcSpace = icGetColorSpaceType(m_srcSpace);
2145
2146 m_nSrcSamples = pFromXform->GetNumDstSamples();
2147
2148 m_dstSpace = pToXform->GetSrcSpace();
2149 if (IsSpaceSpectralPCS(m_dstSpace))
2150 m_dstSpace = icGetColorSpaceType(m_dstSpace);
2151
2152 m_nDstSamples = pToXform->GetNumSrcSamples();
2153
2154 switch (m_srcSpace) {
2155 case icSigLabPcsData:
2156 switch (m_dstSpace) {
2157 case icSigLabPcsData:
2158 if (pFromXform->UseLegacyPCS())
2159 pushLab2ToXyz(pFromXform->m_pConnectionConditions);
2160 else
2161 pushLabToXyz(pFromXform->m_pConnectionConditions);
2162 if (pFromXform->NeedAdjustPCS()) {
2163 pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]);
2164 pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]);
2165 }
2166 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2167 return stat;
2168 }
2169 if (pToXform->NeedAdjustPCS()) {
2170 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2171 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2172 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2173 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2174 }
2175 if (pToXform->UseLegacyPCS())
2176 pushXyzToLab2(pToXform->m_pConnectionConditions);
2177 else
2178 pushXyzToLab(pToXform->m_pConnectionConditions);
2179 break;
2180
2181 case icSigXYZPcsData:
2182 if (pFromXform->UseLegacyPCS())
2183 pushLab2ToXyz(pFromXform->m_pConnectionConditions);
2184 else
2185 pushLabToXyz(pFromXform->m_pConnectionConditions);
2186 if (pFromXform->NeedAdjustPCS()) {
2187 pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]);
2188 pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]);
2189 }
2190 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2191 return stat;
2192 }
2193 if (pToXform->NeedAdjustPCS()) {
2194 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2195 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2196 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2197 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2198 }
2199 pushXyzToXyzIn();
2200 break;
2201
2208 }
2209 break;
2210
2211 case icSigXYZPcsData:
2212 switch (m_dstSpace) {
2213 case icSigLabPcsData:
2214 pushXyzInToXyz();
2215 if (pFromXform->NeedAdjustPCS()) {
2216 pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]);
2217 pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]);
2218 }
2219 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2220 return stat;
2221 }
2222 if (pToXform->NeedAdjustPCS()) {
2223 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2224 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2225 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2226 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2227 }
2228 if (pToXform->UseLegacyPCS())
2229 pushXyzToLab2(pToXform->m_pConnectionConditions);
2230 else
2231 pushXyzToLab(pToXform->m_pConnectionConditions);
2232 break;
2233
2234 case icSigXYZPcsData:
2235 pushXyzInToXyz();
2236 if (pFromXform->NeedAdjustPCS()) {
2237 pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]);
2238 pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]);
2239 }
2240 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2241 return stat;
2242 }
2243 if (pToXform->NeedAdjustPCS()) {
2244 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2245 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2246 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2247 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2248 }
2249 pushXyzToXyzIn();
2250 break;
2251
2258 }
2259 break;
2260
2263 switch (m_dstSpace) {
2264 case icSigLabPcsData:
2265 pushRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions);
2266 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2267 return stat;
2268 }
2269 if (pToXform->NeedAdjustPCS()) {
2270 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2271 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2272 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2273 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2274 }
2275 if (pToXform->UseLegacyPCS())
2276 pushXyzToLab2(pToXform->m_pConnectionConditions);
2277 else
2278 pushXyzToLab(pToXform->m_pConnectionConditions);
2279 break;
2280
2281 case icSigXYZPcsData:
2282 pushRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions);
2283 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2284 return stat;
2285 }
2286 if (pToXform->NeedAdjustPCS()) {
2287 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2288 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2289 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2290 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2291 }
2292 pushXyzToXyzIn();
2293 break;
2294
2297 pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange,
2298 pToXform->m_pProfile->m_Header.spectralRange);
2299 break;
2300
2302 pushApplyIllum(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions);
2303 pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange,
2304 pToXform->m_pProfile->m_Header.spectralRange);
2305 break;
2306
2310 }
2311 break;
2312
2314 CIccProfile *pFromProfile = pFromXform->GetProfilePtr();
2315 CIccProfile *pToProfile = pToXform->GetProfilePtr();
2316
2317 switch (m_dstSpace) {
2318 case icSigLabPcsData:
2319 pushRad2Xyz(pFromProfile, pFromXform->m_pConnectionConditions, false);
2320 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2321 return stat;
2322 }
2323 if (pToXform->NeedAdjustPCS()) {
2324 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2325 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2326 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2327 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2328 }
2329 if (pToXform->UseLegacyPCS())
2330 pushXyzToLab2(pToXform->m_pConnectionConditions);
2331 else
2332 pushXyzToLab(pToXform->m_pConnectionConditions);
2333 break;
2334
2335 case icSigXYZPcsData:
2336 pushRad2Xyz(pFromProfile, pFromXform->m_pConnectionConditions, false);
2337 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2338 return stat;
2339 }
2340 if (pToXform->NeedAdjustPCS()) {
2341 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2342 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2343 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2344 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2345 }
2346 pushXyzToXyzIn();
2347 break;
2348
2352
2353
2355 pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange,
2356 pToXform->m_pProfile->m_Header.spectralRange);
2357 break;
2358
2362 }
2363 }
2364 break;
2365
2368 switch (m_dstSpace) {
2369 case icSigLabPcsData:
2370 pushBiRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions);
2371 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2372 return stat;
2373 }
2374 if (pToXform->NeedAdjustPCS()) {
2375 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2376 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2377 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2378 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2379 }
2380 if (pToXform->UseLegacyPCS())
2381 pushXyzToLab2(pToXform->m_pConnectionConditions);
2382 else
2383 pushXyzToLab(pToXform->m_pConnectionConditions);
2384 break;
2385
2386 case icSigXYZPcsData:
2387 if ((stat=pushBiRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions))!=icCmmStatOk) {
2388 return stat;
2389 }
2390 if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) {
2391 return stat;
2392 }
2393 if (pToXform->NeedAdjustPCS()) {
2394 pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0],
2395 pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1],
2396 pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]);
2397 pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]);
2398 }
2399 pushXyzToXyzIn();
2400 break;
2401
2404 if ((stat=pushBiRef2Ref(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions))!=icCmmStatOk) {
2405 return stat;
2406 }
2407 pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange,
2408 pToXform->m_pProfile->m_Header.spectralRange);
2409 break;
2410
2412 if ((stat=pushBiRef2Rad(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions))!=icCmmStatOk) {
2413 return stat;
2414 }
2415 pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange,
2416 pToXform->m_pProfile->m_Header.spectralRange);
2417 break;
2418
2420 if (icSameSpectralRange(pFromXform->m_pProfile->m_Header.spectralRange, pToXform->m_pProfile->m_Header.spectralRange) &&
2421 icSameSpectralRange(pFromXform->m_pProfile->m_Header.biSpectralRange, pToXform->m_pProfile->m_Header.biSpectralRange))
2422 break;
2423 else
2425
2428 }
2429 break;
2430 }
2431 }
2432
2433 icStatusCMM rv = Optimize();
2434 if (rv!=icCmmStatOk)
2435 return rv;
2436
2437 if (m_list->begin()==m_list->end())
2439
2440 return icCmmStatOk;
2441}
2442
2443
2444/**
2445 **************************************************************************
2446 * Name: CIccPcsXform::Optimize
2447 *
2448 * Purpose:
2449 * Analyzes and concatenates/removes transforms in pcs transformation chain
2450 **************************************************************************
2451 */
2452icStatusCMM CIccPcsXform::Optimize()
2453{
2454 if (!m_list)
2455 return icCmmStatBadXform;
2456
2457 CIccPcsStepList steps = *m_list;
2458 CIccPcsStepList::iterator next, last;
2459 bool done=false;
2460
2461#if 0
2462 std::string str;
2463 for (next = steps.begin(); next != steps.end(); next++) {
2464 next->ptr->dump(str);
2465 }
2466 printf("PCS_Steps:\n%s", str.c_str());
2467#endif
2468
2469 while (!done) {
2470 CIccPcsStepList newSteps;
2471 CIccPcsStepPtr ptr;
2472
2473 done = true;
2474
2475 next = steps.begin();
2476 if (next==steps.end()) {
2477 *m_list = steps;
2479 }
2480 last = next;
2481 next++;
2482
2483 ptr.ptr = last->ptr;
2484
2485 for (;next!=steps.end(); next++) {
2486 CIccPcsStep *pStep = ptr.ptr->concat(next->ptr);
2487
2488 if (pStep) {
2489 done = false;
2490
2491 delete ptr.ptr;
2492 delete next->ptr;
2493 ptr.ptr = pStep;
2494 }
2495 else {
2496 if (!ptr.ptr->isIdentity()) {
2497 newSteps.push_back(ptr);
2498 }
2499 ptr.ptr = next->ptr;
2500 }
2501 }
2502 if (!ptr.ptr->isIdentity()) {
2503 newSteps.push_back(ptr);
2504 }
2505
2506 steps = newSteps;
2507
2508// for (next=steps.begin(); next!=steps.end(); next++) {
2509// ptr.ptr = next->ptr;
2510// done = true;
2511// }
2512
2513 }
2514
2515 if (!steps.empty()) {
2516 CIccPcsStepList newSteps;
2517 CIccPcsStepPtr ptr;
2518
2519 for (next=steps.begin(); next != steps.end(); next++) {
2520 ptr.ptr = next->ptr->reduce();
2521 if (ptr.ptr != next->ptr)
2522 delete next->ptr;
2523 newSteps.push_back(ptr);
2524 }
2525 steps = newSteps;
2526 }
2527
2528 *m_list = steps;
2529
2530 return icCmmStatOk;
2531}
2532
2533
2534/**
2535 **************************************************************************
2536 * Name: CIccPcsXform::GetNewApply
2537 *
2538 * Purpose:
2539 * Allocates a CIccApplyXform based object that can store local data for
2540 * processing (needed by CIccPcsStepMpe).
2541 **************************************************************************
2542 */
2543CIccApplyXform *CIccPcsXform::GetNewApply(icStatusCMM &status)
2544{
2545 CIccApplyPcsXform *pNew = new CIccApplyPcsXform(this);
2546
2547 if (pNew) {
2548 if (!pNew->Init()) {
2549 delete pNew;
2550 status = icCmmStatAllocErr;
2551 return NULL;
2552 }
2553 }
2554 else {
2555 status = icCmmStatAllocErr;
2556 return NULL;
2557 }
2558
2559 CIccPcsStepList::iterator i;
2560 CIccApplyPcsStep *pStep;
2561
2562 for (i=m_list->begin(); i!=m_list->end(); i++) {
2563 pStep = i->ptr->GetNewApply();
2564 if (!pStep || status != icCmmStatOk) {
2565 delete pNew;
2566 return NULL;
2567 }
2568 pNew->AppendApplyStep(pStep);
2569 }
2570
2571 return pNew;
2572}
2573
2574
2575/**
2576 **************************************************************************
2577 * Name: CIccPcsXform::MaxChannels
2578 *
2579 * Purpose:
2580 * Returns the maximum number of channels used by PCS xform steps
2581 **************************************************************************
2582 */
2583icUInt16Number CIccPcsXform::MaxChannels()
2584{
2585 icUInt16Number nMax = 0;
2586 CIccPcsStepList::const_iterator s = m_list->begin();
2587 if (s==m_list->end())
2588 return nMax;
2589 nMax = s->ptr->GetDstChannels();
2590 s++;
2591 for (; s!= m_list->end(); s++) {
2592 if (s->ptr->GetSrcChannels()>nMax)
2593 nMax = s->ptr->GetSrcChannels();
2594 }
2595 return nMax;
2596}
2597
2598/**
2599 **************************************************************************
2600 * Name: CIccPcsXform::pushRouteMcs
2601 *
2602 * Purpose:
2603 * Insert PCS step that routes MCS channel data from one profile to another
2604 **************************************************************************
2605 */
2606void CIccPcsXform::pushRouteMcs(CIccTagArray *pSrcChannels, CIccTagArray *pDstChannels, CIccTagNumArray *pDefaults)
2607{
2608 CIccPcsStepPtr ptr;
2609
2610 ptr.ptr = new CIccPcsStepRouteMcs(pSrcChannels, pDstChannels, pDefaults);
2611 m_list->push_back(ptr);
2612}
2613
2614
2615/**
2616 **************************************************************************
2617 * Name: CIccPcsXform::pushLab2ToXyz
2618 *
2619 * Purpose:
2620 * Insert PCS step that converts from V2 Lab internal to actual XYZ
2621 **************************************************************************
2622 */
2623void CIccPcsXform::pushLab2ToXyz( IIccProfileConnectionConditions *pPCC)
2624{
2625 icFloatNumber xyzWhite[3];
2626 pPCC->getNormIlluminantXYZ(xyzWhite);
2627
2628 CIccPcsStepPtr ptr;
2629
2630 ptr.ptr = new CIccPcsStepLab2ToXYZ(xyzWhite);
2631 m_list->push_back(ptr);
2632}
2633
2634
2635/**
2636 **************************************************************************
2637 * Name: CIccPcsXform::pushXyzToLab2
2638 *
2639 * Purpose:
2640 * Insert PCS step that converts from actual XYZ to V2 Lab internal
2641 **************************************************************************
2642 */
2643void CIccPcsXform::pushXyzToLab2(IIccProfileConnectionConditions *pPCC)
2644{
2645 icFloatNumber xyzWhite[3];
2646 pPCC->getNormIlluminantXYZ(xyzWhite);
2647
2648 CIccPcsStepPtr ptr;
2649
2650 ptr.ptr = new CIccPcsStepXYZToLab2(xyzWhite);
2651 m_list->push_back(ptr);
2652}
2653
2654
2655/**
2656 **************************************************************************
2657 * Name: CIccPcsXform::pushLabToXyz
2658 *
2659 * Purpose:
2660 * Insert PCS step that converts from V4 Lab internal to actual XYZ
2661 **************************************************************************
2662 */
2663void CIccPcsXform::pushLabToXyz(IIccProfileConnectionConditions *pPCC)
2664{
2665 icFloatNumber xyzWhite[3];
2666 pPCC->getNormIlluminantXYZ(xyzWhite);
2667
2668 CIccPcsStepPtr ptr;
2669
2670 ptr.ptr = new CIccPcsStepLabToXYZ(xyzWhite);
2671 m_list->push_back(ptr);
2672}
2673
2674
2675/**
2676 **************************************************************************
2677 * Name: CIccPcsXform::pushXyzToLab
2678 *
2679 * Purpose:
2680 * Insert PCS step that converts from actual XYZ to V4 Lab internal
2681 **************************************************************************
2682 */
2683void CIccPcsXform::pushXyzToLab( IIccProfileConnectionConditions *pPCC)
2684{
2685 icFloatNumber xyzWhite[3];
2686 pPCC->getNormIlluminantXYZ(xyzWhite);
2687
2688 CIccPcsStepPtr ptr;
2689
2690 ptr.ptr = new CIccPcsStepXYZToLab(xyzWhite);
2691 m_list->push_back(ptr);
2692}
2693
2694/**
2695 **************************************************************************
2696 * Name: CIccPcsXform::pushScale3
2697 *
2698 * Purpose:
2699 * Insert PCS step that individually scaled three channels (conceptually
2700 * equivalent to inserting a 3x3 diagonal matrix).
2701 **************************************************************************
2702 */
2703void CIccPcsXform::pushScale3(icFloatNumber v1, icFloatNumber v2, icFloatNumber v3)
2704{
2705 CIccPcsStepScale *scale;
2706 CIccPcsStepPtr ptr;
2707
2708 scale = new CIccPcsStepScale(3);
2709 icFloatNumber *data = scale->data();
2710 data[0] = v1;
2711 data[1] = v2;
2712 data[2] = v3;
2713
2714 ptr.ptr = scale;
2715 m_list->push_back(ptr);
2716}
2717
2718/**
2719 **************************************************************************
2720 * Name: CIccPcsXform::pushXyzToXyzIn
2721 *
2722 * Purpose:
2723 * Insert PCS step that converts from actual XYZ to internal XYZ
2724 **************************************************************************
2725 */
2726void CIccPcsXform::pushXyzToXyzIn()
2727{
2728 icFloatNumber scale = (icFloatNumber) (32768.0 / 65535.0);
2729 pushScale3(scale, scale, scale);
2730}
2731
2732
2733/**
2734 **************************************************************************
2735 * Name: CIccPcsXform::pushXyzInToXyz
2736 *
2737 * Purpose:
2738 * Insert PCS step that converts from internal XYZ to actual XYZ
2739 **************************************************************************
2740 */
2741void CIccPcsXform::pushXyzInToXyz()
2742{
2743 icFloatNumber scale = (icFloatNumber) (65535.0 / 32768.0);
2744 return pushScale3(scale, scale, scale);
2745}
2746
2747
2748/**
2749**************************************************************************
2750* Name: CIccPcsXform::pushXyzToXyzLum
2751*
2752* Purpose:
2753* Insert PCS step that converts from normalized XYZ to XYZ Luminance
2754**************************************************************************
2755*/
2756void CIccPcsXform::pushXyzToXyzLum(IIccProfileConnectionConditions *pPCC)
2757{
2758 icFloatNumber XYZLum[3];
2759 pPCC->getLumIlluminantXYZ(&XYZLum[0]);
2760
2761 icFloatNumber scale = XYZLum[1];
2762
2763 return pushScale3(scale, scale, scale);
2764}
2765
2766
2767/**
2768**************************************************************************
2769* Name: CIccPcsXform::pushXyzLumToXyz
2770*
2771* Purpose:
2772* Insert PCS step that converts from XYZ Luminance to normalized XYZ
2773**************************************************************************
2774*/
2775void CIccPcsXform::pushXyzLumToXyz(IIccProfileConnectionConditions *pPCC)
2776{
2777 icFloatNumber XYZLum[3];
2778 pPCC->getLumIlluminantXYZ(&XYZLum[0]);
2779
2780 icFloatNumber scale = 1.0f / XYZLum[1];
2781
2782 return pushScale3(scale, scale, scale);
2783}
2784
2785
2786/**
2787 **************************************************************************
2788 * Name: CIccPcsXform::pushXyzToXyzIn
2789 *
2790 * Purpose:
2791 * Insert PCS step that adds an offset to 3 channels. If bConvertIntXyzOffset
2792 * is true the the offset is assumed to be in Internal XYZ format and
2793 * will be converted to be an actual XYZ offset.
2794 **************************************************************************
2795 */
2796void CIccPcsXform::pushOffset3(icFloatNumber v1, icFloatNumber v2, icFloatNumber v3, bool bConvertIntXyzOffset/*=true*/)
2797{
2798 CIccPcsStepOffset *offset;
2799 CIccPcsStepPtr ptr;
2800
2801 offset = new CIccPcsStepOffset(3);
2802 icFloatNumber *data = offset->data();
2803 if (bConvertIntXyzOffset) {
2804 data[0] = v1*65535.0f/32768.0f;
2805 data[1] = v2*65535.0f/32768.0f;
2806 data[2] = v3*65535.0f/32768.0f;
2807 }
2808 else {
2809 data[0] = v1;
2810 data[1] = v2;
2811 data[2] = v3;
2812 }
2813
2814 ptr.ptr = offset;
2815 m_list->push_back(ptr);
2816}
2817
2818
2819/**
2820 **************************************************************************
2821 * Name: CIccPcsXform::pushScale
2822 *
2823 * Purpose:
2824 * Insert PCS step that individually n channels (conceptually
2825 * equivalent to inserting a nxn diagonal matrix).
2826 **************************************************************************
2827 */
2828void CIccPcsXform::pushScale(icUInt16Number n, const icFloatNumber *vals)
2829{
2830 CIccPcsStepScale *scale = new CIccPcsStepScale(n);
2831 memcpy(scale->data(), vals, n*sizeof(icFloatNumber));
2832
2833 CIccPcsStepPtr ptr;
2834 ptr.ptr = scale;
2835 m_list->push_back(ptr);
2836}
2837
2838
2839/**
2840 **************************************************************************
2841 * Name: CIccPcsXform::pushMatrix
2842 *
2843 * Purpose:
2844 * Insert PCS step defined by a nRows x nCols matrix with specified vals
2845 **************************************************************************
2846 */
2847void CIccPcsXform::pushMatrix(icUInt16Number nRows, icUInt16Number nCols, const icFloatNumber *vals)
2848{
2849 CIccPcsStepMatrix *mtx = new CIccPcsStepMatrix(nRows, nCols);
2850 memcpy(mtx->entry(0), vals, nRows*nCols*sizeof(icFloatNumber));
2851
2852 CIccPcsStepPtr ptr;
2853 ptr.ptr = mtx;
2854 m_list->push_back(ptr);
2855}
2856
2857
2858/**
2859 **************************************************************************
2860 * Name: CIccPcsXform::pushXYZConvert
2861 *
2862 * Purpose:
2863 * Insert PCS step that converts from source XYZ colorimetry to dest XYZ
2864 * colorimetry accounting for possible changes in illuminant and/or observer.
2865 * Luminance matching is also accounted for.
2866 **************************************************************************
2867 */
2868icStatusCMM CIccPcsXform::pushXYZConvert(CIccXform *pFromXform, CIccXform *pToXform)
2869{
2870 IIccProfileConnectionConditions *pSrcPcc = pFromXform->GetConnectionConditions();
2871 IIccProfileConnectionConditions *pDstPcc = pToXform->GetConnectionConditions();
2872
2873 if (!pSrcPcc || !pDstPcc)
2875
2876 //If source and dest observer and illuminant are same then no transform is needed
2877 if (pSrcPcc->isEquivalentPcc(*pDstPcc)) {
2878 return icCmmStatOk;
2879 }
2880
2881 CIccPcsStepPtr ptr;
2882
2883 if (!pSrcPcc->isStandardPcc()) {
2884
2886
2887 if (!pMpe || pMpe->NumInputChannels()!=3 || pMpe->NumOutputChannels()!=3)
2888 return icCmmStatBadSpaceLink;
2889
2890 ptr.ptr = NULL;
2891
2892 //push single matrix element as a CIccPcsStepMatrix so it can be optimized
2893 if (pMpe->NumElements()==1) {
2894 CIccMultiProcessElement *pElem = pMpe->GetElement(0);
2895 if (pElem) {
2896 if (pElem->GetType()==icSigMatrixElemType) {
2897 CIccMpeMatrix *pMatElem = (CIccMpeMatrix*)pElem;
2898
2899 icFloatNumber *pMat = pMatElem->GetMatrix();
2900 icFloatNumber *pOffset = pMatElem->GetConstants();
2901
2902 if (pMat && (!pOffset || (pOffset[0]==0.0 && pOffset[1]==0.0 && pOffset[2]==0.0))) {
2903 CIccPcsStepMatrix *pStepMtx = new CIccPcsStepMatrix(3, 3);
2904
2905 if (pStepMtx ) {
2906 memcpy(pStepMtx->entry(0,0), pMat, 9*sizeof(icFloatNumber));
2907 }
2908 ptr.ptr = pStepMtx;
2909 }
2910 }
2911 }
2912 }
2913
2914 if (!ptr.ptr) {
2915 CIccPcsStepMpe *pStepMpe = new CIccPcsStepMpe((CIccTagMultiProcessElement*)pMpe->NewCopy());
2916
2917 if (!pStepMpe)
2918 return icCmmStatAllocErr;
2919
2920 if (!pStepMpe->Begin()) {
2921 delete pStepMpe;
2923 }
2924
2925 ptr.ptr = pStepMpe;
2926 }
2927
2928 m_list->push_back(ptr);
2929 }
2930
2931 if (!pDstPcc->isStandardPcc()) {
2932
2934
2935 if (!pMpe || pMpe->NumInputChannels()!=3 || pMpe->NumOutputChannels()!=3)
2936 return icCmmStatBadSpaceLink;
2937
2938 ptr.ptr = NULL;
2939
2940 //push single matrix element as a CIccPcsStepMatrix so it can be optimized
2941 if (pMpe->NumElements()==1) {
2942 CIccMultiProcessElement *pElem = pMpe->GetElement(0);
2943 if (pElem) {
2944 if (pElem->GetType()==icSigMatrixElemType) {
2945 CIccMpeMatrix *pMatElem = (CIccMpeMatrix*)pElem;
2946
2947 icFloatNumber *pMat = pMatElem->GetMatrix();
2948 icFloatNumber *pOffset = pMatElem->GetConstants();
2949
2950 if (pMat && (!pOffset || (pOffset[0]==0.0 && pOffset[1]==0.0 && pOffset[2]==0.0))) {
2951 CIccPcsStepMatrix *pStepMtx = new CIccPcsStepMatrix(3, 3);
2952
2953 if (pStepMtx ) {
2954 memcpy(pStepMtx->entry(0,0), pMat, 9*sizeof(icFloatNumber));
2955 }
2956 ptr.ptr = pStepMtx;
2957 }
2958 }
2959 }
2960 }
2961
2962 if (!ptr.ptr) {
2963 CIccPcsStepMpe *pStepMpe = new CIccPcsStepMpe((CIccTagMultiProcessElement*)pMpe->NewCopy());
2964
2965 if (!pStepMpe)
2966 return icCmmStatAllocErr;
2967
2968 if (!pStepMpe->Begin()) {
2969 delete pStepMpe;
2971 }
2972
2973 ptr.ptr = pStepMpe;
2974 }
2975
2976 m_list->push_back(ptr);
2977 }
2978
2979 if (pFromXform->LuminanceMatching()) {
2980 pushXyzToXyzLum(pSrcPcc);
2981 }
2982 if (pToXform->LuminanceMatching()) {
2983 pushXyzLumToXyz(pDstPcc);
2984 }
2985
2986 return icCmmStatOk;
2987}
2988
2989void CIccPcsXform::pushXYZNormalize(IIccProfileConnectionConditions *pPcc, const icSpectralRange &srcRange, const icSpectralRange &dstRange)
2990{
2992 CIccPcsXform tmp;
2993
2994 icSpectralRange illuminantRange;
2995 const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange);
2996
2997 icSpectralRange observerRange;
2998 const icFloatNumber *observer = pView->getObserver(observerRange);
2999
3000 //make sure illuminant goes through identical conversion steps
3001 if (!icSameSpectralRange(srcRange, illuminantRange) || !icSameSpectralRange(dstRange, illuminantRange)) {
3002 tmp.pushSpecToRange(illuminantRange, srcRange);
3003 tmp.pushSpecToRange(srcRange, dstRange);
3004 tmp.pushSpecToRange(dstRange, observerRange);
3005 }
3006 else {
3007 tmp.pushSpecToRange(illuminantRange, observerRange);
3008 }
3009 tmp.pushMatrix(3, observerRange.steps, observer);
3010
3012 CIccApplyXform *pApply = tmp.GetNewApply(stat);
3013 if (pApply) {
3014 icFloatNumber xyz[3], normxyz[3], pccxyz[3];
3015
3016 //Get absolute xyz for illuminant and observer
3017 tmp.Apply(pApply, xyz, illuminant);
3018
3019 //calculate normalized XYZ
3020 normxyz[0] = xyz[0] / xyz[1];
3021 normxyz[1] = xyz[1] / xyz[1];
3022 normxyz[2] = xyz[2] / xyz[1];
3023
3024 //get desired XYZ from pcc (might be slightly different from calculated normxyz)
3025 pPcc->getNormIlluminantXYZ(pccxyz);
3026
3027#if 1
3028 //push scale factor to normalize XYZ values and correct for difference between calculated and desired XYZ
3029 pushScale3(pccxyz[0] / (normxyz[0] * xyz[1]),
3030 pccxyz[1] / (normxyz[1] * xyz[1]),
3031 pccxyz[2] / (normxyz[2] * xyz[1]));
3032#else
3033 pushScale3(1.0f/xyz[1], 1.0f/xyz[1], 1.0f/xyz[1]);
3034#endif
3035
3036 delete pApply;
3037 }
3038}
3039
3040/**
3041 **************************************************************************
3042 * Name: CIccPcsXform::pushRef2Xyz
3043 *
3044 * Purpose:
3045 * Insert PCS step that convert reflectance to XYZ colorimetry defined by the
3046 * observer and illuminant accessed through the Profile Connections Conditions
3047 * handle pPcc.
3048 **************************************************************************
3049 */
3050void CIccPcsXform::pushRef2Xyz(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc)
3051{
3053
3054 if (pView) {
3055 icSpectralRange illuminantRange;
3056 const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange);
3057
3058 icSpectralRange observerRange;
3059 const icFloatNumber *observer = pView->getObserver(observerRange);
3060
3061 pushSpecToRange(pProfile->m_Header.spectralRange, illuminantRange);
3062 pushScale(illuminantRange.steps, illuminant);
3063 pushSpecToRange(illuminantRange, observerRange);
3064 pushMatrix(3, observerRange.steps, observer);
3065
3066 pushXYZNormalize(pPcc, illuminantRange, illuminantRange);
3067 }
3068}
3069
3070
3071/**
3072 **************************************************************************
3073 * Name: CIccPcsXform::rangeMap
3074 *
3075 * Purpose:
3076 * This helper function generates a PCS step matrix that can be used to convert
3077 * spectral vectors from one spectral range to another using linear interpolation.
3078 **************************************************************************
3079 */
3080CIccPcsStepMatrix *CIccPcsXform::rangeMap(const icSpectralRange &srcRange, const icSpectralRange &dstRange)
3081{
3082 if (srcRange.steps != dstRange.steps ||
3083 srcRange.start != dstRange.start ||
3084 srcRange.end != dstRange.end) {
3085 CIccPcsStepMatrix *mtx = new CIccPcsStepMatrix(dstRange.steps, srcRange.steps);
3086 if (!mtx->SetRange(srcRange, dstRange))
3087 {
3088 delete mtx;
3089 return NULL;
3090 }
3091 return mtx;
3092 }
3093
3094 return NULL;
3095}
3096
3097
3098/**
3099 **************************************************************************
3100 * Name: CIccPcsXform::pushSpecToRange
3101 *
3102 * Purpose:
3103 * Insert PCS step that res-samples spectral vector data from a source spectral
3104 * range to a destination spectral range.
3105 **************************************************************************
3106 */
3107void CIccPcsXform::pushSpecToRange(const icSpectralRange &srcRange, const icSpectralRange &dstRange)
3108{
3109 if (!icSameSpectralRange(srcRange, dstRange)) {
3110 CIccPcsStepPtr ptr;
3111 ptr.ptr = rangeMap(srcRange, dstRange);
3112
3113 if (ptr.ptr)
3114 m_list->push_back(ptr);
3115 }
3116}
3117
3118
3119/**
3120 **************************************************************************
3121 * Name: CIccPcsXform::pushApplyIllum
3122 *
3123 * Purpose:
3124 * Insert PCS step that applies an illuminant to incoming spectral transmissive
3125 * vectors to . Illuminant from Profile Connection
3126 * Conditions will be resampled to match the sampling range of the incoming
3127 * vectors.
3128 **************************************************************************
3129 */
3130void CIccPcsXform::pushApplyIllum(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc)
3131{
3133
3134 if (pView) {
3135 CIccPcsStepPtr ptr;
3136
3137 icSpectralRange illuminantRange;
3138 const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange);
3139
3140 CIccPcsStepScale *pScale = new CIccPcsStepScale(illuminantRange.steps);
3141 memcpy(pScale->data(), illuminant, illuminantRange.steps*sizeof(icFloatNumber));
3142
3143 if (icSameSpectralRange(pProfile->m_Header.spectralRange, illuminantRange)) {
3144 ptr.ptr = pScale;
3145 m_list->push_back(ptr);
3146 }
3147 else {
3148 ptr.ptr = rangeMap(pProfile->m_Header.spectralRange, illuminantRange);
3149 if (ptr.ptr) {
3150 m_list->push_back(ptr);
3151 }
3152
3153 ptr.ptr = pScale;
3154 m_list->push_back(ptr);
3155
3156 ptr.ptr = rangeMap(illuminantRange, pProfile->m_Header.spectralRange);
3157 if (ptr.ptr)
3158 m_list->push_back(ptr);
3159 }
3160 }
3161}
3162
3163
3164/**
3165 **************************************************************************
3166 * Name: CIccPcsXform::pushRad2Xyz
3167 *
3168 * Purpose:
3169 * Insert PCS step that converts from source spectral radiometric vectors to
3170 * actual XYZ colorimetry based upon observer information in Profile
3171 * Connection Conditions.
3172 **************************************************************************
3173 */
3174void CIccPcsXform::pushRad2Xyz(CIccProfile* pProfile, IIccProfileConnectionConditions *pPcc, bool bAbsoluteCIEColorimetry)
3175{
3176 const CIccTagSpectralViewingConditions *pProfView = pProfile ? pProfile->getPccViewingConditions() : NULL;
3178 if (pProfView && pView) {
3179 icSpectralRange illuminantRange;
3180 const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange);
3181
3182 icSpectralRange observerRange;
3183 const icFloatNumber *observer = pView->getObserver(observerRange);
3184
3185 //Preserve smallest step size
3186 icFloatNumber dPCSStepSize = (icF16toF(pProfile->m_Header.spectralRange.end) - icF16toF(pProfile->m_Header.spectralRange.start))/(icFloatNumber)pProfile->m_Header.spectralRange.steps;
3187 icFloatNumber dObsStepSize = (icF16toF(observerRange.end) - icF16toF(observerRange.start)) / (icFloatNumber) observerRange.steps;
3188
3189 if (dPCSStepSize<dObsStepSize) {
3190 icFloatNumber *obs = pView->applyRangeToObserver(pProfile->m_Header.spectralRange);
3191
3192 pushMatrix(3, pProfile->m_Header.spectralRange.steps, obs);
3193 free(obs);
3194 }
3195 else {
3196 pushSpecToRange(pProfile->m_Header.spectralRange, observerRange);
3197 pushMatrix(3, observerRange.steps, observer);
3198
3199 }
3200 icFloatNumber k;
3201 if (bAbsoluteCIEColorimetry) {
3202 k = 683;
3203 }
3204 else {
3205 k = 1.0f / pPcc->getObserverWhiteScaleFactor(illuminant, illuminantRange);
3206 }
3207 pushScale3(k, k, k);
3208 }
3209}
3210
3211
3212/**
3213 **************************************************************************
3214 * Name: CIccPcsXform::pushBiRef2Rad
3215 *
3216 * Purpose:
3217 * Insert PCS steps that apply an illuminant to incoming bi-spectral reflectance
3218 * matrices to get estimate of light "reflected" by surface.
3219 **************************************************************************
3220 */
3221icStatusCMM CIccPcsXform::pushBiRef2Rad(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc)
3222{
3224
3225 if (pView) {
3226 icSpectralRange illuminantRange;
3227 const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange);
3228
3229 if (icGetColorSpaceType(pProfile->m_Header.spectralPCS)==icSigSparseMatrixSpectralPcsData) {
3230 CIccPcsStepSrcSparseMatrix *pMtx = new CIccPcsStepSrcSparseMatrix(pProfile->m_Header.spectralRange.steps,
3231 pProfile->m_Header.biSpectralRange.steps,
3232 (icUInt16Number)icGetSpaceSamples((icColorSpaceSignature)pProfile->m_Header.spectralPCS));
3233 if (!pMtx)
3234 return icCmmStatAllocErr;
3235
3236 CIccPcsStepMatrix *illumMtx = rangeMap(illuminantRange, pProfile->m_Header.biSpectralRange);
3237 if (illumMtx) {
3238 illumMtx->Apply(NULL, pMtx->data(), illuminant);
3239 delete illumMtx;
3240 }
3241 else {
3242 memcpy(pMtx->data(), illuminant, illuminantRange.steps*sizeof(icFloatNumber));
3243 }
3244
3245 CIccPcsStepPtr ptr;
3246 ptr.ptr = pMtx;
3247 m_list->push_back(ptr);
3248
3249 }
3250 else {
3251 CIccPcsStepSrcMatrix *pMtx = new CIccPcsStepSrcMatrix(pProfile->m_Header.spectralRange.steps, pProfile->m_Header.biSpectralRange.steps);
3252 if (!pMtx)
3253 return icCmmStatAllocErr;
3254
3255 CIccPcsStepMatrix *illumMtx = rangeMap(illuminantRange, pProfile->m_Header.biSpectralRange);
3256 if (illumMtx) {
3257 illumMtx->Apply(NULL, pMtx->data(), illuminant);
3258 delete illumMtx;
3259 }
3260 else {
3261 memcpy(pMtx->data(), illuminant, illuminantRange.steps*sizeof(icFloatNumber));
3262 }
3263
3264 CIccPcsStepPtr ptr;
3265 ptr.ptr = pMtx;
3266 m_list->push_back(ptr);
3267
3268 }
3269 }
3270
3271 return icCmmStatOk;
3272}
3273
3274
3275/**
3276 **************************************************************************
3277 * Name: CIccPcsXform::pushBiRef2Xyz
3278 *
3279 * Purpose:
3280 * Insert PCS step that applies an illuminant to incoming bi-spectral reflectance
3281 * matrices to get actual XYZ values. The illuminant from the Profile
3282 * Connection Conditions is re-sampled to match the number of columns in
3283 * the incoming matrices.
3284 **************************************************************************
3285 */
3286icStatusCMM CIccPcsXform::pushBiRef2Xyz(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc)
3287{
3288 icStatusCMM stat = pushBiRef2Rad(pProfile, pPcc);
3289 if (stat!=icCmmStatOk)
3290 return stat;
3291
3293
3294 if (pView) {
3295 icSpectralRange observerRange;
3296 const icFloatNumber *observer = pView->getObserver(observerRange);
3297
3298 pushSpecToRange(pProfile->m_Header.spectralRange, observerRange);
3299 pushMatrix(3, observerRange.steps, observer);
3300 pushXYZNormalize(pPcc, pProfile->m_Header.biSpectralRange, pProfile->m_Header.spectralRange);
3301 }
3302 else {
3304 }
3305
3306 return icCmmStatOk;
3307}
3308
3309
3310/**
3311 **************************************************************************
3312 * Name: CIccPcsXform::pushBiRef2Ref
3313 *
3314 * Purpose:
3315 * Insert PCS steps that apply an illuminant to incoming bi-spectral reflectance
3316 * matrices and then normalizes by the illuminant to get an estimate of
3317 * reflectance factor under that illuminant.
3318 **************************************************************************
3319 */
3320icStatusCMM CIccPcsXform::pushBiRef2Ref(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc)
3321{
3322 icStatusCMM stat = pushBiRef2Rad(pProfile, pPcc);
3323 if (stat!=icCmmStatOk)
3324 return stat;
3325
3327
3328 if (pView) {
3329 icSpectralRange illuminantRange;
3330 const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange);
3331
3332 CIccPcsStepScale *pScale = new CIccPcsStepScale(pProfile->m_Header.spectralRange.steps);
3333
3334 if (pScale) {
3335 icFloatNumber *pData = pScale->data();
3336 CIccPcsStepMatrix *illumMtx = rangeMap(illuminantRange, pProfile->m_Header.spectralRange);
3337 int i;
3338
3339 if (illumMtx) {
3340 illumMtx->Apply(NULL, pData, illuminant);
3341 for (i=0; i<pProfile->m_Header.spectralRange.steps; i++)
3342 pData[i] = 1.0f / pData[i];
3343
3344 delete illumMtx;
3345
3346 CIccPcsStepPtr ptr;
3347 ptr.ptr = pScale;
3348 m_list->push_back(ptr);
3349 }
3350 else {
3351 for (i=0; i<pProfile->m_Header.spectralRange.steps; i++) {
3352 pData[i] = 1.0f / illuminant[i];
3353 }
3354 }
3355 }
3356 else
3357 return icCmmStatAllocErr;
3358 }
3359 else
3361
3362 return icCmmStatOk;
3363}
3364
3365
3366#ifdef _DEBUG
3367//#define DUMPCSSTEPRESULTS
3368#ifdef DUMPCSSTEPRESULTS
3369 #define ICCDUMPPIXEL(n, pix) \
3370 if ((n)<96) { \
3371 printf("["); \
3372 int i; \
3373 for (i=0; i<(n); i++) { \
3374 if (i && !(i%12)) \
3375 printf("...\n"); \
3376 printf(" %.5f", pix[i]); \
3377 } \
3378 printf("]\n"); \
3379 } \
3380 else { \
3381 printf("[ BigAray with %d elements]\n", (n)); \
3382 }
3383#else
3384 #define ICCDUMPPIXEL(n, pix)
3385#endif
3386#else
3387 #define ICCDUMPPIXEL(n, pix)
3388#endif
3389
3390
3391/**
3392**************************************************************************
3393* Name: CIccPcsXform::Apply
3394*
3395* Purpose:
3396* Applies the PcsXfrom steps using the apply pXform data to SrcPixel to get DstPixel
3397**************************************************************************
3398*/
3399void CIccPcsXform::Apply(CIccApplyXform *pXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
3400{
3401 CIccApplyPcsXform *pApplyXform = (CIccApplyPcsXform*)pXform;
3402 CIccApplyPcsStepList *pList = pApplyXform->m_list;
3403
3404 ICCDUMPPIXEL(GetNumSrcSamples(), SrcPixel);
3405
3406 if (!pList) {
3407 memcpy(DstPixel, SrcPixel, GetNumSrcSamples()*sizeof(icFloatNumber));
3408 ICCDUMPPIXEL(GetNumSrcSamples(), DstPixel);
3409 return;
3410 }
3411
3412 CIccApplyPcsStepList::iterator s, n;
3413 s = n =pList->begin();
3414
3415 if (s==pList->end()) {
3416 memcpy(DstPixel, SrcPixel, GetNumSrcSamples()*sizeof(icFloatNumber));
3417 ICCDUMPPIXEL(GetNumSrcSamples(), DstPixel);
3418 return;
3419 }
3420
3421 n++;
3422
3423 if (n==pList->end()) {
3424 s->ptr->Apply(DstPixel, SrcPixel);
3425 ICCDUMPPIXEL(s->ptr->GetStep()->GetDstChannels(), DstPixel);
3426 }
3427 else {
3428 const icFloatNumber *src = SrcPixel;
3429 icFloatNumber *p1 = pApplyXform->m_temp1;
3430 icFloatNumber *p2 = pApplyXform->m_temp2;
3431 icFloatNumber *t;
3432
3433 for (;n!=pList->end(); s=n, n++) {
3434 s->ptr->Apply(p1, src);
3435 ICCDUMPPIXEL(s->ptr->GetStep()->GetDstChannels(), p1);
3436 src=p1;
3437 t=p1; p1=p2; p2=t;
3438 }
3439 s->ptr->Apply(DstPixel, src);
3440 ICCDUMPPIXEL(s->ptr->GetStep()->GetDstChannels(), DstPixel);
3441 }
3442}
3443
3444/**
3445**************************************************************************
3446* Name: CIccPcsStep::GetNewApply
3447*
3448* Purpose:
3449* Allocates a new CIccApplyPcsStep to be used with processing.
3450**************************************************************************
3451*/
3452CIccApplyPcsStep* CIccPcsStep::GetNewApply()
3453{
3454 return new CIccApplyPcsStep(this);
3455}
3456
3457
3458/**
3459**************************************************************************
3460* Name: CIccPcsStepIdentity::Apply
3461*
3462* Purpose:
3463* Copies pSrc to pDst
3464**************************************************************************
3465*/
3466void CIccPcsStepIdentity::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
3467{
3468 if (pDst != pSrc)
3469 memcpy(pDst, pSrc, m_nChannels*sizeof(icFloatNumber));
3470}
3471
3472
3473/**
3474**************************************************************************
3475* Name: CIccPcsStepIdentity::dump
3476*
3477* Purpose:
3478* dumps the context of the step
3479**************************************************************************
3480*/
3481void CIccPcsStepIdentity::dump(std::string &str) const
3482{
3483 str += "\nCIccPcsStepIdentity\n\n";
3484}
3485
3486
3487/**
3488**************************************************************************
3489* Name: CIccPcsStepIdentity::CIccPcsStepIdentity
3490*
3491* Purpose:
3492* Constructor
3493**************************************************************************
3494*/
3495CIccPcsStepRouteMcs::CIccPcsStepRouteMcs(CIccTagArray *pSrcChannels, CIccTagArray *pDstChannels, CIccTagNumArray *pDefaults)
3496{
3497 m_nSrcChannels = (icUInt16Number)pSrcChannels->GetSize();
3498 m_nDstChannels = (icUInt16Number)pDstChannels->GetSize();
3499 m_Index = new int[m_nDstChannels];
3500 m_Defaults = new icFloatNumber[m_nDstChannels];
3501
3502 memset(m_Defaults, 0, m_nDstChannels*sizeof(icFloatNumber));
3503
3504 if (pDefaults) {
3505 pDefaults->GetValues(m_Defaults, 0, m_nDstChannels);
3506 }
3507
3508 int i, j;
3509 char *szSrc;
3510
3511 for (i=0; i<m_nDstChannels; i++) {
3512 const icUChar *szDstChan = ((CIccTagUtf8Text*)(pDstChannels->GetIndex(i)))->GetText();
3513 for (j=0; j<m_nSrcChannels; j++) {
3514 const icUChar *szSrcChan = ((CIccTagUtf8Text*)(pSrcChannels->GetIndex(j)))->GetText();
3515 szSrc = (char*)szSrcChan;
3516 if (!icUtf8StrCmp(szDstChan, szSrcChan))
3517 break;
3518 }
3519 if (j==m_nSrcChannels) {
3520 m_Index[i] = -1;
3521 }
3522 else {
3523 m_Index[i] = j;
3524 }
3525 //printf("%d - %d %s\n", m_Index[i], i, szDstChan);
3526 }
3527}
3528
3529
3530/**
3531**************************************************************************
3532* Name: CIccPcsStepIdentity::~CIccPcsStepIdentity
3533*
3534* Purpose:
3535* Destructor
3536**************************************************************************
3537*/
3538CIccPcsStepRouteMcs::~CIccPcsStepRouteMcs()
3539{
3540 if (m_Index)
3541 delete [] m_Index;
3542 if (m_Defaults)
3543 delete [] m_Defaults;
3544}
3545
3546
3547/**
3548**************************************************************************
3549* Name: CIccPcsStepRouteMcs::isIdentity
3550*
3551* Purpose:
3552* Determines if applying this step will result in negligible change in data
3553**************************************************************************
3554*/
3555bool CIccPcsStepRouteMcs::isIdentity() const
3556{
3557 if (m_nSrcChannels!=m_nDstChannels)
3558 return false;
3559
3560 int i;
3561 for (i=0; i<m_nDstChannels; i++) {
3562 if (m_Index[i]!=i)
3563 return false;
3564 }
3565
3566 return true;
3567}
3568
3569
3570
3571/**
3572**************************************************************************
3573* Name: CIccPcsStepRouteMcs::Apply
3574*
3575* Purpose:
3576* Copies pSrc to pDst
3577**************************************************************************
3578*/
3579void CIccPcsStepRouteMcs::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
3580{
3581 if (pDst != pSrc) {
3582 int i;
3583 for (i=0; i<m_nDstChannels; i++) {
3584 if (m_Index[i]>=0)
3585 pDst[i] = pSrc[m_Index[i]];
3586 else
3587 pDst[i] = m_Defaults[i];
3588 }
3589 }
3590}
3591
3592
3593/**
3594**************************************************************************
3595* Name: CIccPcsStepRouteMcs::dump
3596*
3597* Purpose:
3598* dumps the context of the step
3599**************************************************************************
3600*/
3601void CIccPcsStepRouteMcs::dump(std::string &str) const
3602{
3603 str += "\nCIccPcsStepRouteMcs\n\n";
3604}
3605
3606extern icFloatNumber icD50XYZ[3];
3607
3608/**
3609**************************************************************************
3610* Name: CIccPcsLabStep::isSameWhite
3611*
3612* Purpose:
3613* Determines if this step has same white point as that passed in
3614**************************************************************************
3615*/
3616bool CIccPcsLabStep::isSameWhite(const icFloatNumber *xyzWhite)
3617{
3618 return (m_xyzWhite[0]==xyzWhite[0] &&
3619 m_xyzWhite[1]==xyzWhite[1] &&
3620 m_xyzWhite[2]==xyzWhite[2]);
3621}
3622
3623
3624
3625/**
3626**************************************************************************
3627* Name: CIccPcsStepLabToXYZ::CIccPcsStepLabToXYZ
3628*
3629* Purpose:
3630* Constructor
3631**************************************************************************
3632*/
3633CIccPcsStepLabToXYZ::CIccPcsStepLabToXYZ(const icFloatNumber *xyzWhite/*=NULL*/)
3634{
3635 if (xyzWhite) {
3636 memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite));
3637 }
3638 else {
3639 memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite));
3640 }
3641}
3642
3643
3644/**
3645**************************************************************************
3646* Name: CIccPcsStepLabToXYZ::Apply
3647*
3648* Purpose:
3649* Converts from V4 Internal Lab to actual XYZ
3650**************************************************************************
3651*/
3652void CIccPcsStepLabToXYZ::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
3653{
3654 icFloatNumber Lab[3];
3655
3656 //lab4 to XYZ
3657 Lab[0] = pSrc[0] * 100.0f;
3658 Lab[1] = (icFloatNumber)(pSrc[1]*255.0f - 128.0f);
3659 Lab[2] = (icFloatNumber)(pSrc[2]*255.0f - 128.0f);
3660
3661 icLabtoXYZ(pDst, Lab, m_xyzWhite);
3662}
3663
3664
3665/**
3666**************************************************************************
3667* Name: CIccPcsStepLabToXYZ::dump
3668*
3669* Purpose:
3670* dumps the context of the step
3671**************************************************************************
3672*/
3673void CIccPcsStepLabToXYZ::dump(std::string &str) const
3674{
3675 str += "\nCIccPcsStepLabToXYZ\n\n";
3676}
3677
3678
3679/**
3680**************************************************************************
3681* Name: CIccPcsStepLabToXYZ::concat
3682*
3683* Purpose:
3684* Determines if this step can be combined with the next step.
3685* Checks if next step is an icPcsStepXyzToLab step resulting in a combined
3686* identity transform.
3687**************************************************************************
3688*/
3689CIccPcsStep *CIccPcsStepLabToXYZ::concat(CIccPcsStep *pNext) const
3690{
3691 if (pNext && pNext->GetType()==icPcsStepXYZToLab) {
3692 CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext;
3693 if (pStep->isSameWhite(m_xyzWhite))
3694 return new CIccPcsStepIdentity(3);
3695 }
3696 return NULL;
3697}
3698
3699
3700/**
3701**************************************************************************
3702* Name: CIccPcsStepXYZToLab::CIccPcsStepXYZToLab
3703*
3704* Purpose:
3705* Constructor
3706**************************************************************************
3707*/
3708CIccPcsStepXYZToLab::CIccPcsStepXYZToLab(const icFloatNumber *xyzWhite/*=NULL*/)
3709{
3710 if (xyzWhite) {
3711 memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite));
3712 }
3713 else {
3714 memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite));
3715 }
3716}
3717
3718
3719/**
3720**************************************************************************
3721* Name: CIccPcsStepXYZToLab::Apply
3722*
3723* Purpose:
3724* Converts from actual XYZ to V4 Internal Lab
3725**************************************************************************
3726*/
3727void CIccPcsStepXYZToLab::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
3728{
3729 icFloatNumber Lab[3];
3730 icXYZtoLab(Lab, (icFloatNumber*)pSrc, m_xyzWhite);
3731 //lab4 from XYZ
3732 pDst[0] = Lab[0] / 100.0f;
3733 pDst[1] = (icFloatNumber)((Lab[1] + 128.0f) / 255.0f);
3734 pDst[2] = (icFloatNumber)((Lab[2] + 128.0f) / 255.0f);
3735}
3736
3737
3738/**
3739**************************************************************************
3740* Name: CIccPcsStepXYZToLab::dump
3741*
3742* Purpose:
3743* dumps the context of the step
3744**************************************************************************
3745*/
3746void CIccPcsStepXYZToLab::dump(std::string &str) const
3747{
3748 str += "\nCIccPcsStepXYZToLab\n\n";
3749}
3750
3751
3752/**
3753**************************************************************************
3754* Name: CIccPcsStepXYZToLab::concat
3755*
3756* Purpose:
3757* Determines if this step can be combined with the next step.
3758* Checks if next step is an icPcsStepLabToXYZ step resulting in a combined
3759* identity transform.
3760**************************************************************************
3761*/
3762CIccPcsStep *CIccPcsStepXYZToLab::concat(CIccPcsStep *pNext) const
3763{
3764 if (pNext && pNext->GetType()==icPcsStepLabToXYZ) {
3765 CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext;
3766 if (pStep->isSameWhite(m_xyzWhite))
3767 return new CIccPcsStepIdentity(3);
3768 }
3769 return NULL;
3770}
3771
3772
3773/**
3774**************************************************************************
3775* Name: CIccPcsStepLab2ToXYZ::CIccPcsStepLab2ToXYZ
3776*
3777* Purpose:
3778* Constructor
3779**************************************************************************
3780*/
3781CIccPcsStepLab2ToXYZ::CIccPcsStepLab2ToXYZ(const icFloatNumber *xyzWhite/*=NULL*/)
3782{
3783 if (xyzWhite) {
3784 memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite));
3785 }
3786 else {
3787 memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite));
3788 }
3789}
3790
3791/**
3792**************************************************************************
3793* Name: CIccPcsStepLab2ToXYZ::Apply
3794*
3795* Purpose:
3796* Converts from actual XYZ to V2 Internal Lab
3797**************************************************************************
3798*/
3799void CIccPcsStepLab2ToXYZ::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
3800{
3801 icFloatNumber Lab[3];
3802
3803 //lab2 to XYZ
3804 Lab[0] = pSrc[0] * (65535.0f / 65280.0f) * 100.0f;
3805 Lab[1] = (icFloatNumber)(pSrc[1] * 65535.0f / 65280.0f * 255.0f - 128.0f);
3806 Lab[2] = (icFloatNumber)(pSrc[2] * 65535.0f / 65280.0f * 255.0f - 128.0f);
3807
3808 icLabtoXYZ(pDst, Lab, m_xyzWhite);
3809}
3810
3811
3812/**
3813**************************************************************************
3814* Name: CIccPcsStepLab2ToXYZ::dump
3815*
3816* Purpose:
3817* dumps the context of the step
3818**************************************************************************
3819*/
3820void CIccPcsStepLab2ToXYZ::dump(std::string &str) const
3821{
3822 str += "\nCIccPcsStepLab2ToXYZ\n\n";
3823}
3824
3825
3826/**
3827**************************************************************************
3828* Name: CIccPcsStepLab2ToXYZ::concat
3829*
3830* Purpose:
3831* Determines if this step can be combined with the next step.
3832* Checks if next step is an icPcsStepXYZToLab2 step resulting in a combined
3833* identity transform.
3834**************************************************************************
3835*/
3836CIccPcsStep *CIccPcsStepLab2ToXYZ::concat(CIccPcsStep *pNext) const
3837{
3838 if (pNext && pNext->GetType()==icPcsStepXYZToLab2) {
3839 CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext;
3840 if (pStep->isSameWhite(m_xyzWhite))
3841 return new CIccPcsStepIdentity(3);
3842 }
3843 return NULL;
3844}
3845
3846
3847/**
3848**************************************************************************
3849* Name: CIccPcsStepXYZToLab2::CIccPcsStepXYZToLab2
3850*
3851* Purpose:
3852* Constructor
3853**************************************************************************
3854*/
3855CIccPcsStepXYZToLab2::CIccPcsStepXYZToLab2(const icFloatNumber *xyzWhite/*=NULL*/)
3856{
3857 if (xyzWhite) {
3858 memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite));
3859 }
3860 else {
3861 memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite));
3862 }
3863}
3864
3865
3866/**
3867**************************************************************************
3868* Name: CIccPcsStepXYZToLab2::Apply
3869*
3870* Purpose:
3871* Converts from V2 Internal Lab to actual XYZ
3872**************************************************************************
3873*/
3874void CIccPcsStepXYZToLab2::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
3875{
3876 icFloatNumber Lab[3];
3877 icXYZtoLab(Lab, (icFloatNumber*)pSrc, m_xyzWhite);
3878 //lab2 from XYZ
3879 pDst[0] = (Lab[0] / 100.0f) * (65280.0f / 65535.0f);
3880 pDst[1] = (icFloatNumber)((Lab[1] + 128.0f) / 255.0f) * (65280.0f / 65535.0f);
3881 pDst[2] = (icFloatNumber)((Lab[2] + 128.0f) / 255.0f) * (65280.0f / 65535.0f);
3882}
3883
3884
3885/**
3886**************************************************************************
3887* Name: CIccPcsStepXYZToLab2::dump
3888*
3889* Purpose:
3890* dumps the context of the step
3891**************************************************************************
3892*/
3893void CIccPcsStepXYZToLab2::dump(std::string &str) const
3894{
3895 str += "\nCIccPcsStepXYZToLab2\n\n";
3896}
3897
3898
3899/**
3900**************************************************************************
3901* Name: CIccPcsStepXYZToLab2::concat
3902*
3903* Purpose:
3904* Determines if this step can be combined with the next step.
3905* Checks if next step is an icPcsStepLab2ToXYZ step resulting in a combined
3906* identity transform.
3907**************************************************************************
3908*/
3909CIccPcsStep *CIccPcsStepXYZToLab2::concat(CIccPcsStep *pNext) const
3910{
3911 if (pNext && pNext->GetType()==icPcsStepLab2ToXYZ) {
3912 CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext;
3913 if (pStep->isSameWhite(m_xyzWhite))
3914 return new CIccPcsStepIdentity(3);
3915 }
3916 return NULL;
3917}
3918
3919
3920/**
3921**************************************************************************
3922* Name: CIccPcsStepOffset::CIccPcsStepOffset
3923*
3924* Purpose:
3925* Constructor
3926**************************************************************************
3927*/
3928CIccPcsStepOffset::CIccPcsStepOffset(icUInt16Number nChannels)
3929{
3930 m_nChannels = nChannels;
3931 m_vals = new icFloatNumber[nChannels];
3932}
3933
3934
3935/**
3936**************************************************************************
3937* Name: CIccPcsStepOffset::CIccPcsStepOffset
3938*
3939* Purpose:
3940* Destructor
3941**************************************************************************
3942*/
3943CIccPcsStepOffset::~CIccPcsStepOffset()
3944{
3945 if (m_vals)
3946 delete m_vals;
3947}
3948
3949
3950/**
3951**************************************************************************
3952* Name: CIccPcsStepOffset::Apply
3953*
3954* Purpose:
3955* Added a fixed offset to the pSrc vector passed in
3956**************************************************************************
3957*/
3958void CIccPcsStepOffset::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
3959{
3960 if (m_nChannels==3) {
3961 pDst[0] = m_vals[0] + pSrc[0];
3962 pDst[1] = m_vals[1] + pSrc[1];
3963 pDst[2] = m_vals[2] + pSrc[2];
3964 }
3965 else {
3966 int i;
3967 for (i=0; i<m_nChannels; i++) {
3968 pDst[i] = m_vals[i] + pSrc[i];
3969 }
3970 }
3971}
3972
3973
3974/**
3975**************************************************************************
3976* Name: CIccPcsStepOffset::dump
3977*
3978* Purpose:
3979* dumps the context of the step
3980**************************************************************************
3981*/
3982void CIccPcsStepOffset::dump(std::string &str) const
3983{
3984 str += "\nCIccPcsStepOffset\n\n";
3985 char buf[80];
3986 for (int i=0; i<m_nChannels; i++) {
3987 sprintf(buf, ICCPCSSTEPDUMPFMT, m_vals[i]);
3988 str += buf;
3989 }
3990 str +="\n";
3991}
3992
3993
3994/**
3995**************************************************************************
3996* Name: CIccPcsStepOffset::Apply
3997*
3998* Purpose:
3999* Creates a new CIccPcsStepOffet step that is the result of adding the
4000* offset of this object to the offset of another object.
4001**************************************************************************
4002*/
4003CIccPcsStepOffset *CIccPcsStepOffset::Add(const CIccPcsStepOffset *offset) const
4004{
4005 if (offset->m_nChannels != m_nChannels)
4006 return NULL;
4007
4008 CIccPcsStepOffset *pNew = new CIccPcsStepOffset(m_nChannels);
4009
4010 if (pNew) {
4011 int i;
4012 for (i=0; i<m_nChannels; i++) {
4013 pNew->m_vals[i] = m_vals[i] + offset->m_vals[i];
4014 }
4015 }
4016
4017 return pNew;
4018}
4019
4020/**
4021**************************************************************************
4022* Name: CIccPcsStepOffset::concat
4023*
4024* Purpose:
4025* Determines if this step can be combined with the next step.
4026* Checks if next step is a compatible icPcsStepOffset step resulting in a
4027* single combined offset.
4028**************************************************************************
4029*/
4030CIccPcsStep *CIccPcsStepOffset::concat(CIccPcsStep *pNext) const
4031{
4032 if (pNext && pNext->GetType()==icPcsStepOffset && m_nChannels==pNext->GetSrcChannels())
4033 return Add((const CIccPcsStepOffset*)pNext);
4034
4035 return NULL;
4036}
4037
4038
4039/**
4040**************************************************************************
4041* Name: CIccPcsStepOffset::isIdentity
4042*
4043* Purpose:
4044* Determines if applying this step will result in negligible change in data
4045**************************************************************************
4046*/
4047bool CIccPcsStepOffset::isIdentity() const
4048{
4049 int i;
4050 for (i=0; i<m_nChannels; i++) {
4051 if (m_vals[i]<-icNearRange || m_vals[i]>icNearRange)
4052 return false;
4053 }
4054
4055 return true;
4056}
4057
4058
4059/**
4060**************************************************************************
4061* Name: CIccPcsStepScale::CIccPcsStepScale
4062*
4063* Purpose:
4064* Constructor
4065**************************************************************************
4066*/
4067CIccPcsStepScale::CIccPcsStepScale(icUInt16Number nChannels)
4068{
4069 m_nChannels = nChannels;
4070 m_vals = new icFloatNumber[nChannels];
4071}
4072
4073
4074/**
4075**************************************************************************
4076* Name: CIccPcsStepScale::~CIccPcsStepScale
4077*
4078* Purpose:
4079* Destructor
4080**************************************************************************
4081*/
4082CIccPcsStepScale::~CIccPcsStepScale()
4083{
4084 if (m_vals)
4085 delete m_vals;
4086}
4087
4088/**
4089**************************************************************************
4090* Name: CIccPcsStepScale::Apply
4091*
4092* Purpose:
4093* Multiplies fixed scale values to the pSrc vector passed in
4094**************************************************************************
4095*/
4096void CIccPcsStepScale::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
4097{
4098 if (m_nChannels==3) {
4099 pDst[0] = m_vals[0] * pSrc[0];
4100 pDst[1] = m_vals[1] * pSrc[1];
4101 pDst[2] = m_vals[2] * pSrc[2];
4102 }
4103 else {
4104 int i;
4105 for (i=0; i<m_nChannels; i++) {
4106 pDst[i] = m_vals[i] * pSrc[i];
4107 }
4108 }
4109}
4110
4111
4112/**
4113**************************************************************************
4114* Name: CIccPcsStepScale::dump
4115*
4116* Purpose:
4117* dumps the context of the step
4118**************************************************************************
4119*/
4120void CIccPcsStepScale::dump(std::string &str) const
4121{
4122 str += "\nCIccPcsStepScale\n\n";
4123 char buf[80];
4124 for (int i=0; i<m_nChannels; i++) {
4125 sprintf(buf, ICCPCSSTEPDUMPFMT, m_vals[i]);
4126 str += buf;
4127 }
4128 str +="\n";
4129}
4130
4131
4132/**
4133**************************************************************************
4134* Name: CIccPcsStepScale::Mult
4135*
4136* Purpose:
4137* Creates a new CIccPcsStepScale step that is the result of multiplying the
4138* scale of this object to the scale of another object.
4139**************************************************************************
4140*/
4141CIccPcsStepScale *CIccPcsStepScale::Mult(const CIccPcsStepScale *scale) const
4142{
4143 if (scale->m_nChannels != m_nChannels)
4144 return NULL;
4145
4146 CIccPcsStepScale *pNew = new CIccPcsStepScale(m_nChannels);
4147
4148 if (pNew) {
4149 int i;
4150 for (i=0; i<m_nChannels; i++) {
4151 pNew->m_vals[i] = m_vals[i] * scale->m_vals[i];
4152 }
4153 }
4154 return pNew;
4155}
4156
4157/**
4158**************************************************************************
4159* Name: CIccPcsStepScale::Mult
4160*
4161* Purpose:
4162* Creates a new CIccPcsStepMatrix step that is the result of multiplying the
4163* scale of this object to the scale of another matrix.
4164**************************************************************************
4165*/
4166CIccPcsStepMatrix *CIccPcsStepScale::Mult(const CIccPcsStepMatrix *matrix) const
4167{
4168 if (matrix->GetSrcChannels() != m_nChannels)
4169 return NULL;
4170
4171 CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(matrix->GetDstChannels(), matrix->GetSrcChannels());
4172
4173 if (pNew) {
4174 int i, j;
4175 for (j=0; j<matrix->GetDstChannels(); j++) {
4176 const icFloatNumber *row = matrix->entry(j);
4177 icFloatNumber *to=pNew->entry(j);
4178
4179 for (i=0; i<m_nChannels; i++) {
4180 to[i] = m_vals[i] * row[i];
4181 }
4182 }
4183 }
4184
4185 return pNew;
4186}
4187
4188/**
4189**************************************************************************
4190* Name: CIccPcsStepScale::Mult
4191*
4192* Purpose:
4193* Creates a new CIccPcsStepMatrix step that is the result of multiplying the
4194* scale of this object to the scale of another matrix.
4195**************************************************************************
4196*/
4197CIccPcsStepMatrix *CIccPcsStepScale::Mult(const CIccMpeMatrix *matrix) const
4198{
4199 if (matrix->NumInputChannels() != m_nChannels)
4200 return NULL;
4201
4202 CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(matrix->NumOutputChannels(), matrix->NumInputChannels());
4203
4204 if (pNew) {
4205 int i, j;
4206 icFloatNumber *mtx = matrix->GetMatrix();
4207 for (j = 0; j < matrix->NumOutputChannels(); j++) {
4208 const icFloatNumber *row = &mtx[j*matrix->NumInputChannels()];
4209 icFloatNumber *to = pNew->entry(j);
4210
4211 for (i = 0; i < m_nChannels; i++) {
4212 to[i] = m_vals[i] * row[i];
4213 }
4214 }
4215 }
4216
4217 return pNew;
4218}
4219
4220
4221/**
4222**************************************************************************
4223* Name: CIccPcsStepScale::concat
4224*
4225* Purpose:
4226* Determines if this step can be combined with the next step.
4227* Checks if next step is a compatible icPcsStepScale or icPcsStepMatrix step
4228* resulting in a single combined object.
4229**************************************************************************
4230*/
4231CIccPcsStep *CIccPcsStepScale::concat(CIccPcsStep *pNext) const
4232{
4233 if (pNext) {
4234 if (pNext->GetType()==icPcsStepScale && m_nChannels==pNext->GetSrcChannels())
4235 return Mult((const CIccPcsStepScale*)pNext);
4236 if (pNext->GetType()==icPcsStepMatrix && m_nChannels==pNext->GetSrcChannels())
4237 return Mult((const CIccPcsStepMatrix*)pNext);
4238 if (pNext->GetType() == icPcsStepMpe && m_nChannels == pNext->GetSrcChannels()) {
4239 CIccPcsStepMpe *pMpe = (CIccPcsStepMpe*)pNext;
4240 CIccMpeMatrix *pMatrix = pMpe->GetMatrix();
4241 if (pMatrix)
4242 return Mult(pMatrix);
4243 }
4244 }
4245
4246 return NULL;
4247}
4248
4249
4250/**
4251**************************************************************************
4252* Name: CIccPcsStepScale::isIdentity
4253*
4254* Purpose:
4255* Determines if applying this step will result in negligible change in data
4256**************************************************************************
4257*/
4258bool CIccPcsStepScale::isIdentity() const
4259{
4260 int i;
4261 for (i=0; i<m_nChannels; i++) {
4262 if (m_vals[i]<1.0f-icNearRange || m_vals[i]>1.0f+icNearRange)
4263 return false;
4264 }
4265
4266 return true;
4267}
4268
4269
4270
4271/**
4272**************************************************************************
4273* Name: CIccPcsStepMatrix::dump
4274*
4275* Purpose:
4276* dumps the context of the step
4277**************************************************************************
4278*/
4279void CIccPcsStepMatrix::dump(std::string &str) const
4280{
4281 str += "\nCIccPcsStepMatrix\n\n";
4282 dumpMtx(str);
4283}
4284
4285
4286/**
4287**************************************************************************
4288* Name: CIccPcsStepMatrix::Mult
4289*
4290* Purpose:
4291* Creates a new CIccPcsStepMatrix step that is the result of multiplying the
4292* matrix of this object to the scale of another object.
4293**************************************************************************
4294*/
4295CIccPcsStepMatrix *CIccPcsStepMatrix::Mult(const CIccPcsStepScale *scale) const
4296{
4297 icUInt16Number mCols = scale->GetSrcChannels();
4298 icUInt16Number mRows = mCols;
4299
4300 if (m_nRows != mCols)
4301 return NULL;
4302
4303 CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(m_nRows, m_nCols);
4304 const icFloatNumber *data = scale->data();
4305
4306 int i, j;
4307 for (j=0; j<m_nRows; j++) {
4308 const icFloatNumber *row = entry(j);
4309 icFloatNumber *to = pNew->entry(j);
4310 for (i=0; i<m_nCols; i++) {
4311 to[i] = data[j] * row[i];
4312 }
4313 }
4314
4315 return pNew;
4316}
4317
4318/**
4319**************************************************************************
4320* Name: CIccPcsStepMatrix::Mult
4321*
4322* Purpose:
4323* Creates a new CIccPcsStepMatrix step that is the result of concatentating
4324* another matrix with this matrix. (IE result = matrix * this).
4325**************************************************************************
4326*/
4327CIccPcsStepMatrix *CIccPcsStepMatrix::Mult(const CIccPcsStepMatrix *matrix) const
4328{
4329 icUInt16Number mCols = matrix->m_nCols;
4330 icUInt16Number mRows = matrix->m_nRows;
4331
4332 if (m_nRows != mCols)
4333 return NULL;
4334
4335 CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(mRows, m_nCols);
4336
4337 int i, j, k;
4338 for (j=0; j<mRows; j++) {
4339 const icFloatNumber *row = matrix->entry(j);
4340 for (i=0; i<m_nCols; i++) {
4341 icFloatNumber *to = pNew->entry(j, i);
4342 const icFloatNumber *from = entry(0, i);
4343
4344 *to = 0.0f;
4345 for (k=0; k<m_nRows; k++) {
4346 *to += row[k] * (*from);
4347 from += m_nCols;
4348 }
4349 }
4350 }
4351
4352 return pNew;
4353}
4354
4355
4356/**
4357**************************************************************************
4358* Name: CIccPcsStepMatrix::concat
4359*
4360* Purpose:
4361* Determines if this step can be combined with the next step.
4362* Checks if next step is a compatible icPcsStepScale or icPcsStepMatrix step
4363* resulting in a single combined object.
4364**************************************************************************
4365*/
4366CIccPcsStep *CIccPcsStepMatrix::concat(CIccPcsStep *pNext) const
4367{
4368 if (pNext) {
4369 if (pNext->GetType()==icPcsStepScale && GetDstChannels()==pNext->GetSrcChannels())
4370 return Mult((const CIccPcsStepScale*)pNext);
4371 if (pNext->GetType()==icPcsStepMatrix && GetDstChannels()==pNext->GetSrcChannels())
4372 return Mult((const CIccPcsStepMatrix*)pNext);
4373 }
4374
4375 return NULL;
4376}
4377
4378/**
4379**************************************************************************
4380* Name: CIccPcsStepMatrix::concat
4381*
4382* Purpose:
4383* Determines if this step can be combined with the next step.
4384* Checks if next step is a compatible icPcsStepScale or icPcsStepMatrix step
4385* resulting in a single combined object.
4386**************************************************************************
4387*/
4388CIccPcsStep *CIccPcsStepMatrix::reduce() const
4389{
4390 int nVals = m_nRows*m_nCols;
4391 int nNonZeros = 0;
4392 int i;
4393
4394 for (i=0; i<nVals; i++) {
4395 icFloatNumber v = m_vals[i];
4396 if (icNotZero(v))
4397 nNonZeros++;
4398 }
4399 if (nNonZeros<nVals*3/4) {
4400 icUInt32Number nMatrixBytes = CIccSparseMatrix::MemSize(nNonZeros, m_nRows, sizeof(icFloatNumber))+4*sizeof(icFloatNumber);
4401 CIccPcsStepSparseMatrix *pMtx = new CIccPcsStepSparseMatrix(m_nRows, m_nCols, nMatrixBytes);
4402 CIccSparseMatrix mtx(pMtx->data(), nMatrixBytes);
4403 mtx.Init(m_nRows, m_nCols, true);
4404 mtx.FillFromFullMatrix(m_vals);
4405 return pMtx;
4406 }
4407
4408 return (CIccPcsStep*)this;
4409}
4410
4411
4412
4413/**
4414**************************************************************************
4415* Name: CIccPcsStepMpe::CIccPcsStepMpe
4416*
4417* Purpose:
4418* Constructor
4419**************************************************************************
4420*/
4421CIccPcsStepMpe::CIccPcsStepMpe(CIccTagMultiProcessElement *pMpe)
4422{
4423 m_pMpe = pMpe;
4424}
4425
4426
4427/**
4428**************************************************************************
4429* Name: CIccPcsStepMpe::~CIccPcsStepMpe
4430*
4431* Purpose:
4432* Destructor
4433**************************************************************************
4434*/
4435CIccPcsStepMpe::~CIccPcsStepMpe()
4436{
4437 if (m_pMpe)
4438 delete m_pMpe;
4439}
4440
4441
4442/**
4443**************************************************************************
4444* Name: CIccPcsStepMpe::GetNewApply
4445*
4446* Purpose:
4447* Allocates a new CIccApplyPcsStep to be used with processing.
4448**************************************************************************
4449*/
4450CIccApplyPcsStep* CIccPcsStepMpe::GetNewApply()
4451{
4452 CIccApplyPcsStepMpe *rv = new CIccApplyPcsStepMpe(this, m_pMpe->GetNewApply());
4453
4454 return rv;
4455}
4456
4457
4458/**
4459**************************************************************************
4460* Name: CIccPcsStepMpe::Apply
4461*
4462* Purpose:
4463* Applies a MultiProcessingElement to a Source vector to get a Dest vector
4464**************************************************************************
4465*/
4466void CIccPcsStepMpe::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
4467{
4468 CIccApplyPcsStepMpe *pMpeApply = (CIccApplyPcsStepMpe*)pApply;
4469
4470 m_pMpe->Apply(pMpeApply->m_pApply, pDst, pSrc);
4471}
4472
4473
4474/**
4475**************************************************************************
4476* Name: CIccPcsStepMpe::dump
4477*
4478* Purpose:
4479* dumps the context of the step
4480**************************************************************************
4481*/
4482void CIccPcsStepMpe::dump(std::string &str) const
4483{
4484 str += "\nCIccPcsStepMpe\n\n";
4485 m_pMpe->Describe(str, 100); // TODO propogate nVerboseness
4486}
4487
4488
4489/**
4490**************************************************************************
4491* Name: CIccPcsStepMpe::isIdentity
4492*
4493* Purpose:
4494* Determines if applying this step will obviously result in no change in data
4495**************************************************************************
4496*/
4497bool CIccPcsStepMpe::isIdentity() const
4498{
4499 if (!m_pMpe || !m_pMpe->NumElements())
4500 return true;
4501 return false;
4502}
4503
4504/**
4505**************************************************************************
4506* Name: CIccPcsStepMpe::GetSrcChannels
4507*
4508* Purpose:
4509* Returns the number of channels of data required going into the multi-
4510* processing element
4511**************************************************************************
4512*/
4513icUInt16Number CIccPcsStepMpe::GetSrcChannels() const
4514{
4515 return m_pMpe->NumInputChannels();
4516}
4517
4518
4519/**
4520**************************************************************************
4521* Name: CIccPcsStepMpe::GetDstChannels
4522*
4523* Purpose:
4524* Returns the number of channels of data coming out of the multi-
4525* processing element
4526**************************************************************************
4527*/
4528icUInt16Number CIccPcsStepMpe::GetDstChannels() const
4529{
4530 return m_pMpe->NumOutputChannels();
4531}
4532
4533
4534/**
4535**************************************************************************
4536* Name: CIccPcsStepMpe::GetMatrix()
4537*
4538* Purpose:
4539* Returns single CIccMpeMatrix element associated with PCS step or
4540* NULL if the MPE is more complex
4541**************************************************************************
4542*/
4543CIccMpeMatrix *CIccPcsStepMpe::GetMatrix() const
4544{
4545 //Must be single element
4546 if (m_pMpe->NumElements() == 1) {
4547 CIccMultiProcessElement *pElem = m_pMpe->GetElement(0);
4548 //Must be a matrix
4549 if (pElem && pElem->GetType() == icSigMatrixElemType) {
4550 CIccMpeMatrix *pMtx = (CIccMpeMatrix*)pElem;
4551
4552 //Should not apply any constants
4553 if (!pMtx->GetConstants() || !pMtx->GetApplyConstants())
4554 return pMtx;
4555 }
4556 }
4557
4558 return NULL;
4559}
4560
4561
4562
4563
4564/**
4565**************************************************************************
4566* Name: CIccPcsStepMpe::Begin
4567*
4568* Purpose:
4569* Initializes multi-processing element for processing. Must be called before
4570* Apply is called
4571**************************************************************************
4572*/
4573bool CIccPcsStepMpe::Begin()
4574{
4575 return m_pMpe->Begin();
4576}
4577
4578
4579/**
4580**************************************************************************
4581* Name: CIccPcsStepSrcMatrix::CIccPcsStepSrcMatrix
4582*
4583* Purpose:
4584* Constructor
4585**************************************************************************
4586*/
4587CIccPcsStepSrcMatrix::CIccPcsStepSrcMatrix(icUInt16Number nRows, icUInt16Number nCols)
4588{
4589 m_nRows = nRows;
4590 m_nCols = nCols;
4591 m_vals = new icFloatNumber[nCols];
4592}
4593
4594
4595/**
4596**************************************************************************
4597* Name: CIccPcsStepSrcMatrix::~CIccPcsStepSrcMatrix
4598*
4599* Purpose:
4600* Destructor
4601**************************************************************************
4602*/
4603CIccPcsStepSrcMatrix::~CIccPcsStepSrcMatrix()
4604{
4605 if (m_vals)
4606 delete m_vals;
4607}
4608
4609
4610/**
4611**************************************************************************
4612* Name: CIccPcsStepSrcMatrix::Apply
4613*
4614* Purpose:
4615* Multiplies illuminant stored in m_vals by pSrc matrix passed in resulting
4616* in a pDst vector
4617**************************************************************************
4618*/
4619void CIccPcsStepSrcMatrix::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
4620{
4621 int i, j;
4622 const icFloatNumber *row = pSrc;
4623 for (j=0; j<m_nRows; j++) {
4624 pDst[j] = 0.0f;
4625 for (i=0; i<m_nCols; i++) {
4626 pDst[j] += row[i] * m_vals[i];
4627 }
4628 row += m_nCols;
4629 }
4630}
4631
4632
4633/**
4634**************************************************************************
4635* Name: CIccPcsStepSrcMatrix::dump
4636*
4637* Purpose:
4638* dumps the context of the step
4639**************************************************************************
4640*/
4641void CIccPcsStepSrcMatrix::dump(std::string &str) const
4642{
4643 str += "\nCIccPcsStepSrcMatrix\n\n";
4644 char buf[80];
4645 for (int i=0; i<m_nCols; i++) {
4646 sprintf(buf, ICCPCSSTEPDUMPFMT, m_vals[i]);
4647 str += buf;
4648 }
4649 str += "\n";
4650}
4651
4652
4653/**
4654**************************************************************************
4655* Name: CIccPcsStepSparseMatrix::CIccPcsStepSparseMatrix
4656*
4657* Purpose:
4658* Constructor
4659**************************************************************************
4660*/
4661CIccPcsStepSparseMatrix::CIccPcsStepSparseMatrix(icUInt16Number nRows, icUInt16Number nCols, icUInt32Number nBytesPerMatrix)
4662{
4663 m_nRows = nRows;
4664 m_nCols = nCols;
4665 m_nBytesPerMatrix = nBytesPerMatrix;
4666 m_nChannels = 0;
4667 m_vals = new icFloatNumber[m_nBytesPerMatrix/sizeof(icFloatNumber)];
4668}
4669
4670
4671/**
4672**************************************************************************
4673* Name: CIccPcsStepSparseMatrix::~CIccPcsStepSparseMatrix
4674*
4675* Purpose:
4676* Destructor
4677**************************************************************************
4678*/
4679CIccPcsStepSparseMatrix::~CIccPcsStepSparseMatrix()
4680{
4681 if (m_vals)
4682 delete [] m_vals;
4683}
4684
4685
4686/**
4687**************************************************************************
4688* Name: CIccPcsStepSparseMatrix::Apply
4689*
4690* Purpose:
4691* Multiplies illuminant stored in m_vals by pSrc matrix passed in resulting
4692* in a pDst vector
4693**************************************************************************
4694*/
4695void CIccPcsStepSparseMatrix::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
4696{
4697 CIccSparseMatrix mtx((icUInt8Number*)m_vals, m_nBytesPerMatrix, icSparseMatrixFloatNum, true);
4698
4699 mtx.MultiplyVector(pDst, pSrc);
4700}
4701
4702
4703/**
4704**************************************************************************
4705* Name: CIccPcsStepSparseMatrix::dump
4706*
4707* Purpose:
4708* dumps the context of the step
4709**************************************************************************
4710*/
4711void CIccPcsStepSparseMatrix::dump(std::string &str) const
4712{
4713 str += "\nCIccPcsStepSparseMatrix\n\n";
4714// char buf[80];
4715// for (int i=0; i<m_nCols; i++) {
4716// sprintf(buf, ICCPCSSTEPDUMPFMT, m_vals[i]);
4717// str += buf;
4718// }
4719// str += "\n";
4720}
4721
4722
4723/**
4724**************************************************************************
4725* Name: CIccPcsStepSrcSparseMatrix::CIccPcsStepSrcSparseMatrix
4726*
4727* Purpose:
4728* Constructor
4729**************************************************************************
4730*/
4731CIccPcsStepSrcSparseMatrix::CIccPcsStepSrcSparseMatrix(icUInt16Number nRows, icUInt16Number nCols, icUInt16Number nChannels)
4732{
4733 m_nRows = nRows;
4734 m_nCols = nCols;
4735 m_nChannels = nChannels;
4736 m_nBytesPerMatrix = nChannels * sizeof(icFloatNumber);
4737
4738 m_vals = new icFloatNumber[nCols];
4739}
4740
4741
4742/**
4743**************************************************************************
4744* Name: CIccPcsStepSrcSparseMatrix::~CIccPcsSrcStepSparseMatrix
4745*
4746* Purpose:
4747* Destructor
4748**************************************************************************
4749*/
4750CIccPcsStepSrcSparseMatrix::~CIccPcsStepSrcSparseMatrix()
4751{
4752 if (m_vals)
4753 delete [] m_vals;
4754}
4755
4756
4757/**
4758**************************************************************************
4759* Name: CIccPcsStepSrcSparseMatrix::Apply
4760*
4761* Purpose:
4762* Multiplies illuminant stored in m_vals by pSrc matrix passed in resulting
4763* in a pDst vector
4764**************************************************************************
4765*/
4766void CIccPcsStepSrcSparseMatrix::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const
4767{
4768 CIccSparseMatrix mtx((icUInt8Number*)pSrc, m_nBytesPerMatrix, icSparseMatrixFloatNum, true);
4769
4770 mtx.MultiplyVector(pDst, m_vals);
4771}
4772
4773
4774/**
4775**************************************************************************
4776* Name: CIccPcsStepSrcSparseMatrix::dump
4777*
4778* Purpose:
4779* dumps the context of the step
4780**************************************************************************
4781*/
4782void CIccPcsStepSrcSparseMatrix::dump(std::string &str) const
4783{
4784 str += "\nCIccPcsStepSrcSparseMatrix\n\n";
4785 char buf[80];
4786 for (int i=0; i<m_nCols; i++) {
4787 sprintf(buf, ICCPCSSTEPDUMPFMT, m_vals[i]);
4788 str += buf;
4789 }
4790 str += "\n";
4791}
4792
4793
4794/**
4795**************************************************************************
4796* Name: CIccXformMonochrome::CIccXformMonochrome
4797*
4798* Purpose:
4799* Constructor
4800**************************************************************************
4801*/
4802CIccXformMonochrome::CIccXformMonochrome()
4803{
4804 m_Curve = NULL;
4805 m_ApplyCurvePtr = NULL;
4806 m_bFreeCurve = false;
4807}
4808
4809/**
4810**************************************************************************
4811* Name: CIccXformMonochrome::~CIccXformMonochrome
4812*
4813* Purpose:
4814* Destructor
4815**************************************************************************
4816*/
4817CIccXformMonochrome::~CIccXformMonochrome()
4818{
4819 if (m_bFreeCurve && m_Curve) {
4820 delete m_Curve;
4821 }
4822}
4823
4824/**
4825**************************************************************************
4826* Name: CIccXformMonochrome::Begin
4827*
4828* Purpose:
4829* Does the initialization of the Xform before Apply() is called.
4830* Must be called before Apply().
4831*
4832**************************************************************************
4833*/
4834icStatusCMM CIccXformMonochrome::Begin()
4835{
4836 icStatusCMM status;
4837
4838 status = CIccXform::Begin();
4839 if (status != icCmmStatOk)
4840 return status;
4841
4842 m_ApplyCurvePtr = NULL;
4843
4844 if (m_bInput) {
4845 m_Curve = GetCurve(icSigGrayTRCTag);
4846
4847 if (!m_Curve) {
4849 }
4850 }
4851 else {
4852 m_Curve = GetInvCurve(icSigGrayTRCTag);
4853 m_bFreeCurve = true;
4854
4855 if (!m_Curve) {
4857 }
4858 }
4859
4860 m_Curve->Begin();
4861 if (!m_Curve->IsIdentity()) {
4862 m_ApplyCurvePtr = m_Curve;
4863 }
4864
4865 return icCmmStatOk;
4866}
4867
4868/**
4869**************************************************************************
4870* Name: CIccXformMonochrome::Apply
4871*
4872* Purpose:
4873* Does the actual application of the Xform.
4874*
4875* Args:
4876* pApply = ApplyXform object containing temporary storage used during Apply
4877* DstPixel = Destination pixel where the result is stored,
4878* SrcPixel = Source pixel which is to be applied.
4879**************************************************************************
4880*/
4881void CIccXformMonochrome::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
4882{
4883 icFloatNumber Pixel[3];
4884 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
4885
4886 if (m_bInput) {
4887 Pixel[0] = SrcPixel[0];
4888
4889 if (m_ApplyCurvePtr) {
4890 Pixel[0] = m_ApplyCurvePtr->Apply(Pixel[0]);
4891 }
4892
4893 DstPixel[0] = icFloatNumber(icPerceptualRefWhiteX);
4894 DstPixel[1] = icFloatNumber(icPerceptualRefWhiteY);
4895 DstPixel[2] = icFloatNumber(icPerceptualRefWhiteZ);
4896
4897 icXyzToPcs(DstPixel);
4898
4899 if (m_pProfile->m_Header.pcs==icSigLabData) {
4900 if (UseLegacyPCS()) {
4901 CIccPCS::XyzToLab2(DstPixel, DstPixel, true);
4902 }
4903 else {
4904 CIccPCS::XyzToLab(DstPixel, DstPixel, true);
4905 }
4906 }
4907
4908 DstPixel[0] *= Pixel[0];
4909 DstPixel[1] *= Pixel[0];
4910 DstPixel[2] *= Pixel[0];
4911 }
4912 else {
4916
4917 icXyzToPcs(Pixel);
4918
4919 if (m_pProfile->m_Header.pcs==icSigLabData) {
4920 if (UseLegacyPCS()) {
4921 CIccPCS::XyzToLab2(Pixel, Pixel, true);
4922 }
4923 else {
4924 CIccPCS::XyzToLab(Pixel, Pixel, true);
4925 }
4926 DstPixel[0] = SrcPixel[0]/Pixel[0];
4927 }
4928 else {
4929 DstPixel[0] = SrcPixel[1]/Pixel[1];
4930 }
4931
4932 if (m_ApplyCurvePtr) {
4933 DstPixel[0] = m_ApplyCurvePtr->Apply(DstPixel[0]);
4934 }
4935 }
4936
4937 CheckDstAbs(DstPixel);
4938}
4939
4940/**
4941**************************************************************************
4942* Name: CIccXformMonochrome::GetCurve
4943*
4944* Purpose:
4945* Gets the curve having the passed signature, from the profile.
4946*
4947* Args:
4948* sig = signature of the curve to be found
4949*
4950* Return:
4951* Pointer to the curve.
4952**************************************************************************
4953*/
4954CIccCurve *CIccXformMonochrome::GetCurve(icSignature sig) const
4955{
4956 CIccTag *pTag = m_pProfile->FindTag(sig);
4957
4958 if (pTag && (pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType)) {
4959 return (CIccCurve*)pTag;
4960 }
4961
4962 return NULL;
4963}
4964
4965/**
4966**************************************************************************
4967* Name: CIccXformMonochrome::GetInvCurve
4968*
4969* Purpose:
4970* Gets the inverted curve having the passed signature, from the profile.
4971*
4972* Args:
4973* sig = signature of the curve to be inverted
4974*
4975* Return:
4976* Pointer to the inverted curve.
4977**************************************************************************
4978*/
4979CIccCurve *CIccXformMonochrome::GetInvCurve(icSignature sig) const
4980{
4981 CIccCurve *pCurve;
4982 CIccTagCurve *pInvCurve;
4983
4984 if (!(pCurve = GetCurve(sig)))
4985 return NULL;
4986
4987 pCurve->Begin();
4988
4989 pInvCurve = new CIccTagCurve(2048);
4990
4991 int i;
4992 icFloatNumber x;
4993 icFloatNumber *Lut = &(*pInvCurve)[0];
4994
4995 for (i=0; i<2048; i++) {
4996 x=(icFloatNumber)i / 2047;
4997
4998 Lut[i] = pCurve->Find(x);
4999 }
5000
5001 return pInvCurve;
5002}
5003
5004/**
5005**************************************************************************
5006* Name: CIccXformMonochrome::ExtractInputCurves
5007*
5008* Purpose:
5009* Gets the input curves. Should be called only after Begin()
5010* has been called. Once the curves are extracted, they will
5011* not be used by the Apply() function.
5012* WARNING: caller owns the curves and must be deleted by the caller.
5013*
5014* Return:
5015* Pointer to the input curves.
5016**************************************************************************
5017*/
5018LPIccCurve* CIccXformMonochrome::ExtractInputCurves()
5019{
5020 if (m_bInput) {
5021 if (m_Curve) {
5022 LPIccCurve* Curve = new LPIccCurve[1];
5023 Curve[0] = (LPIccCurve)(m_Curve->NewCopy());
5024 m_ApplyCurvePtr = NULL;
5025 return Curve;
5026 }
5027 }
5028
5029 return NULL;
5030}
5031
5032/**
5033**************************************************************************
5034* Name: CIccXformMonochrome::ExtractOutputCurves
5035*
5036* Purpose:
5037* Gets the output curves. Should be called only after Begin()
5038* has been called. Once the curves are extracted, they will
5039* not be used by the Apply() function.
5040* WARNING: caller owns the curves and must be deleted by the caller.
5041*
5042* Return:
5043* Pointer to the output curves.
5044**************************************************************************
5045*/
5046LPIccCurve* CIccXformMonochrome::ExtractOutputCurves()
5047{
5048 if (!m_bInput) {
5049 if (m_Curve) {
5050 LPIccCurve* Curve = new LPIccCurve[1];
5051 Curve[0] = (LPIccCurve)(m_Curve->NewCopy());
5052 m_ApplyCurvePtr = NULL;
5053 return Curve;
5054 }
5055 }
5056
5057 return NULL;
5058}
5059
5060/**
5061 **************************************************************************
5062 * Name: CIccXformMatrixTRC::CIccXformMatrixTRC
5063 *
5064 * Purpose:
5065 * Constructor
5066 **************************************************************************
5067 */
5068CIccXformMatrixTRC::CIccXformMatrixTRC() : m_e{}
5069{
5070 m_Curve[0] = m_Curve[1] = m_Curve[2] = NULL;
5071 m_ApplyCurvePtr = NULL;
5072 m_bFreeCurve = false;
5073}
5074
5075/**
5076 **************************************************************************
5077 * Name: CIccXformMatrixTRC::~CIccXformMatrixTRC
5078 *
5079 * Purpose:
5080 * Destructor
5081 **************************************************************************
5082 */
5083CIccXformMatrixTRC::~CIccXformMatrixTRC()
5084{
5085 if (m_bFreeCurve) {
5086 if (m_Curve[0])
5087 delete m_Curve[0];
5088 if (m_Curve[1])
5089 delete m_Curve[1];
5090 if (m_Curve[2])
5091 delete m_Curve[2];
5092 }
5093}
5094
5095/**
5096 **************************************************************************
5097 * Name: CIccXformMatrixTRC::Begin
5098 *
5099 * Purpose:
5100 * Does the initialization of the Xform before Apply() is called.
5101 * Must be called before Apply().
5102 *
5103 **************************************************************************
5104 */
5105icStatusCMM CIccXformMatrixTRC::Begin()
5106{
5107 icStatusCMM status;
5108 const CIccTagXYZ *pXYZ;
5109
5110 status = CIccXform::Begin();
5111 if (status != icCmmStatOk)
5112 return status;
5113
5114 pXYZ = GetColumn(icSigRedMatrixColumnTag);
5115 if (!pXYZ) {
5117 }
5118
5119 m_e[0] = icFtoD((*pXYZ)[0].X);
5120 m_e[3] = icFtoD((*pXYZ)[0].Y);
5121 m_e[6] = icFtoD((*pXYZ)[0].Z);
5122
5123 pXYZ = GetColumn(icSigGreenMatrixColumnTag);
5124 if (!pXYZ) {
5126 }
5127
5128 m_e[1] = icFtoD((*pXYZ)[0].X);
5129 m_e[4] = icFtoD((*pXYZ)[0].Y);
5130 m_e[7] = icFtoD((*pXYZ)[0].Z);
5131
5132 pXYZ = GetColumn(icSigBlueMatrixColumnTag);
5133 if (!pXYZ) {
5135 }
5136
5137 m_e[2] = icFtoD((*pXYZ)[0].X);
5138 m_e[5] = icFtoD((*pXYZ)[0].Y);
5139 m_e[8] = icFtoD((*pXYZ)[0].Z);
5140
5141 m_ApplyCurvePtr = NULL;
5142
5143 if (m_bInput) {
5144 m_Curve[0] = GetCurve(icSigRedTRCTag);
5145 m_Curve[1] = GetCurve(icSigGreenTRCTag);
5146 m_Curve[2] = GetCurve(icSigBlueTRCTag);
5147
5148 if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) {
5150 }
5151
5152 }
5153 else {
5154 if (m_pProfile->m_Header.pcs!=icSigXYZData) {
5155 return icCmmStatBadSpaceLink;
5156 }
5157
5158 m_Curve[0] = GetInvCurve(icSigRedTRCTag);
5159 m_Curve[1] = GetInvCurve(icSigGreenTRCTag);
5160 m_Curve[2] = GetInvCurve(icSigBlueTRCTag);
5161
5162 m_bFreeCurve = true;
5163
5164 if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) {
5166 }
5167
5168 if (!icMatrixInvert3x3(m_e)) {
5170 }
5171 }
5172
5173 m_Curve[0]->Begin();
5174 m_Curve[1]->Begin();
5175 m_Curve[2]->Begin();
5176
5177 if (!m_Curve[0]->IsIdentity() || !m_Curve[1]->IsIdentity() || !m_Curve[2]->IsIdentity()) {
5178 m_ApplyCurvePtr = m_Curve;
5179 }
5180
5181 return icCmmStatOk;
5182}
5183
5184
5186{
5187 v = (icFloatNumber)(v * 32768.0 / 65535.0);
5188 return v;
5189}
5190
5192{
5193 return (icFloatNumber)(v * 65535.0 / 32768.0);
5194}
5195
5197{
5198 if (v<=0)
5199 return(pCurve->Apply(0));
5200 else if (v>=1.0)
5201 return (pCurve->Apply(1.0));
5202
5203 return pCurve->Apply(v);
5204}
5205
5206/**
5207 **************************************************************************
5208 * Name: CIccXformMatrixTRC::Apply
5209 *
5210 * Purpose:
5211 * Does the actual application of the Xform.
5212 *
5213 * Args:
5214 * pApply = ApplyXform object containging temporary storage used during Apply
5215 * DstPixel = Destination pixel where the result is stored,
5216 * SrcPixel = Source pixel which is to be applied.
5217 **************************************************************************
5218 */
5219void CIccXformMatrixTRC::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
5220{
5221 icFloatNumber Pixel[3];
5222
5223 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
5224 Pixel[0] = SrcPixel[0];
5225 Pixel[1] = SrcPixel[1];
5226 Pixel[2] = SrcPixel[2];
5227
5228 if (m_bInput) {
5229
5230 double LinR, LinG, LinB;
5231 if (m_ApplyCurvePtr) {
5232 LinR = m_ApplyCurvePtr[0]->Apply(Pixel[0]);
5233 LinG = m_ApplyCurvePtr[1]->Apply(Pixel[1]);
5234 LinB = m_ApplyCurvePtr[2]->Apply(Pixel[2]);
5235 }
5236 else {
5237 LinR = Pixel[0];
5238 LinG = Pixel[1];
5239 LinB = Pixel[2];
5240 }
5241
5242 DstPixel[0] = XYZScale((icFloatNumber)(m_e[0] * LinR + m_e[1] * LinG + m_e[2] * LinB));
5243 DstPixel[1] = XYZScale((icFloatNumber)(m_e[3] * LinR + m_e[4] * LinG + m_e[5] * LinB));
5244 DstPixel[2] = XYZScale((icFloatNumber)(m_e[6] * LinR + m_e[7] * LinG + m_e[8] * LinB));
5245 }
5246 else {
5247 double X = XYZDescale(Pixel[0]);
5248 double Y = XYZDescale(Pixel[1]);
5249 double Z = XYZDescale(Pixel[2]);
5250
5251 if (m_ApplyCurvePtr) {
5252 DstPixel[0] = RGBClip((icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z), m_ApplyCurvePtr[0]);
5253 DstPixel[1] = RGBClip((icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z), m_ApplyCurvePtr[1]);
5254 DstPixel[2] = RGBClip((icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z), m_ApplyCurvePtr[2]);
5255 }
5256 else {
5257 DstPixel[0] = (icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z);
5258 DstPixel[1] = (icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z);
5259 DstPixel[2] = (icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z);
5260 }
5261 }
5262
5263 CheckDstAbs(DstPixel);
5264}
5265
5266/**
5267 **************************************************************************
5268 * Name: CIccXformMatrixTRC::GetCurve
5269 *
5270 * Purpose:
5271 * Gets the curve having the passed signature, from the profile.
5272 *
5273 * Args:
5274 * sig = signature of the curve to be found
5275 *
5276 * Return:
5277 * Pointer to the curve.
5278 **************************************************************************
5279 */
5280CIccCurve *CIccXformMatrixTRC::GetCurve(icSignature sig) const
5281{
5282 CIccTag *pTag = m_pProfile->FindTag(sig);
5283
5284 if (pTag && pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType) {
5285 return (CIccCurve*)pTag;
5286 }
5287
5288 return NULL;
5289}
5290
5291/**
5292 **************************************************************************
5293 * Name: CIccXformMatrixTRC::GetColumn
5294 *
5295 * Purpose:
5296 * Gets the XYZ tag from the profile.
5297 *
5298 * Args:
5299 * sig = signature of the XYZ tag to be found.
5300 *
5301 * Return:
5302 * Pointer to the XYZ tag.
5303 **************************************************************************
5304 */
5305CIccTagXYZ *CIccXformMatrixTRC::GetColumn(icSignature sig) const
5306{
5307 CIccTag *pTag = m_pProfile->FindTag(sig);
5308
5309 if (!pTag || pTag->GetType()!=icSigXYZType) {
5310 return NULL;
5311 }
5312
5313 return (CIccTagXYZ*)pTag;
5314}
5315
5316/**
5317 **************************************************************************
5318 * Name: CIccXformMatrixTRC::GetInvCurve
5319 *
5320 * Purpose:
5321 * Gets the inverted curve having the passed signature, from the profile.
5322 *
5323 * Args:
5324 * sig = signature of the curve to be inverted
5325 *
5326 * Return:
5327 * Pointer to the inverted curve.
5328 **************************************************************************
5329 */
5330CIccCurve *CIccXformMatrixTRC::GetInvCurve(icSignature sig) const
5331{
5332 CIccCurve *pCurve;
5333 CIccTagCurve *pInvCurve;
5334
5335 if (!(pCurve = GetCurve(sig)))
5336 return NULL;
5337
5338 pCurve->Begin();
5339
5340 pInvCurve = new CIccTagCurve(2048);
5341
5342 int i;
5343 icFloatNumber x;
5344 icFloatNumber *Lut = &(*pInvCurve)[0];
5345
5346 for (i=0; i<2048; i++) {
5347 x=(icFloatNumber)i / 2047;
5348
5349 Lut[i] = pCurve->Find(x);
5350 }
5351
5352 return pInvCurve;
5353}
5354
5355/**
5356**************************************************************************
5357* Name: CIccXformMatrixTRC::ExtractInputCurves
5358*
5359* Purpose:
5360* Gets the input curves. Should be called only after Begin()
5361* has been called. Once the curves are extracted, they will
5362* not be used by the Apply() function.
5363* WARNING: caller owns the curves and must be deleted by the caller.
5364*
5365* Return:
5366* Pointer to the input curves.
5367**************************************************************************
5368*/
5369LPIccCurve* CIccXformMatrixTRC::ExtractInputCurves()
5370{
5371 if (m_bInput) {
5372 if (m_Curve[0]) {
5373 LPIccCurve* Curve = new LPIccCurve[3];
5374 Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy());
5375 Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy());
5376 Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy());
5377 m_ApplyCurvePtr = NULL;
5378 return Curve;
5379 }
5380 }
5381
5382 return NULL;
5383}
5384
5385/**
5386**************************************************************************
5387* Name: CIccXformMatrixTRC::ExtractOutputCurves
5388*
5389* Purpose:
5390* Gets the output curves. Should be called only after Begin()
5391* has been called. Once the curves are extracted, they will
5392* not be used by the Apply() function.
5393* WARNING: caller owns the curves and must be deleted by the caller.
5394*
5395* Return:
5396* Pointer to the output curves.
5397**************************************************************************
5398*/
5399LPIccCurve* CIccXformMatrixTRC::ExtractOutputCurves()
5400{
5401 if (!m_bInput) {
5402 if (m_Curve[0]) {
5403 LPIccCurve* Curve = new LPIccCurve[3];
5404 Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy());
5405 Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy());
5406 Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy());
5407 m_ApplyCurvePtr = NULL;
5408 return Curve;
5409 }
5410 }
5411
5412 return NULL;
5413}
5414
5415/**
5416 **************************************************************************
5417 * Name: CIccXform3DLut::CIccXform3DLut
5418 *
5419 * Purpose:
5420 * Constructor
5421 *
5422 * Args:
5423 * pTag = Pointer to the tag of type CIccMBB
5424 **************************************************************************
5425 */
5426CIccXform3DLut::CIccXform3DLut(CIccTag *pTag)
5427{
5428 if (pTag && pTag->IsMBBType()) {
5429 m_pTag = (CIccMBB*)pTag;
5430 }
5431 else
5432 m_pTag = NULL;
5433
5434 m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
5435 m_ApplyMatrixPtr = NULL;
5436}
5437
5438/**
5439 **************************************************************************
5440 * Name: CIccXform3DLut::~CIccXform3DLut
5441 *
5442 * Purpose:
5443 * Destructor
5444 **************************************************************************
5445 */
5446CIccXform3DLut::~CIccXform3DLut()
5447{
5448}
5449
5450/**
5451 **************************************************************************
5452 * Name: CIccXform3DLut::Begin
5453 *
5454 * Purpose:
5455 * Does the initialization of the Xform before Apply() is called.
5456 * Must be called before Apply().
5457 *
5458 **************************************************************************
5459 */
5460 icStatusCMM CIccXform3DLut::Begin()
5461{
5462 icStatusCMM status;
5463 CIccCurve **Curve;
5464 int i;
5465
5466 status = CIccXform::Begin();
5467 if (status != icCmmStatOk)
5468 return status;
5469
5470 if (!m_pTag ||
5471 m_pTag->InputChannels()!=3) {
5472 return icCmmStatInvalidLut;
5473 }
5474
5475 m_ApplyCurvePtrA = NULL;
5476 m_ApplyCurvePtrB = NULL;
5477 m_ApplyCurvePtrM = NULL;
5478
5479 if (m_pTag->m_bInputMatrix) {
5480 if (m_pTag->m_CurvesB) {
5481 Curve = m_pTag->m_CurvesB;
5482
5483 Curve[0]->Begin();
5484 Curve[1]->Begin();
5485 Curve[2]->Begin();
5486
5487 if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) {
5488 m_ApplyCurvePtrB = Curve;
5489 }
5490 }
5491
5492 if (m_pTag->m_CurvesM) {
5493 Curve = m_pTag->m_CurvesM;
5494
5495 Curve[0]->Begin();
5496 Curve[1]->Begin();
5497 Curve[2]->Begin();
5498
5499 if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) {
5500 m_ApplyCurvePtrM = Curve;
5501 }
5502 }
5503
5504 if (m_pTag->m_CLUT) {
5505 m_pTag->m_CLUT->Begin();
5506 }
5507
5508 if (m_pTag->m_CurvesA) {
5509 Curve = m_pTag->m_CurvesA;
5510
5511 for (i=0; i<m_pTag->m_nOutput; i++) {
5512 Curve[i]->Begin();
5513 }
5514
5515 for (i=0; i<m_pTag->m_nOutput; i++) {
5516 if (!Curve[i]->IsIdentity()) {
5517 m_ApplyCurvePtrA = Curve;
5518 break;
5519 }
5520 }
5521 }
5522
5523 }
5524 else {
5525 if (m_pTag->m_CurvesA) {
5526 Curve = m_pTag->m_CurvesA;
5527
5528 Curve[0]->Begin();
5529 Curve[1]->Begin();
5530 Curve[2]->Begin();
5531
5532 if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) {
5533 m_ApplyCurvePtrA = Curve;
5534 }
5535 }
5536
5537 if (m_pTag->m_CLUT) {
5538 m_pTag->m_CLUT->Begin();
5539 }
5540
5541 if (m_pTag->m_CurvesM) {
5542 Curve = m_pTag->m_CurvesM;
5543
5544 for (i=0; i<m_pTag->m_nOutput; i++) {
5545 Curve[i]->Begin();
5546 }
5547
5548 for (i=0; i<m_pTag->m_nOutput; i++) {
5549 if (!Curve[i]->IsIdentity()) {
5550 m_ApplyCurvePtrM = Curve;
5551 break;
5552 }
5553 }
5554 }
5555
5556 if (m_pTag->m_CurvesB) {
5557 Curve = m_pTag->m_CurvesB;
5558
5559 for (i=0; i<m_pTag->m_nOutput; i++) {
5560 Curve[i]->Begin();
5561 }
5562
5563 for (i=0; i<m_pTag->m_nOutput; i++) {
5564 if (!Curve[i]->IsIdentity()) {
5565 m_ApplyCurvePtrB = Curve;
5566 break;
5567 }
5568 }
5569 }
5570 }
5571
5572 m_ApplyMatrixPtr = NULL;
5573 if (m_pTag->m_Matrix) {
5574 if (m_pTag->m_bInputMatrix) {
5575 if (m_pTag->m_nInput!=3) {
5577 }
5578 }
5579 else {
5580 if (m_pTag->m_nOutput!=3) {
5582 }
5583 }
5584
5585 if (!m_pTag->m_Matrix->IsIdentity()) {
5586 m_ApplyMatrixPtr = m_pTag->m_Matrix;
5587 }
5588 }
5589
5590 return icCmmStatOk;
5591}
5592
5593/**
5594 **************************************************************************
5595 * Name: CIccXform3DLut::Apply
5596 *
5597 * Purpose:
5598 * Does the actual application of the Xform.
5599 *
5600 * Args:
5601 * pApply = ApplyXform object containing temporary storage used during Apply
5602 * DstPixel = Destination pixel where the result is stored,
5603 * SrcPixel = Source pixel which is to be applied.
5604 **************************************************************************
5605 */
5606void CIccXform3DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
5607{
5608 icFloatNumber Pixel[16];
5609 int i;
5610
5611 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
5612 Pixel[0] = SrcPixel[0];
5613 Pixel[1] = SrcPixel[1];
5614 Pixel[2] = SrcPixel[2];
5615
5616 if (m_pTag->m_bInputMatrix) {
5617 if (m_ApplyCurvePtrB) {
5618 Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]);
5619 Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]);
5620 Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]);
5621 }
5622
5623 if (m_ApplyMatrixPtr) {
5624 m_ApplyMatrixPtr->Apply(Pixel);
5625 }
5626
5627 if (m_ApplyCurvePtrM) {
5628 Pixel[0] = m_ApplyCurvePtrM[0]->Apply(Pixel[0]);
5629 Pixel[1] = m_ApplyCurvePtrM[1]->Apply(Pixel[1]);
5630 Pixel[2] = m_ApplyCurvePtrM[2]->Apply(Pixel[2]);
5631 }
5632
5633 if (m_pTag->m_CLUT) {
5634 if (m_nInterp==icInterpLinear)
5635 m_pTag->m_CLUT->Interp3d(Pixel, Pixel);
5636 else
5637 m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel);
5638 }
5639
5640 if (m_ApplyCurvePtrA) {
5641 for (i=0; i<m_pTag->m_nOutput; i++) {
5642 Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]);
5643 }
5644 }
5645
5646 }
5647 else {
5648 if (m_ApplyCurvePtrA) {
5649 Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]);
5650 Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]);
5651 Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]);
5652 }
5653
5654 if (m_pTag->m_CLUT) {
5655 if (m_nInterp==icInterpLinear)
5656 m_pTag->m_CLUT->Interp3d(Pixel, Pixel);
5657 else
5658 m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel);
5659 }
5660
5661 if (m_ApplyCurvePtrM) {
5662 for (i=0; i<m_pTag->m_nOutput; i++) {
5663 Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]);
5664 }
5665 }
5666
5667 if (m_ApplyMatrixPtr) {
5668 m_ApplyMatrixPtr->Apply(Pixel);
5669 }
5670
5671 if (m_ApplyCurvePtrB) {
5672 for (i=0; i<m_pTag->m_nOutput; i++) {
5673 Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]);
5674 }
5675 }
5676 }
5677
5678 for (i=0; i<m_pTag->m_nOutput; i++) {
5679 DstPixel[i] = Pixel[i];
5680 }
5681
5682 CheckDstAbs(DstPixel);
5683}
5684
5685/**
5686**************************************************************************
5687* Name: CIccXform3DLut::ExtractInputCurves
5688*
5689* Purpose:
5690* Gets the input curves. Should be called only after Begin()
5691* has been called. Once the curves are extracted, they will
5692* not be used by the Apply() function.
5693* WARNING: caller owns the curves and must be deleted by the caller.
5694*
5695* Return:
5696* Pointer to the input curves.
5697**************************************************************************
5698*/
5699LPIccCurve* CIccXform3DLut::ExtractInputCurves()
5700{
5701 if (m_bInput) {
5702 if (m_pTag->m_bInputMatrix) {
5703 if (m_pTag->m_CurvesB) {
5704 LPIccCurve* Curve = new LPIccCurve[3];
5705 Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy());
5706 Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy());
5707 Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy());
5708 m_ApplyCurvePtrB = NULL;
5709 return Curve;
5710 }
5711 }
5712 else {
5713 if (m_pTag->m_CurvesA) {
5714 LPIccCurve* Curve = new LPIccCurve[3];
5715 Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy());
5716 Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy());
5717 Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy());
5718 m_ApplyCurvePtrA = NULL;
5719 return Curve;
5720 }
5721 }
5722 }
5723
5724 return NULL;
5725}
5726
5727/**
5728**************************************************************************
5729* Name: CIccXform3DLut::ExtractOutputCurves
5730*
5731* Purpose:
5732* Gets the output curves. Should be called only after Begin()
5733* has been called. Once the curves are extracted, they will
5734* not be used by the Apply() function.
5735* WARNING: caller owns the curves and must be deleted by the caller.
5736*
5737* Return:
5738* Pointer to the output curves.
5739**************************************************************************
5740*/
5741LPIccCurve* CIccXform3DLut::ExtractOutputCurves()
5742{
5743 if (!m_bInput) {
5744 if (m_pTag->m_bInputMatrix) {
5745 if (m_pTag->m_CurvesA) {
5746 LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
5747 for (int i=0; i<m_pTag->m_nOutput; i++) {
5748 Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy());
5749 }
5750 m_ApplyCurvePtrA = NULL;
5751 return Curve;
5752 }
5753 }
5754 else {
5755 if (m_pTag->m_CurvesB) {
5756 LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
5757 for (int i=0; i<m_pTag->m_nOutput; i++) {
5758 Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy());
5759 }
5760 m_ApplyCurvePtrB = NULL;
5761 return Curve;
5762 }
5763 }
5764 }
5765
5766 return NULL;
5767}
5768
5769/**
5770 **************************************************************************
5771 * Name: CIccXform4DLut::CIccXform4DLut
5772 *
5773 * Purpose:
5774 * Constructor
5775 *
5776 * Args:
5777 * pTag = Pointer to the tag of type CIccMBB
5778 **************************************************************************
5779 */
5780CIccXform4DLut::CIccXform4DLut(CIccTag *pTag)
5781{
5782 if (pTag && pTag->IsMBBType()) {
5783 m_pTag = (CIccMBB*)pTag;
5784 }
5785 else
5786 m_pTag = NULL;
5787
5788 m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
5789 m_ApplyMatrixPtr = NULL;
5790}
5791
5792
5793/**
5794 **************************************************************************
5795 * Name: CIccXform4DLut::~CIccXform4DLut
5796 *
5797 * Purpose:
5798 * Destructor
5799 **************************************************************************
5800 */
5801CIccXform4DLut::~CIccXform4DLut()
5802{
5803}
5804
5805
5806/**
5807 **************************************************************************
5808 * Name: CIccXform4DLut::Begin
5809 *
5810 * Purpose:
5811 * Does the initialization of the Xform before Apply() is called.
5812 * Must be called before Apply().
5813 *
5814 **************************************************************************
5815 */
5816icStatusCMM CIccXform4DLut::Begin()
5817{
5818 icStatusCMM status;
5819 CIccCurve **Curve;
5820 int i;
5821
5822 status = CIccXform::Begin();
5823 if (status != icCmmStatOk) {
5824 return status;
5825 }
5826
5827 if (!m_pTag ||
5828 m_pTag->InputChannels()!=4) {
5829 return icCmmStatInvalidLut;
5830 }
5831
5832 m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
5833
5834 if (m_pTag->m_bInputMatrix) {
5835 if (m_pTag->m_CurvesB) {
5836 Curve = m_pTag->m_CurvesB;
5837
5838 Curve[0]->Begin();
5839 Curve[1]->Begin();
5840 Curve[2]->Begin();
5841 Curve[3]->Begin();
5842
5843 if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() ||
5844 !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity())
5845 {
5846 m_ApplyCurvePtrB = Curve;
5847 }
5848 }
5849
5850 if (m_pTag->m_CLUT) {
5851 m_pTag->m_CLUT->Begin();
5852 }
5853
5854 if (m_pTag->m_CurvesA) {
5855 Curve = m_pTag->m_CurvesA;
5856
5857 for (i=0; i<m_pTag->m_nOutput; i++) {
5858 Curve[i]->Begin();
5859 }
5860
5861 for (i=0; i<m_pTag->m_nOutput; i++) {
5862 if (!Curve[i]->IsIdentity()) {
5863 m_ApplyCurvePtrA = Curve;
5864 break;
5865 }
5866 }
5867 }
5868
5869 }
5870 else {
5871 if (m_pTag->m_CurvesA) {
5872 Curve = m_pTag->m_CurvesA;
5873
5874 Curve[0]->Begin();
5875 Curve[1]->Begin();
5876 Curve[2]->Begin();
5877 Curve[3]->Begin();
5878
5879 if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() ||
5880 !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity())
5881 {
5882 m_ApplyCurvePtrA = Curve;
5883 }
5884 }
5885
5886 if (m_pTag->m_CLUT) {
5887 m_pTag->m_CLUT->Begin();
5888 }
5889
5890 if (m_pTag->m_CurvesM) {
5891 Curve = m_pTag->m_CurvesM;
5892
5893 for (i=0; i<m_pTag->m_nOutput; i++) {
5894 Curve[i]->Begin();
5895 }
5896
5897 for (i=0; i<m_pTag->m_nOutput; i++) {
5898 if (!Curve[i]->IsIdentity()) {
5899 m_ApplyCurvePtrM = Curve;
5900 break;
5901 }
5902 }
5903 }
5904
5905 if (m_pTag->m_CurvesB) {
5906 Curve = m_pTag->m_CurvesB;
5907
5908 for (i=0; i<m_pTag->m_nOutput; i++) {
5909 Curve[i]->Begin();
5910 }
5911
5912 for (i=0; i<m_pTag->m_nOutput; i++) {
5913 if (!Curve[i]->IsIdentity()) {
5914 m_ApplyCurvePtrB = Curve;
5915 break;
5916 }
5917 }
5918 }
5919 }
5920
5921 m_ApplyMatrixPtr = NULL;
5922 if (m_pTag->m_Matrix) {
5923 if (m_pTag->m_bInputMatrix) {
5925 }
5926 else {
5927 if (m_pTag->m_nOutput!=3) {
5929 }
5930 }
5931
5932 if (!m_pTag->m_Matrix->IsIdentity()) {
5933 m_ApplyMatrixPtr = m_pTag->m_Matrix;
5934 }
5935 }
5936
5937 return icCmmStatOk;
5938}
5939
5940
5941/**
5942 **************************************************************************
5943 * Name: CIccXform4DLut::Apply
5944 *
5945 * Purpose:
5946 * Does the actual application of the Xform.
5947 *
5948 * Args:
5949 * pApply = ApplyXform object containging temporary storage used during Apply
5950 * DstPixel = Destination pixel where the result is stored,
5951 * SrcPixel = Source pixel which is to be applied.
5952 **************************************************************************
5953 */
5954void CIccXform4DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
5955{
5956 icFloatNumber Pixel[16];
5957 int i;
5958
5959 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
5960 Pixel[0] = SrcPixel[0];
5961 Pixel[1] = SrcPixel[1];
5962 Pixel[2] = SrcPixel[2];
5963 Pixel[3] = SrcPixel[3];
5964
5965 if (m_pTag->m_bInputMatrix) {
5966 if (m_ApplyCurvePtrB) {
5967 Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]);
5968 Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]);
5969 Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]);
5970 Pixel[3] = m_ApplyCurvePtrB[3]->Apply(Pixel[3]);
5971 }
5972
5973 if (m_pTag->m_CLUT) {
5974 m_pTag->m_CLUT->Interp4d(Pixel, Pixel);
5975 }
5976
5977 if (m_ApplyCurvePtrA) {
5978 for (i=0; i<m_pTag->m_nOutput; i++) {
5979 Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]);
5980 }
5981 }
5982
5983 }
5984 else {
5985 if (m_ApplyCurvePtrA) {
5986 Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]);
5987 Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]);
5988 Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]);
5989 Pixel[3] = m_ApplyCurvePtrA[3]->Apply(Pixel[3]);
5990 }
5991
5992 if (m_pTag->m_CLUT) {
5993 m_pTag->m_CLUT->Interp4d(Pixel, Pixel);
5994 }
5995
5996 if (m_ApplyCurvePtrM) {
5997 for (i=0; i<m_pTag->m_nOutput; i++) {
5998 Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]);
5999 }
6000 }
6001
6002 if (m_ApplyMatrixPtr) {
6003 m_ApplyMatrixPtr->Apply(Pixel);
6004 }
6005
6006 if (m_ApplyCurvePtrB) {
6007 for (i=0; i<m_pTag->m_nOutput; i++) {
6008 Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]);
6009 }
6010 }
6011 }
6012
6013 for (i=0; i<m_pTag->m_nOutput; i++) {
6014 DstPixel[i] = Pixel[i];
6015 }
6016
6017 CheckDstAbs(DstPixel);
6018}
6019
6020/**
6021**************************************************************************
6022* Name: CIccXform4DLut::ExtractInputCurves
6023*
6024* Purpose:
6025* Gets the input 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 input curves.
6032**************************************************************************
6033*/
6034LPIccCurve* CIccXform4DLut::ExtractInputCurves()
6035{
6036 if (m_bInput) {
6037 if (m_pTag->m_bInputMatrix) {
6038 if (m_pTag->m_CurvesB) {
6039 LPIccCurve* Curve = new LPIccCurve[4];
6040 Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy());
6041 Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy());
6042 Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy());
6043 Curve[3] = (LPIccCurve)(m_pTag->m_CurvesB[3]->NewCopy());
6044 m_ApplyCurvePtrB = NULL;
6045 return Curve;
6046 }
6047 }
6048 else {
6049 if (m_pTag->m_CurvesA) {
6050 LPIccCurve* Curve = new LPIccCurve[4];
6051 Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy());
6052 Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy());
6053 Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy());
6054 Curve[3] = (LPIccCurve)(m_pTag->m_CurvesA[3]->NewCopy());
6055 m_ApplyCurvePtrA = NULL;
6056 return Curve;
6057 }
6058 }
6059 }
6060
6061 return NULL;
6062}
6063
6064/**
6065**************************************************************************
6066* Name: CIccXform4DLut::ExtractOutputCurves
6067*
6068* Purpose:
6069* Gets the output curves. Should be called only after Begin()
6070* has been called. Once the curves are extracted, they will
6071* not be used by the Apply() function.
6072* WARNING: caller owns the curves and must be deleted by the caller.
6073*
6074* Return:
6075* Pointer to the output curves.
6076**************************************************************************
6077*/
6078LPIccCurve* CIccXform4DLut::ExtractOutputCurves()
6079{
6080 if (!m_bInput) {
6081 if (m_pTag->m_bInputMatrix) {
6082 if (m_pTag->m_CurvesA) {
6083 LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
6084 for (int i=0; i<m_pTag->m_nOutput; i++) {
6085 Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy());
6086 }
6087 m_ApplyCurvePtrA = NULL;
6088 return Curve;
6089 }
6090 }
6091 else {
6092 if (m_pTag->m_CurvesB) {
6093 LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
6094 for (int i=0; i<m_pTag->m_nOutput; i++) {
6095 Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy());
6096 }
6097 m_ApplyCurvePtrB = NULL;
6098 return Curve;
6099 }
6100 }
6101 }
6102
6103 return NULL;
6104}
6105
6106
6107/**
6108 **************************************************************************
6109 * Name: CIccXformNDLut::CIccXformNDLut
6110 *
6111 * Purpose:
6112 * Constructor
6113 *
6114 * Args:
6115 * pTag = Pointer to the tag of type CIccMBB
6116 **************************************************************************
6117 */
6118CIccXformNDLut::CIccXformNDLut(CIccTag *pTag)
6119{
6120 if (pTag && pTag->IsMBBType()) {
6121 m_pTag = (CIccMBB*)pTag;
6122 }
6123 else
6124 m_pTag = NULL;
6125
6126 m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
6127 m_ApplyMatrixPtr = NULL;
6128 m_nNumInput = 0;
6129}
6130
6131
6132/**
6133 **************************************************************************
6134 * Name: CIccXformNDLut::~CIccXformNDLut
6135 *
6136 * Purpose:
6137 * Destructor
6138 **************************************************************************
6139 */
6140CIccXformNDLut::~CIccXformNDLut()
6141{
6142}
6143
6144
6145/**
6146 **************************************************************************
6147 * Name: CIccXformNDLut::Begin
6148 *
6149 * Purpose:
6150 * Does the initialization of the Xform before Apply() is called.
6151 * Must be called before Apply().
6152 *
6153 **************************************************************************
6154 */
6155icStatusCMM CIccXformNDLut::Begin()
6156{
6157 icStatusCMM status;
6158 CIccCurve **Curve;
6159 int i;
6160
6161 status = CIccXform::Begin();
6162 if (status != icCmmStatOk) {
6163 return status;
6164 }
6165
6166 if (!m_pTag || (m_pTag->InputChannels()>2 && m_pTag->InputChannels()<5)) {
6167 return icCmmStatInvalidLut;
6168 }
6169
6170 m_nNumInput = m_pTag->m_nInput;
6171
6172 m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL;
6173
6174 if (m_pTag->m_bInputMatrix) {
6175 if (m_pTag->m_CurvesB) {
6176 Curve = m_pTag->m_CurvesB;
6177
6178 for (i=0; i<m_nNumInput; i++)
6179 Curve[i]->Begin();
6180
6181 for (i=0; i<m_nNumInput; i++) {
6182 if (!Curve[i]->IsIdentity()) {
6183 m_ApplyCurvePtrB = Curve;
6184 break;
6185 }
6186 }
6187 }
6188
6189 if (m_pTag->m_CLUT) {
6190 m_pTag->m_CLUT->Begin();
6191 }
6192
6193 if (m_pTag->m_CurvesA) {
6194 Curve = m_pTag->m_CurvesA;
6195
6196 for (i=0; i<m_pTag->m_nOutput; i++) {
6197 Curve[i]->Begin();
6198 }
6199
6200 for (i=0; i<m_pTag->m_nOutput; i++) {
6201 if (!Curve[i]->IsIdentity()) {
6202 m_ApplyCurvePtrA = Curve;
6203 break;
6204 }
6205 }
6206 }
6207
6208 }
6209 else {
6210 if (m_pTag->m_CurvesA) {
6211 Curve = m_pTag->m_CurvesA;
6212
6213 for (i=0; i<m_nNumInput; i++)
6214 Curve[i]->Begin();
6215
6216 for (i=0; i<m_nNumInput; i++) {
6217 if (!Curve[i]->IsIdentity()) {
6218 m_ApplyCurvePtrA = Curve;
6219 break;
6220 }
6221 }
6222 }
6223
6224 if (m_pTag->m_CLUT) {
6225 m_pTag->m_CLUT->Begin();
6226 }
6227
6228 if (m_pTag->m_CurvesM) {
6229 Curve = m_pTag->m_CurvesM;
6230
6231 for (i=0; i<m_pTag->m_nOutput; i++) {
6232 Curve[i]->Begin();
6233 }
6234
6235 for (i=0; i<m_pTag->m_nOutput; i++) {
6236 if (!Curve[i]->IsIdentity()) {
6237 m_ApplyCurvePtrM = Curve;
6238 break;
6239 }
6240 }
6241 }
6242
6243 if (m_pTag->m_CurvesB) {
6244 Curve = m_pTag->m_CurvesB;
6245
6246 for (i=0; i<m_pTag->m_nOutput; i++) {
6247 Curve[i]->Begin();
6248 }
6249
6250 for (i=0; i<m_pTag->m_nOutput; i++) {
6251 if (!Curve[i]->IsIdentity()) {
6252 m_ApplyCurvePtrB = Curve;
6253 break;
6254 }
6255 }
6256 }
6257 }
6258
6259 m_ApplyMatrixPtr = NULL;
6260 if (m_pTag->m_Matrix) {
6261 if (m_pTag->m_bInputMatrix) {
6263 }
6264 else {
6265 if (m_pTag->m_nOutput!=3) {
6267 }
6268 }
6269
6270 if (!m_pTag->m_Matrix->IsIdentity()) {
6271 m_ApplyMatrixPtr = m_pTag->m_Matrix;
6272 }
6273 }
6274
6275 return icCmmStatOk;
6276}
6277
6278
6279/**
6280 **************************************************************************
6281 * Name: CIccXformNDLut::GetNewApply
6282 *
6283 * Purpose:
6284 * Allocates a new apply object
6285 *
6286 * Args:
6287 * status = reference to status of creation of the apply object
6288 **************************************************************************
6289 */
6290CIccApplyXform* CIccXformNDLut::GetNewApply(icStatusCMM& status)
6291{
6292 if (!m_pTag)
6293 return NULL;
6294
6295 CIccCLUT* pCLUT = m_pTag->GetCLUT();
6296 CIccApplyCLUT* pApply = NULL;
6297
6298 if (pCLUT && m_nNumInput > 6) {
6299 pApply = pCLUT->GetNewApply();
6300 if (!pApply) {
6301 status = icCmmStatAllocErr;
6302 return NULL;
6303 }
6304 }
6305
6306 CIccApplyNDLutXform* rv = new CIccApplyNDLutXform(this, pApply);
6307
6308 if (!rv) {
6309 if (pApply)
6310 delete pApply;
6311 status = icCmmStatAllocErr;
6312 return NULL;
6313 }
6314
6315 status = icCmmStatOk;
6316 return rv;
6317}
6318
6319/**
6320 **************************************************************************
6321 * Name: CIccXformNDLut::Apply
6322 *
6323 * Purpose:
6324 * Does the actual application of the Xform.
6325 *
6326 * Args:
6327 * pApply = ApplyXform object containging temporary storage used during Apply
6328 * DstPixel = Destination pixel where the result is stored,
6329 * SrcPixel = Source pixel which is to be applied.
6330 **************************************************************************
6331 */
6332void CIccXformNDLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
6333{
6334 icFloatNumber Pixel[16] = {0};
6335 int i;
6336
6337 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
6338 for (i=0; i<m_nNumInput; i++)
6339 Pixel[i] = SrcPixel[i];
6340
6341 if (m_pTag->m_bInputMatrix) {
6342 if (m_ApplyCurvePtrB) {
6343 for (i=0; i<m_nNumInput; i++)
6344 Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]);
6345 }
6346
6347 if (m_pTag->m_CLUT) {
6348 switch(m_nNumInput) {
6349 case 5:
6350 m_pTag->m_CLUT->Interp5d(Pixel, Pixel);
6351 break;
6352 case 6:
6353 m_pTag->m_CLUT->Interp6d(Pixel, Pixel);
6354 break;
6355 default:
6356 {
6357 CIccApplyNDLutXform* pNDApply = (CIccApplyNDLutXform*)pApply;
6358 m_pTag->m_CLUT->InterpND(Pixel, Pixel, pNDApply->m_pApply);
6359 break;
6360 }
6361 }
6362 }
6363
6364 if (m_ApplyCurvePtrA) {
6365 for (i=0; i<m_pTag->m_nOutput; i++) {
6366 Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]);
6367 }
6368 }
6369
6370 }
6371 else {
6372 if (m_ApplyCurvePtrA) {
6373 for (i=0; i<m_nNumInput; i++)
6374 Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]);
6375 }
6376
6377 if (m_pTag->m_CLUT) {
6378 switch(m_nNumInput) {
6379 case 5:
6380 m_pTag->m_CLUT->Interp5d(Pixel, Pixel);
6381 break;
6382 case 6:
6383 m_pTag->m_CLUT->Interp6d(Pixel, Pixel);
6384 break;
6385 default:
6386 {
6387 CIccApplyNDLutXform* pNDApply = (CIccApplyNDLutXform*)pApply;
6388 m_pTag->m_CLUT->InterpND(Pixel, Pixel, pNDApply->m_pApply);
6389 break;
6390 }
6391 break;
6392 }
6393 }
6394
6395 if (m_ApplyCurvePtrM) {
6396 for (i=0; i<m_pTag->m_nOutput; i++) {
6397 Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]);
6398 }
6399 }
6400
6401 if (m_ApplyMatrixPtr) {
6402 m_ApplyMatrixPtr->Apply(Pixel);
6403 }
6404
6405 if (m_ApplyCurvePtrB) {
6406 for (i=0; i<m_pTag->m_nOutput; i++) {
6407 Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]);
6408 }
6409 }
6410 }
6411
6412 for (i=0; i<m_pTag->m_nOutput; i++) {
6413 DstPixel[i] = Pixel[i];
6414 }
6415
6416 CheckDstAbs(DstPixel);
6417}
6418
6419/**
6420**************************************************************************
6421* Name: CIccXformNDLut::ExtractInputCurves
6422*
6423* Purpose:
6424* Gets the input curves. Should be called only after Begin()
6425* has been called. Once the curves are extracted, they will
6426* not be used by the Apply() function.
6427* WARNING: caller owns the curves and must be deleted by the caller.
6428*
6429* Return:
6430* Pointer to the input curves.
6431**************************************************************************
6432*/
6433LPIccCurve* CIccXformNDLut::ExtractInputCurves()
6434{
6435 if (m_bInput) {
6436 if (m_pTag->m_bInputMatrix) {
6437 if (m_pTag->m_CurvesB) {
6438 LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput];
6439 for (int i=0; i<m_pTag->m_nInput; i++) {
6440 Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy());
6441 }
6442 m_ApplyCurvePtrB = NULL;
6443 return Curve;
6444 }
6445 }
6446 else {
6447 if (m_pTag->m_CurvesA) {
6448 LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput];
6449 for (int i=0; i<m_pTag->m_nInput; i++) {
6450 Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy());
6451 }
6452 m_ApplyCurvePtrA = NULL;
6453 return Curve;
6454 }
6455 }
6456 }
6457
6458 return NULL;
6459}
6460
6461/**
6462**************************************************************************
6463* Name: CIccXformNDLut::ExtractOutputCurves
6464*
6465* Purpose:
6466* Gets the output curves. Should be called only after Begin()
6467* has been called. Once the curves are extracted, they will
6468* not be used by the Apply() function.
6469* WARNING: caller owns the curves and must be deleted by the caller.
6470*
6471* Return:
6472* Pointer to the output curves.
6473**************************************************************************
6474*/
6475LPIccCurve* CIccXformNDLut::ExtractOutputCurves()
6476{
6477 if (!m_bInput) {
6478 if (m_pTag->m_bInputMatrix) {
6479 if (m_pTag->m_CurvesA) {
6480 LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
6481 for (int i=0; i<m_pTag->m_nOutput; i++) {
6482 Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy());
6483 }
6484 m_ApplyCurvePtrA = NULL;
6485 return Curve;
6486 }
6487 }
6488 else {
6489 if (m_pTag->m_CurvesB) {
6490 LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput];
6491 for (int i=0; i<m_pTag->m_nOutput; i++) {
6492 Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy());
6493 }
6494 m_ApplyCurvePtrB = NULL;
6495 return Curve;
6496 }
6497 }
6498 }
6499
6500 return NULL;
6501}
6502
6503/**
6504 **************************************************************************
6505 * Name: CIccXformNamedColor::CIccXformNamedColor
6506 *
6507 * Purpose:
6508 * Constructor
6509 *
6510 * Args:
6511 * pTag = Pointer to the tag of type CIccTagNamedColor2,
6512 * csPCS = PCS color space,
6513 * csDevice = Device color space
6514 **************************************************************************
6515 */
6516CIccXformNamedColor::CIccXformNamedColor(CIccTag *pTag, icColorSpaceSignature csPcs, icColorSpaceSignature csDevice,
6517 icSpectralColorSignature csSpectralPcs/* =icSigNoSpectralData */,
6518 const icSpectralRange *pSpectralRange /* = NULL */,
6519 const icSpectralRange *pBiSpectralRange /* = NULL */)
6520{
6521 m_nApplyInterface = icApplyPixel2Pixel; // was uninitialized
6522 m_pTag = NULL;
6523 if (pTag) {
6524 if (pTag->GetType()==icSigNamedColor2Type) {
6525 m_pTag = (CIccTagNamedColor2*)pTag;
6526 m_pArray = NULL;
6527
6528 m_pTag->SetColorSpaces(csPcs, csDevice);
6529 }
6530 else if (pTag->GetTagArrayType()==icSigNamedColorArray) {
6531 CIccTagArray *pArray = (CIccTagArray*)pTag;
6533
6534 if (pNamed) {
6535 m_pTag = NULL;
6536 m_pArray = pNamed;
6537 pNamed->SetColorSpaces(csPcs, csDevice, csSpectralPcs, pSpectralRange, pBiSpectralRange);
6538 }
6539 }
6540 }
6541
6542 m_nSrcSpace = icSigUnknownData;
6543 m_nDestSpace = icSigUnknownData;
6544 m_pArray = NULL;
6545}
6546
6547
6548/**
6549 **************************************************************************
6550 * Name: CIccXformNamedColor::CIccXformNamedColor
6551 *
6552 * Purpose:
6553 * Destructor
6554 **************************************************************************
6555 */
6556CIccXformNamedColor::~CIccXformNamedColor()
6557{
6558}
6559
6560/**
6561 **************************************************************************
6562 * Name: CIccXformNamedColor::Begin
6563 *
6564 * Purpose:
6565 * Does the initialization of the Xform before Apply() is called.
6566 * Must be called before Apply().
6567 *
6568 **************************************************************************
6569 */
6570icStatusCMM CIccXformNamedColor::Begin()
6571{
6572 icStatusCMM status;
6573
6574 status = CIccXform::Begin();
6575 if (status != icCmmStatOk)
6576 return status;
6577
6578 if (m_pTag==NULL && m_pArray==NULL) {
6580 }
6581
6582 if (m_nSrcSpace==icSigUnknownData ||
6583 m_nDestSpace==icSigUnknownData) {
6585 }
6586
6587 if (m_nSrcSpace != icSigNamedData) {
6588 if (m_nDestSpace != icSigNamedData) {
6589 m_nApplyInterface = icApplyPixel2Pixel;
6590 }
6591 else {
6592 m_nApplyInterface = icApplyPixel2Named;
6593 }
6594 }
6595 else {
6596 if (m_nDestSpace != icSigNamedData) {
6597 m_nApplyInterface = icApplyNamed2Pixel;
6598 }
6599 else {
6601 }
6602 }
6603
6604 if (m_pTag && !m_pTag->InitFindCachedPCSColor())
6605 return icCmmStatAllocErr;
6606 else if (m_pArray && !m_pArray->Begin())
6607 return icCmmStatAllocErr;
6608
6609 return icCmmStatOk;
6610}
6611
6612
6613
6614/**
6615 **************************************************************************
6616 * Name: CIccXformNamedColor::Apply
6617 *
6618 * Purpose:
6619 * Does the actual application of the Xform.
6620 *
6621 * Args:
6622 * pApply = ApplyXform object containging temporary storage used during Apply
6623 * DstColorName = Destination string where the color name result is stored,
6624 * SrcPixel = Source pixel which is to be applied.
6625 **************************************************************************
6626 */
6627icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icChar *DstColorName, const icFloatNumber *SrcPixel) const
6628{
6629
6630 if (m_pArray) {
6631 const CIccArrayNamedColor *pArray = m_pArray;
6632 CIccStructNamedColor *pColor;
6633
6634 std::string NamedColor;
6635
6636 if (IsSrcPCS()) {
6637 if (IsSpaceSpectralPCS(m_nSrcSpace)) {
6638 pColor = pArray->FindSpectralColor(SrcPixel);
6639 if (pColor)
6640 NamedColor = pColor->getName();
6641 else
6643 }
6644 else {
6645 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
6646 icFloatNumber pix[3];
6647 memcpy(pix, SrcPixel, 3*sizeof(icFloatNumber));
6648
6649 if (m_nSrcSpace == icSigLabPcsData)
6650 icLabFromPcs(pix);
6651 else {
6652 icXyzFromPcs(pix);
6653 icXYZtoLab(pix, pix);
6654 }
6655
6656 pColor = pArray->FindPcsColor(pix);
6657 if (pColor)
6658 NamedColor = pColor->getName();
6659 else
6661 }
6662 }
6663 else {
6664 pColor = pArray->FindDeviceColor(SrcPixel);
6665 if (pColor)
6666 NamedColor = pColor->getName();
6667 else
6669 }
6670
6671 sprintf(DstColorName, "%s", NamedColor.c_str());
6672 }
6673 else if (m_pTag) {
6674 const CIccTagNamedColor2 *pTag = m_pTag;
6675
6676 icFloatNumber DevicePix[16], PCSPix[3];
6677 std::string NamedColor;
6678 icUInt32Number i, j;
6679
6680 if (IsSrcPCS()) {
6681 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
6682 for(i=0; i<3; i++)
6683 PCSPix[i] = SrcPixel[i];
6684
6685 j = pTag->FindCachedPCSColor(PCSPix);
6686 pTag->GetColorName(NamedColor, j);
6687 }
6688 else {
6689 for(i=0; i<m_pTag->GetDeviceCoords(); i++)
6690 DevicePix[i] = SrcPixel[i];
6691
6692 j = pTag->FindDeviceColor(DevicePix);
6693 pTag->GetColorName(NamedColor, j);
6694 }
6695
6696 sprintf(DstColorName, "%s", NamedColor.c_str());
6697 }
6698 else
6699 return icCmmStatBadXform;
6700
6701 return icCmmStatOk;
6702}
6703
6704
6705/**
6706**************************************************************************
6707* Name: CIccXformNamedColor::Apply
6708*
6709* Purpose:
6710* Does the actual application of the Xform.
6711*
6712* Args:
6713* pApply = ApplyXform object containing temporary storage used during Apply
6714* DstPixel = Destination pixel where the result is stored,
6715* SrcColorName = Source color name which is to be applied.
6716**************************************************************************
6717*/
6718icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint) const
6719{
6720
6721 if (m_pArray) {
6722 const CIccArrayNamedColor *pArray = m_pArray;
6723
6724 CIccStructNamedColor *pColor;
6725
6726 if (m_nSrcSpace != icSigNamedData)
6727 return icCmmStatBadSpaceLink;
6728
6729 pColor = pArray->FindColor(SrcColorName);
6730 if (!pColor)
6732
6733 if (IsDestPCS()) {
6734 if (IsSpaceSpectralPCS(m_nDestSpace)) {
6735 if (!pArray->GetSpectralTint(DstPixel, pColor, tint))
6736 return icCmmStatBadTintXform;
6737 }
6738 else {
6739 if (!pArray->GetPcsTint(DstPixel, pColor, tint))
6740 return icCmmStatBadTintXform;
6741
6742 if (m_nDestSpace == icSigLabData) {
6743 icLabToPcs(DstPixel);
6744 }
6745 else {
6746 icXyzToPcs(DstPixel);
6747 }
6748 CheckDstAbs(DstPixel);
6749 }
6750 }
6751 else {
6752 if (!pArray->GetDeviceTint(DstPixel, pColor, tint))
6753 return icCmmStatBadTintXform;
6754 }
6755 }
6756 else if (m_pTag) {
6757 const CIccTagNamedColor2 *pTag = m_pTag;
6758
6759 icInt32Number j;
6760
6761 if (m_nSrcSpace != icSigNamedData)
6762 return icCmmStatBadSpaceLink;
6763
6764 if (IsDestPCS()) {
6765
6766 j = pTag->FindColor(SrcColorName);
6767 if (j<0)
6769
6770 if (m_nDestSpace == icSigLabData) {
6771 memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber));
6772 }
6773 else {
6774 memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber));
6775 }
6776 CheckDstAbs(DstPixel);
6777 }
6778 else {
6779 j = pTag->FindColor(SrcColorName);
6780 if (j<0)
6782 memcpy(DstPixel, pTag->GetEntry(j)->deviceCoords, pTag->GetDeviceCoords()*sizeof(icFloatNumber));
6783 }
6784 }
6785
6786 return icCmmStatOk;
6787}
6788
6789/**
6790 **************************************************************************
6791 * Name: CIccXformNamedColor::SetSrcSpace
6792 *
6793 * Purpose:
6794 * Sets the source space of the Xform
6795 *
6796 * Args:
6797 * nSrcSpace = signature of the color space to be set
6798 **************************************************************************
6799 */
6800icStatusCMM CIccXformNamedColor::SetSrcSpace(icColorSpaceSignature nSrcSpace)
6801{
6802 if (m_pArray) {
6803
6804 }
6805 else if (m_pTag) {
6806 CIccTagNamedColor2 *pTag = m_pTag;
6807
6808 if (nSrcSpace!=pTag->GetPCS())
6809 if (nSrcSpace!=pTag->GetDeviceSpace())
6810 if (nSrcSpace!=icSigNamedData)
6811 return icCmmStatBadSpaceLink;
6812 }
6813
6814 m_nSrcSpace = nSrcSpace;
6815
6816 return icCmmStatOk;
6817}
6818
6819/**
6820 **************************************************************************
6821 * Name: CIccXformNamedColor::SetDestSpace
6822 *
6823 * Purpose:
6824 * Sets the destination space of the Xform
6825 *
6826 * Args:
6827 * nDestSpace = signature of the color space to be set
6828 **************************************************************************
6829 */
6830icStatusCMM CIccXformNamedColor::SetDestSpace(icColorSpaceSignature nDestSpace)
6831{
6832 if (m_nSrcSpace == nDestSpace)
6833 return icCmmStatBadSpaceLink;
6834
6835 if (m_pArray) {
6836
6837 }
6838 else if (m_pTag) {
6839 CIccTagNamedColor2 *pTag = (CIccTagNamedColor2*)m_pTag;
6840
6841 if (nDestSpace!=pTag->GetPCS())
6842 if (nDestSpace!=pTag->GetDeviceSpace())
6843 if (nDestSpace!=icSigNamedData)
6844 return icCmmStatBadSpaceLink;
6845 }
6846
6847 m_nDestSpace = nDestSpace;
6848
6849 return icCmmStatOk;
6850}
6851
6852/**
6853 **************************************************************************
6854 * Name: CIccXformNamedColor::IsSrcPCS
6855 *
6856 * Purpose:
6857 * Sets the source space is a PCS space
6858 **************************************************************************
6859 */
6860bool CIccXformNamedColor::IsSrcPCS() const
6861{
6862 if (m_pTag) {
6863 return m_nSrcSpace == m_pTag->GetPCS();
6864 }
6865 else if (m_pArray) {
6866 return IsSpacePCS(m_nSrcSpace);
6867 }
6868 else
6869 return false;
6870}
6871
6872
6873/**
6874 **************************************************************************
6875 * Name: CIccXformNamedColor::IsDestPCS
6876 *
6877 * Purpose:
6878 * Sets the destination space is a PCS space
6879 **************************************************************************
6880 */
6881bool CIccXformNamedColor::IsDestPCS() const
6882{
6883 if (m_pTag) {
6884 return m_nDestSpace == m_pTag->GetPCS();
6885 }
6886 else if (m_pArray) {
6887 return IsSpacePCS(m_nDestSpace);
6888 }
6889 else
6890 return false;
6891}
6892
6893
6894/**
6895**************************************************************************
6896* Name: CIccXformMPE::CIccXformMPE
6897*
6898* Purpose:
6899* Constructor
6900**************************************************************************
6901*/
6902CIccXformMpe::CIccXformMpe(CIccTag *pTag)
6903{
6904 if (pTag && pTag->GetType()==icSigMultiProcessElementType)
6905 m_pTag = (CIccTagMultiProcessElement*)pTag;
6906 else
6907 m_pTag = NULL;
6908
6909 m_bUsingAcs = false;
6910 m_pAppliedPCC = NULL;
6911 m_bDeleteAppliedPCC = false;
6912}
6913
6914/**
6915**************************************************************************
6916* Name: CIccXformMPE::~CIccXformMPE
6917*
6918* Purpose:
6919* Destructor
6920**************************************************************************
6921*/
6922CIccXformMpe::~CIccXformMpe()
6923{
6924 if (m_pAppliedPCC && m_bDeleteAppliedPCC)
6925 delete m_pAppliedPCC;
6926}
6927
6928/**
6929**************************************************************************
6930* Name: CIccXformMPE::Create
6931*
6932* Purpose:
6933* This is a static Creation function that creates derived CIccXform objects and
6934* initializes them.
6935*
6936* Args:
6937* pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will
6938* be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile
6939* object needs to be allocated on the heap.
6940* bInput = flag to indicate whether to use the input or output side of the profile,
6941* nIntent = the rendering intent to apply to the profile,
6942* nInterp = the interpolation algorithm to use for N-D luts.
6943* nLutType = selection of which transform lut to use
6944* pHintManager = hints for creating the xform
6945*
6946* Return:
6947* A suitable pXform object
6948**************************************************************************
6949*/
6950CIccXform *CIccXformMpe::Create(CIccProfile *pProfile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */,
6951 icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */,
6952 CIccCreateXformHintManager *pHintManager/* =NULL */)
6953{
6954 CIccXform *rv = NULL;
6955 icRenderingIntent nTagIntent = nIntent;
6956 bool bUseSpectralPCS = false;
6957 bool bAbsToRel = false;
6958 icXformLutType nUseLutType = nLutType;
6959 bool bUseColorimeticTags = true;
6960 bool bUseDToB = true;
6961
6962 if (nLutType == icXformLutSpectral) {
6963 nUseLutType = icXformLutColor;
6964 bUseColorimeticTags = false;
6965 }
6966 else if (nLutType == icXformLutColorimetric) {
6967 nUseLutType = icXformLutColor;
6968 bUseDToB = false;
6969 }
6970
6971 if (nTagIntent == icUnknownIntent)
6972 nTagIntent = icPerceptual;
6973
6974 switch (nUseLutType) {
6975 case icXformLutColor:
6976 if (bInput) {
6977 CIccTag *pTag = NULL;
6978 if (bUseDToB) {
6979 pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent);
6980
6981 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
6982 pTag = pProfile->FindTag(icSigDToB1Tag);
6983 if (pTag)
6984 nTagIntent = icRelativeColorimetric;
6985 }
6986 else if (!pTag && nTagIntent != icAbsoluteColorimetric) {
6987 pTag = pProfile->FindTag(icSigDToB3Tag);
6988 if (pTag) {
6989 nTagIntent = icAbsoluteColorimetric;
6990 bAbsToRel = true;
6991 }
6992 }
6993
6994 if (!pTag) {
6995 pTag = pProfile->FindTag(icSigDToB0Tag);
6996 }
6997 }
6998
6999 //Unsupported elements cause fall back behavior
7000 if (pTag && !pTag->IsSupported())
7001 pTag = NULL;
7002
7003 if (pTag && pProfile->m_Header.spectralPCS) {
7004 bUseSpectralPCS = true;
7005 }
7006
7007 if (bUseColorimeticTags) {
7008 if (!pTag) {
7009 if (nTagIntent == icAbsoluteColorimetric)
7010 nTagIntent = icRelativeColorimetric;
7011 pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent);
7012 }
7013
7014 if (!pTag) {
7015 pTag = pProfile->FindTag(icSigAToB0Tag);
7016 }
7017 }
7018
7019 if (!pTag) {
7020 if (bUseColorimeticTags && pProfile->m_Header.colorSpace == icSigRgbData && pProfile->m_Header.version < icVersionNumberV5) {
7021 rv = new CIccXformMatrixTRC();
7022 }
7023 else
7024 return NULL;
7025 }
7026 else if (pTag->GetType()==icSigMultiProcessElementType) {
7027 rv = new CIccXformMpe(pTag);
7028 }
7029 else {
7030 switch(pProfile->m_Header.colorSpace) {
7031 case icSigXYZData:
7032 case icSigLabData:
7033 case icSigLuvData:
7034 case icSigYCbCrData:
7035 case icSigYxyData:
7036 case icSigRgbData:
7037 case icSigHsvData:
7038 case icSigHlsData:
7039 case icSigCmyData:
7040 case icSig3colorData:
7041 rv = new CIccXform3DLut(pTag);
7042 break;
7043
7044 case icSigCmykData:
7045 case icSig4colorData:
7046 rv = new CIccXform4DLut(pTag);
7047 break;
7048
7049 default:
7050 rv = new CIccXformNDLut(pTag);
7051 break;
7052 }
7053 }
7054 }
7055 else {
7056 CIccTag *pTag = NULL;
7057
7058 if (bUseDToB) {
7059 pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent);
7060
7061 if (!pTag && nTagIntent == icAbsoluteColorimetric) {
7062 pTag = pProfile->FindTag(icSigBToD1Tag);
7063 if (pTag)
7064 nTagIntent = icRelativeColorimetric;
7065 }
7066 else if (!pTag && nTagIntent != icAbsoluteColorimetric) {
7067 pTag = pProfile->FindTag(icSigBToD3Tag);
7068 if (pTag) {
7069 nTagIntent = icAbsoluteColorimetric;
7070 bAbsToRel = true;
7071 }
7072 }
7073
7074 if (!pTag) {
7075 pTag = pProfile->FindTag(icSigBToD0Tag);
7076 }
7077 }
7078
7079 //Unsupported elements cause fall back behavior
7080 if (pTag && !pTag->IsSupported())
7081 pTag = NULL;
7082
7083 if (bUseColorimeticTags) {
7084 if (!pTag) {
7085 if (nTagIntent == icAbsoluteColorimetric)
7086 nTagIntent = icRelativeColorimetric;
7087 pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent);
7088 }
7089
7090 if (!pTag) {
7091 pTag = pProfile->FindTag(icSigBToA0Tag);
7092 }
7093 }
7094
7095 if (!pTag) {
7096 if (bUseColorimeticTags && pProfile->m_Header.colorSpace == icSigRgbData && pProfile->m_Header.version<icVersionNumberV5) {
7097 rv = new CIccXformMatrixTRC();
7098 }
7099 else
7100 return NULL;
7101 }
7102
7103 if (pTag && pTag->GetType()==icSigMultiProcessElementType) {
7104 rv = new CIccXformMpe(pTag);
7105 }
7106 else {
7107 switch(pProfile->m_Header.pcs) {
7108 case icSigXYZData:
7109 case icSigLabData:
7110 rv = new CIccXform3DLut(pTag);
7111
7112 default:
7113 break;
7114 }
7115 }
7116 }
7117 break;
7118
7120 {
7121 CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag);
7122 if (!pTag)
7123 return NULL;
7124
7125 rv = new CIccXformNamedColor(pTag, pProfile->m_Header.pcs, pProfile->m_Header.colorSpace,
7126 pProfile->m_Header.spectralPCS,
7127 &pProfile->m_Header.spectralRange,
7128 &pProfile->m_Header.biSpectralRange);
7129 }
7130 break;
7131
7132 case icXformLutPreview:
7133 {
7134 bInput = false;
7135 CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent);
7136 if (!pTag) {
7137 pTag = pProfile->FindTag(icSigPreview0Tag);
7138 }
7139 if (!pTag) {
7140 return NULL;
7141 }
7142 else {
7143 switch(pProfile->m_Header.pcs) {
7144 case icSigXYZData:
7145 case icSigLabData:
7146 rv = new CIccXform3DLut(pTag);
7147
7148 default:
7149 break;
7150 }
7151 }
7152 }
7153 break;
7154
7155 case icXformLutGamut:
7156 {
7157 bInput = false;
7158 CIccTag *pTag = pProfile->FindTag(icSigGamutTag);
7159 if (!pTag) {
7160 return NULL;
7161 }
7162 else {
7163 switch(pProfile->m_Header.pcs) {
7164 case icSigXYZData:
7165 case icSigLabData:
7166 rv = new CIccXform3DLut(pTag);
7167
7168 default:
7169 break;
7170 }
7171 }
7172 }
7173 break;
7174 }
7175
7176 if (rv) {
7177 rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel);
7178 }
7179
7180 return rv;
7181}
7182
7183/**
7184**************************************************************************
7185* Name: CIccXformMPE::IsLateBinding
7186*
7187* Purpose:
7188* Determines if any processing elements are late binding with connection
7189* conditions
7190**************************************************************************
7191*/
7192bool CIccXformMpe::IsLateBinding() const
7193{
7194 if (m_pTag)
7195 return m_pTag->IsLateBinding();
7196
7197 return false;
7198}
7199
7200/**
7201**************************************************************************
7202* Name: CIccXformMPE::IsLateBindingReflectance
7203*
7204* Purpose:
7205* Determines if any processing elements are late binding with connection
7206* conditions
7207**************************************************************************
7208*/
7209bool CIccXformMpe::IsLateBindingReflectance() const
7210{
7211 if (m_pTag)
7212 return m_pTag->IsLateBindingReflectance();
7213
7214 return false;
7215}
7216
7217/**
7218**************************************************************************
7219* Name: CIccXformMPE::GetConnectionConditions
7220*
7221* Purpose:
7222* Gets appropriate connection conditions
7223**************************************************************************
7224*/
7225IIccProfileConnectionConditions *CIccXformMpe::GetConnectionConditions() const
7226{
7227 if (m_pAppliedPCC)
7228 return m_pAppliedPCC;
7229
7230 return m_pConnectionConditions;
7231}
7232
7233/**
7234**************************************************************************
7235* Name: CIccXformMPE::SetAppliedCC
7236*
7237* Purpose:
7238* This creates combined connection conditions based on profile,
7239* alternate connection conditions and whether reflectance is used
7240* by any late binding processing elements.
7241**************************************************************************
7242*/
7243void CIccXformMpe::SetAppliedCC(IIccProfileConnectionConditions *pPCC)
7244{
7245 if (!pPCC) {
7246 if (m_pAppliedPCC && m_bDeleteAppliedPCC) {
7247 delete m_pAppliedPCC;
7248 }
7249 m_pAppliedPCC = NULL;
7250 m_bDeleteAppliedPCC = false;
7251 return;
7252 }
7253
7254 if (m_pTag) {
7255 bool bReflectance = m_pTag->IsLateBindingReflectance();
7256
7257 if (pPCC != (IIccProfileConnectionConditions *)m_pProfile) {
7258 if (!bReflectance) {
7259 const CIccTagSpectralViewingConditions *pViewPCC = pPCC ? pPCC->getPccViewingConditions() : NULL;
7260 const CIccTagSpectralViewingConditions *pViewProfile = m_pProfile ? m_pProfile->getPccViewingConditions() : NULL;
7261
7262 if (pViewPCC && pViewProfile &&
7263 pViewPCC->getStdIllumiant() == pViewProfile->getStdIllumiant() &&
7264 pViewPCC->getIlluminantCCT() == pViewProfile->getIlluminantCCT() &&
7265 pViewPCC->getStdIllumiant() != icIlluminantUnknown) {
7266 m_pAppliedPCC = pPCC;
7267 m_bDeleteAppliedPCC = false;
7268 }
7269 else {
7270 m_pAppliedPCC = new CIccCombinedConnectionConditions(m_pProfile, pPCC, bReflectance);
7271 m_bDeleteAppliedPCC = true;
7272 }
7273 }
7274 else {
7275 m_pAppliedPCC = new CIccCombinedConnectionConditions(m_pProfile, pPCC, bReflectance);
7276 m_bDeleteAppliedPCC = true;
7277 }
7278 }
7279 else {
7280 m_pAppliedPCC = NULL;
7281 }
7282 }
7283 else {
7284 m_pAppliedPCC = pPCC;
7285 m_bDeleteAppliedPCC = false;
7286 }
7287}
7288
7289
7290/**
7291**************************************************************************
7292* Name: CIccXformMPE::Begin
7293*
7294* Purpose:
7295* This function will be called before the xform is applied. Derived objects
7296* should also call the base class function to initialize for Absolute Colorimetric
7297* Intent handling which is performed through the use of the CheckSrcAbs and
7298* CheckDstAbs functions.
7299**************************************************************************
7300*/
7301icStatusCMM CIccXformMpe::Begin()
7302{
7303 icStatusCMM status;
7304 status = CIccXform::Begin();
7305
7306 if (status != icCmmStatOk)
7307 return status;
7308
7309 if (!m_pTag) {
7310 return icCmmStatInvalidLut;
7311 }
7312
7313 if (!m_pTag->Begin(icElemInterpLinear, GetProfileCC(), GetConnectionConditions(), GetCmmEnvVarLookup())) {
7315 }
7316
7317 return icCmmStatOk;
7318}
7319
7320
7321/**
7322**************************************************************************
7323* Name: CIccXformMpe::GetNewApply
7324*
7325* Purpose:
7326* This Factory function allocates data specific for the application of the xform.
7327* This allows multiple threads to simultaneously use the same xform.
7328**************************************************************************
7329*/
7330CIccApplyXform *CIccXformMpe::GetNewApply(icStatusCMM &status)
7331{
7332 if (!m_pTag)
7333 return NULL;
7334
7335 CIccApplyXformMpe *rv= new CIccApplyXformMpe(this);
7336
7337 if (!rv) {
7338 status = icCmmStatAllocErr;
7339 return NULL;
7340 }
7341
7342 rv->m_pApply = m_pTag->GetNewApply();
7343 if (!rv->m_pApply) {
7344 status = icCmmStatAllocErr;
7345 delete rv;
7346 return NULL;
7347 }
7348
7349 status = icCmmStatOk;
7350 return rv;
7351}
7352
7353
7354/**
7355**************************************************************************
7356* Name: CIccXformMPE::Apply
7357*
7358* Purpose:
7359* Does the actual application of the Xform.
7360*
7361* Args:
7362* pApply = ApplyXform object containging temporary storage used during Apply
7363* DstPixel = Destination pixel where the result is stored,
7364* SrcPixel = Source pixel which is to be applied.
7365**************************************************************************
7366*/
7367void CIccXformMpe::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const
7368{
7369 const CIccTagMultiProcessElement *pTag = m_pTag;
7370
7371 icFloatNumber temp[3];
7372 if (!m_bInput || m_bPcsAdjustXform) { //PCS comming in?
7373 if (m_nIntent != icAbsoluteColorimetric || m_nIntent != m_nTagIntent) { //B2D3 tags don't need abs conversion
7374 SrcPixel = CheckSrcAbs(pApply, SrcPixel);
7375 }
7376
7377 //Since MPE tags use "real" values for PCS we need to convert from
7378 //internal encoding used by IccProfLib
7379 switch (GetSrcSpace()) {
7380 case icSigXYZData:
7381 memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber));
7382 icXyzFromPcs(temp);
7383 SrcPixel = &temp[0];
7384 break;
7385
7386 case icSigLabData:
7387 memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber));
7388 icLabFromPcs(temp);
7389 SrcPixel = &temp[0];
7390 break;
7391
7392 default:
7393 break;
7394 }
7395 }
7396
7397 //Note: pApply should be a CIccApplyXformMpe type here
7398 CIccApplyXformMpe *pApplyMpe = (CIccApplyXformMpe *)pApply;
7399
7400 pTag->Apply(pApplyMpe->m_pApply, DstPixel, SrcPixel);
7401
7402 if (m_bInput) { //PCS going out?
7403 //Since MPE tags use "real" values for PCS we need to convert to
7404 //internal encoding used by IccProfLib
7405 switch(GetDstSpace()) {
7406 case icSigXYZData:
7407 icXyzToPcs(DstPixel);
7408 break;
7409
7410 case icSigLabData:
7411 icLabToPcs(DstPixel);
7412 break;
7413
7414 default:
7415 break;
7416 }
7417
7418 if (m_nIntent != icAbsoluteColorimetric || m_nIntent != m_nTagIntent) { //D2B3 tags don't need abs conversion
7419 CheckDstAbs(DstPixel);
7420 }
7421 }
7422}
7423
7424/**
7425**************************************************************************
7426* Name: CIccApplyXformMpe::CIccApplyXformMpe
7427*
7428* Purpose:
7429* Constructor
7430**************************************************************************
7431*/
7432CIccApplyXformMpe::CIccApplyXformMpe(CIccXformMpe *pXform) : CIccApplyXform(pXform)
7433{
7434 m_pApply = NULL;
7435}
7436
7437/**
7438**************************************************************************
7439* Name: CIccApplyXformMpe::~CIccApplyXformMpe
7440*
7441* Purpose:
7442* Destructor
7443**************************************************************************
7444*/
7445CIccApplyXformMpe::~CIccApplyXformMpe()
7446{
7447}
7448
7449
7450/**
7451**************************************************************************
7452* Name: CIccApplyCmm::CIccApplyCmm
7453*
7454* Purpose:
7455* Constructor
7456*
7457* Args:
7458* pCmm = ptr to CMM to apply against
7459**************************************************************************
7460*/
7461CIccApplyCmm::CIccApplyCmm(CIccCmm *pCmm)
7462{
7463 m_pCmm = pCmm;
7464 m_pPCS = m_pCmm->GetPCS();
7465
7466 m_Xforms = new CIccApplyXformList;
7467 m_Xforms->clear();
7468
7469 m_Pixel = NULL;
7470 m_Pixel2 = NULL;
7471}
7472
7473/**
7474**************************************************************************
7475* Name: CIccApplyCmm::~CIccApplyCmm
7476*
7477* Purpose:
7478* Destructor
7479**************************************************************************
7480*/
7481CIccApplyCmm::~CIccApplyCmm()
7482{
7483 if (m_Xforms) {
7484 CIccApplyXformList::iterator i;
7485
7486 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
7487 if (i->ptr)
7488 delete i->ptr;
7489 }
7490
7491 delete m_Xforms;
7492 }
7493
7494 if (m_pPCS)
7495 delete m_pPCS;
7496
7497 if (m_Pixel)
7498 free(m_Pixel);
7499 if (m_Pixel2)
7500 free(m_Pixel2);
7501}
7502
7503bool CIccApplyCmm::InitPixel()
7504{
7505 if (m_Pixel && m_Pixel2)
7506 return true;
7507
7508 icUInt16Number nSamples = 16;
7509 CIccApplyXformList::iterator i;
7510
7511 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
7512 if (i->ptr->GetXform()) {
7513 icUInt16Number nXformSamples = i->ptr->GetXform()->GetNumDstSamples();
7514 if (nXformSamples>nSamples)
7515 nSamples=nXformSamples;
7516 }
7517 }
7518 m_Pixel = (icFloatNumber*)malloc(nSamples*sizeof(icFloatNumber));
7519 m_Pixel2 = (icFloatNumber*)malloc(nSamples*sizeof(icFloatNumber));
7520
7521 if (!m_Pixel || !m_Pixel2)
7522 return false;
7523
7524 return true;
7525}
7526
7527//#define DEBUG_CMM_APPLY
7528
7529#ifdef DEBUG_CMM_APPLY
7530static void DumpCmmApplyPixel(int nCount, const icFloatNumber* pPixel, icUInt16Number nSamples)
7531{
7532 printf("Xfm%d:", nCount);
7533 for (icUInt16Number i = 0; i < nSamples; i++) {
7534 if (i)
7535 printf(",");
7536 printf(" %.3f", pPixel[i]);
7537 }
7538 printf("\n");
7539
7540}
7541#endif
7542
7543/**
7544**************************************************************************
7545* Name: CIccApplyCmm::Apply
7546*
7547* Purpose:
7548* Does the actual application of the Xforms in the list.
7549*
7550* Args:
7551* DstPixel = Destination pixel where the result is stored,
7552* SrcPixel = Source pixel which is to be applied.
7553**************************************************************************
7554*/
7555icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
7556{
7557 icFloatNumber *pDst, *pTmp;
7558 const icFloatNumber *pSrc;
7559 CIccApplyXformList::iterator i;
7560 const CIccXform *pLastXform;
7561 int j, n = (int)m_Xforms->size();
7562 bool bNoClip;
7563
7564 if (!n)
7565 return icCmmStatBadXform;
7566
7567 if (!m_Pixel && !InitPixel()) {
7568 return icCmmStatAllocErr;
7569 }
7570
7571 m_pPCS->Reset(m_pCmm->m_nSrcSpace);
7572
7573 pSrc = SrcPixel;
7574 pDst = m_Pixel;
7575
7576#ifdef DEBUG_CMM_APPLY
7577 int nCount = 0;
7578 printf("Start ApplyCmm\n");
7579 DumpCmmApplyPixel(nCount++, pSrc, icGetSpaceSamples(m_pCmm->m_nSrcSpace));
7580#endif
7581
7582 if (n>1) {
7583 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
7584
7585 i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform()));
7586
7587#ifdef DEBUG_CMM_APPLY
7588 DumpCmmApplyPixel(nCount++, pDst, i->ptr->GetXform()->GetNumDstSamples());
7589#endif
7590
7591 pTmp = (icFloatNumber*)pSrc;
7592 pSrc = pDst;
7593 if (pTmp == SrcPixel)
7594 pDst = m_Pixel2;
7595 else
7596 pDst = pTmp;
7597 }
7598
7599 pLastXform = i->ptr->GetXform();
7600 i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, pLastXform));
7601 bNoClip = pLastXform->NoClipPCS();
7602 }
7603 else if (n==1) {
7604 i = m_Xforms->begin();
7605
7606 pLastXform = i->ptr->GetXform();
7607 i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, pLastXform));
7608
7609#ifdef DEBUG_CMM_APPLY
7610 DumpCmmApplyPixel(nCount++, pDst, i->ptr->GetXform()->GetNumDstSamples());
7611#endif
7612
7613 bNoClip = pLastXform->NoClipPCS();
7614 }
7615 else {
7616 bNoClip = true;
7617 }
7618
7619 m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace, bNoClip);
7620
7621#ifdef DEBUG_CMM_APPLY
7622 DumpCmmApplyPixel(nCount, DstPixel, icGetSpaceSamples(m_pCmm->m_nDestSpace));
7623 printf("End ApplyCmm\n\n");
7624#endif
7625
7626 return icCmmStatOk;
7627}
7628
7629/**
7630**************************************************************************
7631* Name: CIccApplyCmm::Apply
7632*
7633* Purpose:
7634* Does the actual application of the Xforms in the list.
7635*
7636* Args:
7637* DstPixel = Destination pixel where the result is stored,
7638* SrcPixel = Source pixel which is to be applied.
7639**************************************************************************
7640*/
7641icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
7642{
7643 icFloatNumber *pDst, *pTmp;
7644 const icFloatNumber *pSrc;
7645 CIccApplyXformList::iterator i;
7646 int j, n = (int)m_Xforms->size();
7648
7649 if (!n)
7650 return icCmmStatBadXform;
7651
7652 if (!m_Pixel && !InitPixel()) {
7653 return icCmmStatAllocErr;
7654 }
7655
7656 for (k=0; k<nPixels; k++) {
7657 m_pPCS->Reset(m_pCmm->m_nSrcSpace);
7658
7659 pSrc = SrcPixel;
7660 pDst = m_Pixel;
7661
7662 if (n>1) {
7663 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
7664
7665 i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform()));
7666 pTmp = (icFloatNumber*)pSrc;
7667 pSrc = pDst;
7668 if (pTmp==SrcPixel)
7669 pDst = m_Pixel2;
7670 else
7671 pDst = pTmp;
7672 }
7673
7674 i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, i->ptr->GetXform()));
7675 }
7676 else if (n==1) {
7677 i = m_Xforms->begin();
7678 i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, i->ptr->GetXform()));
7679 }
7680
7681 m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace);
7682
7683 DstPixel += m_pCmm->GetDestSamples();
7684 SrcPixel += m_pCmm->GetSourceSamples();
7685 }
7686
7687 return icCmmStatOk;
7688}
7689
7690void CIccApplyCmm::AppendApplyXform(CIccApplyXform *pApplyXform)
7691{
7692 CIccApplyXformPtr ptr;
7693 ptr.ptr = pApplyXform;
7694
7695 m_Xforms->push_back(ptr);
7696}
7697
7698/**
7699 **************************************************************************
7700 * Name: CIccCmm::CIccCmm
7701 *
7702 * Purpose:
7703 * Constructor
7704 *
7705 * Args:
7706 * nSrcSpace = signature of the source color space,
7707 * nDestSpace = signature of the destination color space,
7708 * bFirstInput = true if the first profile added is an input profile
7709 **************************************************************************
7710 */
7711CIccCmm::CIccCmm(icColorSpaceSignature nSrcSpace /*=icSigUnknownData*/,
7712 icColorSpaceSignature nDestSpace /*=icSigUnknownData*/,
7713 bool bFirstInput /*=true*/)
7714{
7715 m_bValid = false;
7716
7717 m_bLastInput = !bFirstInput;
7718 m_nSrcSpace = nSrcSpace;
7719 m_nDestSpace = nDestSpace;
7720
7721 m_nLastSpace = nSrcSpace;
7722 m_nLastIntent = icUnknownIntent;
7723
7724 m_Xforms = new CIccXformList;
7725 m_Xforms->clear();
7726
7727 m_pApply = NULL;
7728}
7729
7730/**
7731 **************************************************************************
7732 * Name: CIccCmm::~CIccCmm
7733 *
7734 * Purpose:
7735 * Destructor
7736 **************************************************************************
7737 */
7738CIccCmm::~CIccCmm()
7739{
7740 if (m_Xforms) {
7741 CIccXformList::iterator i;
7742
7743 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
7744 if (i->ptr)
7745 delete i->ptr;
7746 }
7747
7748 delete m_Xforms;
7749 }
7750
7751 if (m_pApply)
7752 delete m_pApply;
7753}
7754
7755const icChar* CIccCmm::GetStatusText(icStatusCMM stat)
7756{
7757 switch (stat) {
7758 case icCmmStatBad:
7759 return "Bad CMM";
7760 case icCmmStatOk:
7761 return "OK";
7763 return "Cannot open profile";
7765 return "Invalid space link";
7767 return "Invalid profile";
7768 case icCmmStatBadXform:
7769 return "Invalid profile transform";
7771 return "Invalid Look-Up Table";
7773 return "Missing tag in profile";
7775 return "Color not found";
7777 return "Incorrect Apply object";
7779 return "Invalid color encoding used";
7780 case icCmmStatAllocErr:
7781 return "Memory allocation error";
7783 return "Invalid Look-Up Table type";
7785 return "Identity transform used";
7787 return "Unsupported PCS Link used";
7789 return "Invalid profile connection";
7791 return "Invalid tint transform";
7793 return "Too many samples used";
7795 return "Invalid MCS link connection";
7796 default:
7797 return "Unknown CMM Status value";
7798
7799 }
7800}
7801
7802/**
7803 **************************************************************************
7804 * Name: CIccCmm::AddXform
7805 *
7806 * Purpose:
7807 * Adds a profile at the end of the Xform list
7808 *
7809 * Args:
7810 * szProfilePath = file name of the profile to be added,
7811 * nIntent = rendering intent to be used with the profile,
7812 * nInterp = type of interpolation to be used with the profile,
7813 * nLutType = selection of which transform lut to use
7814 * pHintManager = hints for creating the xform
7815 *
7816 * Return:
7817 * icCmmStatOk, if the profile was added to the list succesfully
7818 **************************************************************************
7819 */
7820icStatusCMM CIccCmm::AddXform(const icChar *szProfilePath,
7821 icRenderingIntent nIntent /*=icUnknownIntent*/,
7822 icXformInterp nInterp /*icXformInterp*/,
7823 IIccProfileConnectionConditions *pPcc/*=NULL*/,
7824 icXformLutType nLutType /*=icXformLutColor*/,
7825 bool bUseD2BxB2DxTags /*=true*/,
7826 CIccCreateXformHintManager *pHintManager /*=NULL*/,
7827 bool bUseSubProfile /*=false*/)
7828{
7829 CIccProfile *pProfile = OpenIccProfile(szProfilePath, bUseSubProfile);
7830
7831 if (!pProfile)
7833
7834 icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
7835
7836 if (rv != icCmmStatOk)
7837 delete pProfile;
7838
7839 return rv;
7840}
7841
7842
7843/**
7844**************************************************************************
7845* Name: CIccCmm::AddXform
7846*
7847* Purpose:
7848* Adds a profile at the end of the Xform list
7849*
7850* Args:
7851* pProfileMem = ptr to profile loaded into memory. Note: this memory
7852* needs to be available until after the Begin() function is called.
7853* nProfileLen = size in bytes of profile loaded into memory
7854* nIntent = rendering intent to be used with the profile,
7855* nInterp = type of interpolation to be used with the profile,
7856* nLutType = selection of which transform lut to use
7857* bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
7858* pHintManager = hints for creating the xform
7859*
7860* Return:
7861* icCmmStatOk, if the profile was added to the list succesfully
7862**************************************************************************
7863*/
7864icStatusCMM CIccCmm::AddXform(icUInt8Number *pProfileMem,
7865 icUInt32Number nProfileLen,
7866 icRenderingIntent nIntent /*=icUnknownIntent*/,
7867 icXformInterp nInterp /*icXformInterp*/,
7868 IIccProfileConnectionConditions *pPcc/*=NULL*/,
7869 icXformLutType nLutType /*=icXformLutColor*/,
7870 bool bUseD2BxB2DxTags /*=true*/,
7871 CIccCreateXformHintManager *pHintManager /*=NULL*/,
7872 bool bUseSubProfile /*=false*/)
7873{
7874 CIccMemIO *pFile = new CIccMemIO;
7875
7876 if (!pFile || !pFile->Attach(pProfileMem, nProfileLen, bUseSubProfile))
7878
7879 CIccProfile *pProfile = new CIccProfile;
7880
7881 if (!pProfile)
7883
7884 if (!pProfile->Attach(pFile)) {
7885 delete pFile;
7886 delete pProfile;
7888 }
7889
7890 icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
7891
7892 if (rv != icCmmStatOk)
7893 delete pProfile;
7894
7895 return rv;
7896}
7897
7898
7899/**
7900 **************************************************************************
7901 * Name: CIccCmm::AddXform
7902 *
7903 * Purpose:
7904 * Adds a profile at the end of the Xform list
7905 *
7906 * Args:
7907 * pProfile = pointer to the CIccProfile object to be added (profile will be owned by the CMM's added xform),
7908 * nIntent = rendering intent to be used with the profile,
7909 * nInterp = type of interpolation to be used with the profile,
7910 * nLutType = selection of which transform lut to use
7911 * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
7912 * pHintManager = hints for creating the xform
7913 *
7914 * Return:
7915 * icCmmStatOk, if the profile was added to the list succesfully
7916 **************************************************************************
7917 */
7918icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile,
7919 icRenderingIntent nIntent /*=icUnknownIntent*/,
7920 icXformInterp nInterp /*=icInterpLinear*/,
7921 IIccProfileConnectionConditions *pPcc/*=NULL*/,
7922 icXformLutType nLutType /*=icXformLutColor*/,
7923 bool bUseD2BxB2DxTags /*=true*/,
7924 CIccCreateXformHintManager *pHintManager /*=NULL*/)
7925{
7926 icColorSpaceSignature nSrcSpace, nDstSpace;
7927 bool bInput = !m_bLastInput;
7928
7929 if (!pProfile)
7931
7932 switch(pProfile->m_Header.deviceClass) {
7936 nIntent = icPerceptual;
7937 nLutType = icXformLutMCS;
7938
7939 default:
7940 break;
7941 }
7942
7943 switch (nLutType) {
7944 case icXformLutColor:
7946 case icXformLutSpectral:
7947 {
7948 //Check pProfile if nIntent and input can be found.
7949 if (bInput) {
7950 nSrcSpace = pProfile->m_Header.colorSpace;
7951
7952 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric))
7953 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
7954 else
7955 nDstSpace = pProfile->m_Header.pcs;
7956 }
7957 else {
7958 if (pProfile->m_Header.deviceClass == icSigLinkClass) {
7959 return icCmmStatBadSpaceLink;
7960 }
7961 if (pProfile->m_Header.deviceClass == icSigAbstractClass) {
7962 bInput = true;
7963 nIntent = icPerceptual; // Note: icPerceptualIntent = 0
7964 }
7965
7966 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric))
7967 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
7968 else
7969 nSrcSpace = pProfile->m_Header.pcs;
7970
7971 nDstSpace = pProfile->m_Header.colorSpace;
7972 }
7973 }
7974 break;
7975
7976 case icXformLutPreview:
7977 nSrcSpace = pProfile->m_Header.pcs;
7978 nDstSpace = pProfile->m_Header.pcs;
7979 bInput = false;
7980 break;
7981
7982 case icXformLutGamut:
7983 nSrcSpace = pProfile->m_Header.pcs;
7984 nDstSpace = icSigGamutData;
7985 bInput = true;
7986 break;
7987
7989 if (!bInput)
7990 return icCmmStatBadSpaceLink;
7991 nSrcSpace = pProfile->m_Header.colorSpace;
7992 nDstSpace = icSigBRDFParameters;
7993 bInput = true;
7994 break;
7995
7997 if (!bInput)
7998 return icCmmStatBadSpaceLink;
7999 nSrcSpace = icSigBRDFDirect;
8000 nDstSpace = pProfile->m_Header.pcs;
8001 bInput = true;
8002 break;
8003
8005 if (!bInput)
8006 return icCmmStatBadSpaceLink;
8007 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
8008 nDstSpace = icSigBRDFParameters;
8009 break;
8010
8011 case icXformLutMCS:
8012 if (bInput) {
8013 nSrcSpace = pProfile->m_Header.colorSpace;
8014 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
8015 }
8016 else {
8017 if (m_Xforms->size()) {
8018 CIccXformList::iterator prev = --(m_Xforms->end());
8019
8020 //Make sure previous profile connects with an icXformLutMCS
8021 if (prev->ptr->GetXformType()!=icXformLutMCS) {
8022 //check to see if we can convert previous xform to connect via an MCS
8023 if (!prev->ptr->GetProfile()->m_Header.mcs) {
8024 return icCmmStatBadMCSLink;
8025 }
8026
8027 CIccXform *pPrev = prev->ptr;
8028 CIccXform *pNew = CIccXform::Create(pPrev->GetProfilePtr(), pPrev->IsInput(), pPrev->GetIntent(), pPrev->GetInterp(),
8029 pPrev->GetConnectionConditions(), icXformLutMCS, bUseD2BxB2DxTags, pHintManager);
8030
8031 if (pNew) {
8032 pPrev->DetachAll();
8033 delete pPrev;
8034 }
8035
8036 prev->ptr = pNew;
8037
8038 }
8039 }
8040 else {
8041 return icCmmStatBadMCSLink;
8042 }
8043
8044 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
8045 if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) {
8046 if (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS) {
8047 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
8048 }
8049 else {
8050 nDstSpace = pProfile->m_Header.pcs;
8051 }
8052 }
8053 else if (pProfile->m_Header.deviceClass==icSigMaterialLinkClass) {
8054 nDstSpace = pProfile->m_Header.colorSpace;
8055 }
8056 else {
8057 return icCmmStatBadSpaceLink;
8058 }
8059 }
8060 break;
8061
8062 default:
8063 return icCmmStatBadLutType;
8064 }
8065
8066 //Make sure colorspaces match with previous xforms
8067 if (!m_Xforms->size()) {
8068 if (m_nSrcSpace == icSigUnknownData) {
8069 m_nLastSpace = nSrcSpace;
8070 m_nSrcSpace = nSrcSpace;
8071 }
8072 else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)) {
8073 return icCmmStatBadSpaceLink;
8074 }
8075 }
8076 else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)) {
8077 return icCmmStatBadSpaceLink;
8078 }
8079
8080 if (nSrcSpace==icSigNamedData)
8081 return icCmmStatBadSpaceLink;
8082
8083 //Automatic creation of intent from header/last profile
8084 if (nIntent==icUnknownIntent) {
8085 if (bInput) {
8086 nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent;
8087 }
8088 else {
8089 nIntent = m_nLastIntent;
8090 }
8091 if (nIntent == icUnknownIntent)
8092 nIntent = icPerceptual;
8093 }
8094
8095 CIccXformPtr Xform;
8096
8097 Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
8098
8099 if (!Xform.ptr) {
8100 return icCmmStatBadXform;
8101 }
8102
8103 if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) {
8104 bInput = true;
8105 }
8106
8107 m_nLastSpace = nDstSpace;
8108 m_nLastIntent = nIntent;
8109 m_bLastInput = bInput;
8110
8111 m_Xforms->push_back(Xform);
8112
8113 return icCmmStatOk;
8114}
8115
8116/**
8117**************************************************************************
8118* Name: CIccCmm::AddXform
8119*
8120* Purpose:
8121* Adds a profile at the end of the Xform list
8122*
8123* Args:
8124* pProfile = pointer to the CIccProfile object to be added,
8125* nIntent = rendering intent to be used with the profile,
8126* nInterp = type of interpolation to be used with the profile,
8127* nLutType = selection of which transform lut to use
8128* bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
8129* pHintManager = hints for creating the xform
8130*
8131* Return:
8132* icCmmStatOk, if the profile was added to the list succesfully
8133**************************************************************************
8134*/
8135icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile,
8136 CIccTag *pXformTag,
8137 icRenderingIntent nIntent/*= icUnknownIntent*/,
8138 icXformInterp nInterp /*=icInterpLinear*/,
8139 IIccProfileConnectionConditions *pPcc/*=NULL*/,
8140 bool bUseSpectralPCS /*=false*/,
8141 CIccCreateXformHintManager *pHintManager /*=NULL*/)
8142{
8143 icColorSpaceSignature nSrcSpace, nDstSpace;
8144 bool bInput = !m_bLastInput;
8145
8146 if (!pProfile)
8148
8149 switch (pProfile->m_Header.deviceClass) {
8153 return icCmmStatBadLutType;
8154
8155 default:
8156 break;
8157 }
8158
8159 //Check pProfile if nIntent and input can be found.
8160 if (bInput) {
8161 nSrcSpace = pProfile->m_Header.colorSpace;
8162
8163 if (bUseSpectralPCS && pProfile->m_Header.spectralPCS)
8164 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
8165 else {
8166 nDstSpace = pProfile->m_Header.pcs;
8167 bUseSpectralPCS = false;
8168 }
8169 }
8170 else {
8171 if (pProfile->m_Header.deviceClass == icSigLinkClass) {
8172 return icCmmStatBadSpaceLink;
8173 }
8174 if (pProfile->m_Header.deviceClass == icSigAbstractClass) {
8175 bInput = true;
8176 nIntent = icPerceptual; // Note: icPerceptualIntent = 0
8177 }
8178
8179 if (bUseSpectralPCS && pProfile->m_Header.spectralPCS)
8180 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
8181 else {
8182 nSrcSpace = pProfile->m_Header.pcs;
8183 bUseSpectralPCS = false;
8184 }
8185
8186 nDstSpace = pProfile->m_Header.colorSpace;
8187 }
8188
8189 //Make sure colorspaces match with previous xforms
8190 if (!m_Xforms->size()) {
8191 if (m_nSrcSpace == icSigUnknownData) {
8192 m_nLastSpace = nSrcSpace;
8193 m_nSrcSpace = nSrcSpace;
8194 }
8195 else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)) {
8196 return icCmmStatBadSpaceLink;
8197 }
8198 }
8199 else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)) {
8200 return icCmmStatBadSpaceLink;
8201 }
8202
8203 if (nSrcSpace == icSigNamedData)
8204 return icCmmStatBadSpaceLink;
8205
8206 //Automatic creation of intent from header/last profile
8207 if (nIntent == icUnknownIntent) {
8208 if (bInput) {
8209 nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent;
8210 }
8211 else {
8212 nIntent = m_nLastIntent;
8213 }
8214 if (nIntent == icUnknownIntent)
8215 nIntent = icPerceptual;
8216 }
8217
8218 CIccXformPtr Xform;
8219
8220 Xform.ptr = CIccXform::Create(pProfile, pXformTag, bInput, nIntent, nInterp, pPcc, bUseSpectralPCS, pHintManager);
8221
8222 if (!Xform.ptr) {
8223 return icCmmStatBadXform;
8224 }
8225
8226 m_nLastSpace = nDstSpace;
8227 m_nLastIntent = nIntent;
8228 m_bLastInput = bInput;
8229
8230 m_Xforms->push_back(Xform);
8231
8232 return icCmmStatOk;
8233}
8234
8235/**
8236 **************************************************************************
8237 * Name: CIccCmm::AddXform
8238 *
8239 * Purpose:
8240 * Adds a profile at the end of the Xform list
8241 *
8242 * Args:
8243 * Profile = reference a CIccProfile object that will be copies and added,
8244 * nIntent = rendering intent to be used with the profile,
8245 * nInterp = type of interpolation to be used with the profile,
8246 * nLutType = selection of which transform lut to use
8247 * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available
8248 * pHintManager = hints for creating the xform
8249 *
8250 * Return:
8251 * icCmmStatOk, if the profile was added to the list succesfully
8252 **************************************************************************
8253 */
8254icStatusCMM CIccCmm::AddXform(CIccProfile &Profile,
8255 icRenderingIntent nIntent /*=icUnknownIntent*/,
8256 icXformInterp nInterp /*=icInterpLinear*/,
8257 IIccProfileConnectionConditions *pPcc/*=NULL*/,
8258 icXformLutType nLutType /*=icXformLutColor*/,
8259 bool bUseD2BxB2DxTags /*=true*/,
8260 CIccCreateXformHintManager *pHintManager /*=NULL*/)
8261{
8262 CIccProfile *pProfile = new CIccProfile(Profile);
8263
8264 if (!pProfile)
8265 return icCmmStatAllocErr;
8266
8267 icStatusCMM stat = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
8268
8269 if (stat != icCmmStatOk)
8270 delete pProfile;
8271
8272 return stat;
8273}
8274
8275icStatusCMM CIccCmm::CheckPCSConnections(bool bUsePCSConversions/*=false*/)
8276{
8278
8279 CIccXformList::iterator last, next;
8280 CIccXformList xforms;
8281 CIccXformPtr ptr;
8282 bool bUsesPcsXforms = false;
8283
8284 next=m_Xforms->begin();
8285
8286 if (next!=m_Xforms->end()) {
8287 last = next;
8288 next++;
8289
8290 xforms.push_back(*last);
8291
8292 for (;next!=m_Xforms->end(); last=next, next++) {
8293 if ((last->ptr->IsInput() && last->ptr->IsMCS() && next->ptr->IsMCS()) ||
8294 (IsSpaceSpectralPCS(last->ptr->GetDstSpace()) || IsSpaceSpectralPCS(next->ptr->GetSrcSpace())) ||
8295 (!bUsePCSConversions &&
8296 (IsSpaceColorimetricPCS(last->ptr->GetDstSpace()) || IsSpaceColorimetricPCS(next->ptr->GetSrcSpace())))) {
8297 last->ptr->SetDstPCSConversion(false);
8298 next->ptr->SetSrcPCSConversion(false);
8299 CIccPcsXform *pPcs = new CIccPcsXform();
8300
8301 if (!pPcs) {
8302 return icCmmStatAllocErr;
8303 }
8304
8305 rv = pPcs->Connect(last->ptr, next->ptr);
8306
8307 if (rv!=icCmmStatOk && rv!=icCmmStatIdentityXform)
8308 return rv;
8309
8310 if (rv!=icCmmStatIdentityXform) {
8311 ptr.ptr = pPcs;
8312 xforms.push_back(ptr);
8313 }
8314 else {
8315 delete pPcs;
8316 }
8317
8318 bUsesPcsXforms = true;
8319 }
8320 xforms.push_back(*next);
8321 }
8322 }
8323
8324 if (bUsesPcsXforms) {
8325 *m_Xforms = xforms;
8326 }
8327
8328 return rv;
8329}
8330
8331icStatusCMM CIccCmm::CheckPCSRangeConversions()
8332{
8334
8335 CIccXformList::iterator last, next;
8336 CIccXformList xforms;
8337 CIccXformPtr ptr;
8338 bool bUsesRangeConversion = false;
8339
8340 next = m_Xforms->begin();
8341
8342 if (next != m_Xforms->end()) {
8343 last = next;
8344 next++;
8345
8346 xforms.push_back(*last);
8347
8348 for (; next != m_Xforms->end(); last = next, next++) {
8349 //Add extended PCS to standard PCS conversion as needed
8350 if (last->ptr->IsInput() && last->ptr->IsExtendedPCS() && IsSpaceColorimetricPCS(last->ptr->GetDstSpace()) &&
8351 !next->ptr->IsExtendedPCS()) {
8352 CIccProfile* pProfile = last->ptr->GetProfilePtr();
8353 CIccTag* pTag = pProfile->FindTag(icSigHToS0Tag + last->ptr->GetIntent());
8354 if (!pTag) {
8355 pTag = pProfile->FindTag(icSigHToS0Tag);
8356 if (!pTag) {
8357 pTag = pProfile->FindTag(icSigHToS1Tag);
8358 }
8359 }
8360 //If we find the HToSxTag then create a transform for it and inject it into the transform list
8361 if (pTag) {
8362 ptr.ptr = CIccXform::Create(pProfile, pTag, true, last->ptr->GetIntent(), last->ptr->GetInterp(),
8363 last->ptr->GetConnectionConditions(), false);
8364 if (ptr.ptr) {
8365 ptr.ptr->ShareProfile(); //Indicate that profile is shared (so it won't be deleted)
8366 ptr.ptr->SetPcsAdjustXform(); // Indicates that transform should be treated as abstract
8367 ptr.ptr->AttachCmmEnvVarLookup(last->ptr->GetCmmEnvVarLookup());
8368 xforms.push_back(ptr);
8369 bUsesRangeConversion = true;
8370 }
8371 }
8372 }
8373
8374 xforms.push_back(*next);
8375 }
8376 }
8377
8378 if (bUsesRangeConversion) {
8379 *m_Xforms = xforms;
8380 }
8381
8382 return rv;
8383}
8384
8385
8386/**
8387**************************************************************************
8388* Name: CIccCmm::SetLateBindingCC
8389*
8390* Purpose:
8391* Initializes the LateBinding Connection Conditions used by
8392* colorimetric based transforms
8393*
8394**************************************************************************
8395*/
8396void CIccCmm::SetLateBindingCC()
8397{
8398 CIccXformList::iterator i;
8399 CIccXform *pLastXform = NULL;
8400
8401 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
8402 if (i->ptr->IsInput()) {
8403 if (i->ptr->IsLateBinding()) {
8404 CIccXformList::iterator j=i;
8405 j++;
8406 if (j!=m_Xforms->end()) {
8407 if (j->ptr->IsLateBinding()) {
8408 i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8409 j->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8410 pLastXform = i->ptr;
8411 }
8412 else {
8413 i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8414 j->ptr->SetAppliedCC(j->ptr->GetConnectionConditions());
8415 pLastXform = NULL;
8416 }
8417 }
8418 else {
8419 i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8420 pLastXform = NULL;
8421 }
8422 }
8423 else if (IsSpaceSpectralPCS(i->ptr->GetDstSpace())) {
8424 CIccXformList::iterator j=i;
8425 j++;
8426 if (j!=m_Xforms->end()) {
8427 if (j->ptr->IsLateBinding()) {
8428 j->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8429 pLastXform = i->ptr;
8430 }
8431 else if (!j->ptr->IsAbstract()){
8432 j->ptr->SetAppliedCC(j->ptr->GetConnectionConditions());
8433 pLastXform = NULL;
8434 }
8435 }
8436 }
8437 else {
8438 pLastXform = NULL;
8439 }
8440 }
8441 else {
8442 if (!pLastXform)
8443 i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions());
8444 else
8445 pLastXform = NULL;
8446 }
8447 }
8448}
8449
8450
8451/**
8452**************************************************************************
8453* Name: CIccCmm::Begin
8454*
8455* Purpose:
8456* Does the initialization of the Xforms before Apply() is called.
8457* Must be called before Apply().
8458*
8459**************************************************************************
8460*/
8461icStatusCMM CIccCmm::Begin(bool bAllocApplyCmm/*=true*/, bool bUsePCSConversions/*=false*/)
8462{
8463 if (m_pApply)
8464 return icCmmStatOk;
8465
8466 if (m_nDestSpace==icSigUnknownData) {
8467 m_nDestSpace = m_nLastSpace;
8468 }
8469 else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)) {
8470 return icCmmStatBadSpaceLink;
8471 }
8472
8473 if (m_nSrcSpace==icSigNamedData || m_nDestSpace==icSigNamedData) {
8474 return icCmmStatBadSpaceLink;
8475 }
8476
8477 CheckPCSRangeConversions();
8478 SetLateBindingCC();
8479
8480 icStatusCMM rv;
8481 CIccXformList::iterator i;
8482
8483 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
8484
8485 rv = i->ptr->Begin();
8486
8487 if (rv!= icCmmStatOk)
8488 return rv;
8489 }
8490
8491 rv = CheckPCSConnections(bUsePCSConversions);
8492 if (rv != icCmmStatOk && rv!=icCmmStatIdentityXform)
8493 return rv;
8494
8495 if (bAllocApplyCmm) {
8496 m_pApply = GetNewApplyCmm(rv);
8497 }
8498 else
8499 rv = icCmmStatOk;
8500
8501 return rv;
8502}
8503
8504
8505/**
8506 **************************************************************************
8507 * Name: CIccCmm::GetNewApplyCmm
8508 *
8509 * Purpose:
8510 * Allocates an CIccApplyCmm object that does the initialization of the Xforms
8511 * that provides an Apply() function.
8512 * Multiple CIccApplyCmm objects can be allocated and used in separate threads.
8513 *
8514 **************************************************************************
8515 */
8516CIccApplyCmm *CIccCmm::GetNewApplyCmm(icStatusCMM &status)
8517{
8518 CIccApplyCmm *pApply = new CIccApplyCmm(this);
8519
8520 if (!pApply) {
8521 status = icCmmStatAllocErr;
8522 return NULL;
8523 }
8524
8525 CIccXformList::iterator i;
8526 CIccApplyXform *pXform;
8527
8528 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
8529 pXform = i->ptr->GetNewApply(status);
8530 if (!pXform || status != icCmmStatOk) {
8531 delete pApply;
8532 return NULL;
8533 }
8534 pApply->AppendApplyXform(pXform);
8535 }
8536
8537 m_bValid = true;
8538
8539 status = icCmmStatOk;
8540
8541 return pApply;
8542}
8543
8544
8545/**
8546**************************************************************************
8547* Name: CIccCmm::Apply
8548*
8549* Purpose:
8550* Uses the m_pApply object allocated during Begin to Apply the transformations
8551* associated with the CMM.
8552*
8553**************************************************************************
8554*/
8555icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
8556{
8557 return m_pApply->Apply(DstPixel, SrcPixel);
8558}
8559
8560
8561/**
8562**************************************************************************
8563* Name: CIccCmm::Apply
8564*
8565* Purpose:
8566* Uses the m_pApply object allocated during Begin to Apply the transformations
8567* associated with the CMM.
8568*
8569**************************************************************************
8570*/
8571icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
8572{
8573 return m_pApply->Apply(DstPixel, SrcPixel, nPixels);
8574}
8575
8576
8577/**
8578**************************************************************************
8579* Name: CIccCmm::RemoveAllIO()
8580*
8581* Purpose:
8582* Remove any attachments to CIccIO objects associated with the profiles
8583* related to the transforms attached to the CMM.
8584* Must be called after Begin().
8585*
8586* Return:
8587* icCmmStatOK - All IO objects removed
8588* icCmmStatBadXform - Begin() has not been performed.
8589**************************************************************************
8590*/
8591icStatusCMM CIccCmm::RemoveAllIO()
8592{
8593 if (!Valid())
8594 return icCmmStatBadXform;
8595
8596 CIccXformList::iterator i;
8597
8598 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
8599 i->ptr->RemoveIO();
8600 }
8601
8602 return icCmmStatOk;
8603}
8604
8605/**
8606 *************************************************************************
8607 ** Name: CIccCmm::IsInGamut
8608 **
8609 ** Purpose:
8610 ** Function to check if internal representation of gamut is in gamut. Note
8611 ** since gamut table is 8 bit and a color is considered to be in out of gamut
8612 ** if the value is not zero. Then we need to check where the 8 bit representation
8613 ** of the internal value is not zero.
8614 **
8615 ** Args:
8616 ** pInternal = internal pixel representation of gamut value
8617 **
8618 ** Return:
8619 ** true if in gamut, false if out of gamut
8620 **************************************************************************/
8621bool CIccCmm::IsInGamut(icFloatNumber *pInternal)
8622{
8623 if (!((unsigned int)((*pInternal)*255.0)))
8624 return true;
8625 return false;
8626}
8627
8628
8629/**
8630 **************************************************************************
8631 * Name: CIccCmm::ToInternalEncoding
8632 *
8633 * Purpose:
8634 * Functions for converting to Internal representation of pixel colors.
8635 *
8636 * Args:
8637 * nSpace = color space signature of the data,
8638 * nEncode = icFloatColorEncoding type of the data,
8639 * pInternal = converted data is stored here,
8640 * pData = the data to be converted
8641 * bClip = flag to clip to internal range
8642 **************************************************************************
8643 */
8644icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode,
8645 icFloatNumber *pInternal, const icFloatNumber *pData,
8646 bool bClip)
8647{
8648 int nSamples = icGetSpaceSamples(nSpace);
8649 if (!nSamples)
8651
8652
8654 CIccPixelBuf pInput(nSamples);
8655
8656 if (!pInput.get())
8657 return icCmmStatAllocErr;
8658
8659 memcpy(pInput, pData, nSamples*sizeof(icFloatNumber));
8660 bool bCLRspace = icIsSpaceCLR(nSpace);
8661
8662 switch(icGetColorSpaceType(nSpace))
8663 {
8668 bCLRspace = true;
8669 break;
8670 }
8671
8672 switch(nSpace) {
8673
8674 case icSigLabData:
8675 {
8676 switch(nEncode) {
8677 case icEncodeValue:
8678 {
8679 icLabToPcs(pInput);
8680 break;
8681 }
8682 case icEncodeFloat:
8683 {
8684 break;
8685 }
8686 case icEncode8Bit:
8687 {
8688 pInput[0] = icU8toF((icUInt8Number)pInput[0])*100.0f;
8689 pInput[1] = icU8toAB((icUInt8Number)pInput[1]);
8690 pInput[2] = icU8toAB((icUInt8Number)pInput[2]);
8691
8692 icLabToPcs(pInput);
8693 break;
8694 }
8695 case icEncode16Bit:
8696 {
8697 pInput[0] = icU16toF((icUInt16Number)pInput[0]);
8698 pInput[1] = icU16toF((icUInt16Number)pInput[1]);
8699 pInput[2] = icU16toF((icUInt16Number)pInput[2]);
8700 break;
8701 }
8702 case icEncode16BitV2:
8703 {
8704 pInput[0] = icU16toF((icUInt16Number)pInput[0]);
8705 pInput[1] = icU16toF((icUInt16Number)pInput[1]);
8706 pInput[2] = icU16toF((icUInt16Number)pInput[2]);
8707
8708 CIccPCS::Lab2ToLab4(pInput, pInput);
8709 break;
8710 }
8711 default:
8713 break;
8714 }
8715 break;
8716 }
8717
8718 case icSigXYZData:
8719 {
8720 switch(nEncode) {
8721 case icEncodeValue:
8722 {
8723 pInput[0] = (icFloatNumber)pInput[0];
8724 pInput[1] = (icFloatNumber)pInput[1];
8725 pInput[2] = (icFloatNumber)pInput[2];
8726 icXyzToPcs(pInput);
8727 break;
8728 }
8729 case icEncodePercent:
8730 {
8731 pInput[0] = (icFloatNumber)(pInput[0] / 100.0);
8732 pInput[1] = (icFloatNumber)(pInput[1] / 100.0);
8733 pInput[2] = (icFloatNumber)(pInput[2] / 100.0);
8734 icXyzToPcs(pInput);
8735 break;
8736 }
8737 case icEncodeFloat:
8738 {
8739 icXyzToPcs(pInput);
8740 break;
8741 }
8742
8743 case icEncode16Bit:
8744 case icEncode16BitV2:
8745 {
8746 pInput[0] = icUSFtoD((icU1Fixed15Number)pInput[0]);
8747 pInput[1] = icUSFtoD((icU1Fixed15Number)pInput[1]);
8748 pInput[2] = icUSFtoD((icU1Fixed15Number)pInput[2]);
8749 break;
8750 }
8751
8752 default:
8754 break;
8755 }
8756 break;
8757 }
8758
8759 case icSigNamedData:
8761
8762 default:
8763 {
8764 switch(nEncode) {
8765 case icEncodeValue:
8766 {
8767 if (!bCLRspace || nSamples<3) {
8769 }
8770 if (nSamples==3)
8771 icLabToPcs(pInput);
8772 break;
8773 }
8774
8775 case icEncodePercent:
8776 {
8777 if (bClip) {
8778 for(i=0; i<nSamples; i++) {
8779 pInput[i] = (icFloatNumber)(pInput[i]/100.0);
8780 if (pInput[i] < 0.0) pInput[i] = 0.0;
8781 if (pInput[i] > 1.0) pInput[i] = 1.0;
8782 }
8783 }
8784 else {
8785 for(i=0; i<nSamples; i++) {
8786 pInput[i] = (icFloatNumber)(pInput[i]/100.0);
8787 }
8788 }
8789 break;
8790 }
8791
8792 case icEncodeFloat:
8793 {
8794 if (bClip) {
8795 for(i=0; i<nSamples; i++) {
8796 if (pInput[i] < 0.0) pInput[i] = 0.0;
8797 if (pInput[i] > 1.0) pInput[i] = 1.0;
8798 }
8799 }
8800 break;
8801 }
8802
8803 case icEncode8Bit:
8804 {
8805 for(i=0; i<nSamples; i++) {
8806 pInput[i] = icU8toF((icUInt8Number)pInput[i]);
8807 }
8808 break;
8809 }
8810
8811 case icEncode16Bit:
8812 case icEncode16BitV2:
8813 {
8814 for(i=0; i<nSamples; i++) {
8815 pInput[i] = icU16toF((icUInt16Number)pInput[i]);
8816 }
8817 break;
8818 }
8819
8820 default:
8822 break;
8823 }
8824 break;
8825 }
8826 }
8827
8828 memcpy(pInternal, pInput, nSamples*sizeof(icFloatNumber));
8829 return icCmmStatOk;
8830}
8831
8832
8833/**
8834**************************************************************************
8835* Name: CIccCmm::ToInternalEncoding
8836*
8837* Purpose:
8838* Functions for converting to Internal representation of 8 bit pixel colors.
8839*
8840* Args:
8841* nSpace = color space signature of the data,
8842* nEncode = icFloatColorEncoding type of the data,
8843* pInternal = converted data is stored here,
8844* pData = the data to be converted
8845* bClip = flag to clip to internal range
8846**************************************************************************
8847*/
8848icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal,
8849 const icUInt8Number *pData)
8850{
8851 switch(nSpace) {
8852 case icSigRgbData:
8853 {
8854 pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 255.0);
8855 pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 255.0);
8856 pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 255.0);
8857
8858 return icCmmStatOk;
8859 }
8860 case icSigCmykData:
8861 {
8862 pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 255.0);
8863 pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 255.0);
8864 pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 255.0);
8865 pInternal[3] = (icFloatNumber)((icFloatNumber)pData[3] / 255.0);
8866 return icCmmStatOk;
8867 }
8868 default:
8869 {
8871 icUInt32Number nSamples = icGetSpaceSamples(nSpace);
8872 CIccPixelBuf FloatPixel(nSamples);
8873 if (!FloatPixel.get())
8874 return icCmmStatAllocErr;
8875
8876 for(i=0; i<nSamples; i++) {
8877 FloatPixel[i] = (icFloatNumber)pData[i];
8878 }
8879 return ToInternalEncoding(nSpace, icEncode8Bit, pInternal, FloatPixel);
8880 }
8881 }
8882
8883}
8884
8885
8886/**
8887**************************************************************************
8888* Name: CIccCmm::ToInternalEncoding
8889*
8890* Purpose:
8891* Functions for converting to Internal representation of 16 bit pixel colors.
8892*
8893* Args:
8894* nSpace = color space signature of the data,
8895* nEncode = icFloatColorEncoding type of the data,
8896* pInternal = converted data is stored here,
8897* pData = the data to be converted
8898* bClip = flag to clip to internal range
8899**************************************************************************
8900*/
8901icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal,
8902 const icUInt16Number *pData)
8903{
8904 switch(nSpace) {
8905 case icSigRgbData:
8906 {
8907 pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 65535.0);
8908 pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 65535.0);
8909 pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 65535.0);
8910
8911 return icCmmStatOk;
8912 }
8913 case icSigCmykData:
8914 {
8915 pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 65535.0);
8916 pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 65535.0);
8917 pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 65535.0);
8918 pInternal[3] = (icFloatNumber)((icFloatNumber)pData[3] / 65535.0);
8919 return icCmmStatOk;
8920 }
8921 default:
8922 {
8924 icUInt32Number nSamples = icGetSpaceSamples(nSpace);
8925 CIccPixelBuf pFloatPixel(nSamples);
8926 if (!pFloatPixel.get())
8927 return icCmmStatAllocErr;
8928
8929 for(i=0; i<nSamples; i++) {
8930 pFloatPixel[i] = (icFloatNumber)pData[i];
8931 }
8932 return ToInternalEncoding(nSpace, icEncode16Bit, pInternal, pFloatPixel);
8933 }
8934 }
8935}
8936
8937
8938/**
8939 **************************************************************************
8940 * Name: CIccCmm::FromInternalEncoding
8941 *
8942 * Purpose:
8943 * Functions for converting from Internal representation of pixel colors.
8944 *
8945 * Args:
8946 * nSpace = color space signature of the data,
8947 * nEncode = icFloatColorEncoding type of the data,
8948 * pData = converted data is stored here,
8949 * pInternal = the data to be converted
8950 * bClip = flag to clip data to internal range
8951 **************************************************************************
8952 */
8953icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode,
8954 icFloatNumber *pData, const icFloatNumber *pInternal, bool bClip)
8955{
8956 int nSamples = icGetSpaceSamples(nSpace);
8957 if (!nSamples)
8959
8961 CIccPixelBuf pInput(nSamples);
8962
8963 if (!pInput.get())
8964 return icCmmStatAllocErr;
8965
8966 memcpy(pInput, pInternal, nSamples*sizeof(icFloatNumber));
8967 bool bCLRspace = (icIsSpaceCLR(nSpace) || (nSpace == icSigDevLabData) || (nSpace==icSigDevXYZData));
8968
8969 switch(nSpace) {
8970
8971 case icSigLabData:
8972 {
8973 switch(nEncode) {
8974 case icEncodeValue:
8975 {
8976 icLabFromPcs(pInput);
8977 break;
8978 }
8979 case icEncodeUnitFloat:
8980 case icEncodeFloat:
8981 {
8982 break;
8983 }
8984 case icEncode8Bit:
8985 {
8986 icLabFromPcs(pInput);
8987
8988 pInput[0] = (icUInt8Number)(pInput[0]/100.0 * 255.0 + 0.5);
8989 pInput[1] = icABtoU8(pInput[1]);
8990 pInput[2] = icABtoU8(pInput[2]);
8991 break;
8992 }
8993 case icEncode16Bit:
8994 {
8995 pInput[0] = icFtoU16(pInput[0]);
8996 pInput[1] = icFtoU16(pInput[1]);
8997 pInput[2] = icFtoU16(pInput[2]);
8998 break;
8999 }
9000 case icEncode16BitV2:
9001 {
9002 CIccPCS::Lab4ToLab2(pInput, pInput);
9003
9004 pInput[0] = icFtoU16(pInput[0]);
9005 pInput[1] = icFtoU16(pInput[1]);
9006 pInput[2] = icFtoU16(pInput[2]);
9007 break;
9008 }
9009 default:
9011 break;
9012 }
9013 break;
9014 }
9015
9016 case icSigXYZData:
9017 {
9018 switch(nEncode) {
9019 case icEncodeValue:
9020 {
9021 icXyzFromPcs(pInput);
9022 break;
9023 }
9024 case icEncodePercent:
9025 {
9026 icXyzFromPcs(pInput);
9027 pInput[0] = (icFloatNumber)(pInput[0] * 100.0);
9028 pInput[1] = (icFloatNumber)(pInput[1] * 100.0);
9029 pInput[2] = (icFloatNumber)(pInput[2] * 100.0);
9030 break;
9031 }
9032 case icEncodeFloat:
9033 case icEncodeUnitFloat:
9034 {
9035 icXyzFromPcs(pInput);
9036 break;
9037 }
9038
9039 case icEncode16Bit:
9040 case icEncode16BitV2:
9041 {
9042 icXyzFromPcs(pInput);
9043 pInput[0] = icDtoUSF(pInput[0]);
9044 pInput[1] = icDtoUSF(pInput[1]);
9045 pInput[2] = icDtoUSF(pInput[2]);
9046 break;
9047 }
9048
9049 default:
9051 break;
9052 }
9053 break;
9054 }
9055
9056 case icSigNamedData:
9058
9059 default:
9060 {
9061 switch(nEncode) {
9062 case icEncodeValue:
9063 {
9064 if (nSpace == icSigDevXYZData) {
9065 icXyzFromPcs(pInput);
9066 }
9067 else if (bCLRspace && nSamples >=3) {
9068 icLabFromPcs(pInput);
9069 }
9070 break;
9071 }
9072 case icEncodePercent:
9073 {
9074 if (bClip) {
9075 for(i=0; i<nSamples; i++) {
9076 if (pInput[i] < 0.0) pInput[i] = 0.0;
9077 if (pInput[i] > 1.0) pInput[i] = 1.0;
9078 pInput[i] = (icFloatNumber)(pInput[i]*100.0);
9079 }
9080 }
9081 else {
9082 for(i=0; i<nSamples; i++) {
9083 pInput[i] = (icFloatNumber)(pInput[i]*100.0);
9084 }
9085 }
9086 break;
9087 }
9088
9089 case icEncodeFloat:
9090 break;
9091
9092 case icEncodeUnitFloat:
9093 {
9094 if (bClip) {
9095 for(i=0; i<nSamples; i++) {
9096 if (pInput[i] < 0.0) pInput[i] = 0.0;
9097 if (pInput[i] > 1.0) pInput[i] = 1.0;
9098 }
9099 }
9100 break;
9101 }
9102
9103 case icEncode8Bit:
9104 {
9105 for(i=0; i<nSamples; i++) {
9106 pInput[i] = icFtoU8(pInput[i]);
9107 }
9108 break;
9109 }
9110
9111 case icEncode16Bit:
9112 case icEncode16BitV2:
9113 {
9114 for(i=0; i<nSamples; i++) {
9115 pInput[i] = icFtoU16(pInput[i]);
9116 }
9117 break;
9118 }
9119
9120 default:
9122 break;
9123 }
9124 break;
9125 }
9126 }
9127
9128 memcpy(pData, pInput, nSamples*sizeof(icFloatNumber));
9129 return icCmmStatOk;
9130}
9131
9132
9133/**
9134**************************************************************************
9135* Name: CIccCmm::FromInternalEncoding
9136*
9137* Purpose:
9138* Functions for converting from Internal representation of 8 bit pixel colors.
9139*
9140* Args:
9141* nSpace = color space signature of the data,
9142* nEncode = icFloatColorEncoding type of the data,
9143* pData = converted data is stored here,
9144* pInternal = the data to be converted
9145* bClip = flag to clip data to internal range
9146**************************************************************************
9147*/
9148icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icUInt8Number *pData,
9149 const icFloatNumber *pInternal)
9150{
9151 switch(nSpace) {
9152 case icSigRgbData:
9153 {
9154 pData[0] = icFtoU8(pInternal[0]);
9155 pData[1] = icFtoU8(pInternal[1]);
9156 pData[2] = icFtoU8(pInternal[2]);
9157
9158 return icCmmStatOk;
9159 }
9160 case icSigCmykData:
9161 {
9162 pData[0] = icFtoU8(pInternal[0]);
9163 pData[1] = icFtoU8(pInternal[1]);
9164 pData[2] = icFtoU8(pInternal[2]);
9165 pData[3] = icFtoU8(pInternal[3]);
9166
9167 return icCmmStatOk;
9168 }
9169 default:
9170 {
9172 icUInt32Number nSamples = icGetSpaceSamples(nSpace);
9173
9174 CIccPixelBuf pFloatPixel(nSamples);
9175 icStatusCMM convertStat;
9176
9177 if (!pFloatPixel.get())
9178 return icCmmStatAllocErr;
9179
9180 convertStat = FromInternalEncoding(nSpace, icEncode8Bit, pFloatPixel, pInternal);
9181 if (convertStat)
9182 return convertStat;
9183 for(i=0; i<nSamples; i++) {
9184 pData[i] = (icUInt8Number)(pFloatPixel[i] + 0.5);
9185 }
9186
9187 return icCmmStatOk;
9188 }
9189 }
9190}
9191
9192
9193/**
9194**************************************************************************
9195* Name: CIccCmm::FromInternalEncoding
9196*
9197* Purpose:
9198* Functions for converting from Internal representation of 16 bit pixel colors.
9199*
9200* Args:
9201* nSpace = color space signature of the data,
9202* nEncode = icFloatColorEncoding type of the data,
9203* pData = converted data is stored here,
9204* pInternal = the data to be converted
9205* bClip = flag to clip data to internal range
9206**************************************************************************
9207*/
9208icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icUInt16Number *pData,
9209 const icFloatNumber *pInternal)
9210{
9211 switch(nSpace) {
9212 case icSigRgbData:
9213 {
9214 pData[0] = icFtoU16(pInternal[0]);
9215 pData[1] = icFtoU16(pInternal[1]);
9216 pData[2] = icFtoU16(pInternal[2]);
9217
9218 return icCmmStatOk;
9219 }
9220 case icSigCmykData:
9221 {
9222 pData[0] = icFtoU16(pInternal[0]);
9223 pData[1] = icFtoU16(pInternal[1]);
9224 pData[2] = icFtoU16(pInternal[2]);
9225 pData[3] = icFtoU16(pInternal[3]);
9226
9227 return icCmmStatOk;
9228 }
9229 default:
9230 {
9232 icUInt32Number nSamples = icGetSpaceSamples(nSpace);
9233 CIccPixelBuf pFloatPixel(nSamples);
9234 icStatusCMM convertStat;
9235
9236 if (!pFloatPixel.get())
9237 return icCmmStatAllocErr;
9238
9239 convertStat = FromInternalEncoding(nSpace, icEncode16Bit, pFloatPixel, pInternal);
9240 if (convertStat)
9241 return convertStat;
9242 for(i=0; i<nSamples; i++) {
9243 pData[i] = (icUInt16Number)(pFloatPixel[i] + 0.5);
9244 }
9245
9246 return icCmmStatOk;
9247 }
9248 }
9249}
9250
9251
9252/**
9253 **************************************************************************
9254 * Name: CIccCmm::GetFloatColorEncoding
9255 *
9256 * Purpose:
9257 * Converts the encoding type to characters for printing
9258 *
9259 * Args:
9260 * val = encoding type
9261 *
9262 * Return:
9263 * characters for printing
9264 **************************************************************************
9265 */
9266const icChar* CIccCmm::GetFloatColorEncoding(icFloatColorEncoding val)
9267{
9268 switch(val) {
9269
9270 case icEncodeValue:
9271 return "icEncodeValue";
9272
9273 case icEncodeFloat:
9274 return "icEncodeFloat";
9275
9276 case icEncodeUnitFloat:
9277 return "icEncodeUnitFloat";
9278
9279 case icEncodePercent:
9280 return "icEncodePercent";
9281
9282 case icEncode8Bit:
9283 return "icEncode8Bit";
9284
9285 case icEncode16Bit:
9286 return "icEncode16Bit";
9287
9288 case icEncode16BitV2:
9289 return "icEncode16BitV2";
9290
9291 default:
9292 return "icEncodeUnknown";
9293 }
9294}
9295
9296/**
9297 **************************************************************************
9298 * Name: CIccCmm::GetFloatColorEncoding
9299 *
9300 * Purpose:
9301 * Converts the string containing encoding type to icFloatColorEncoding
9302 *
9303 * Args:
9304 * val = string containing encoding type
9305 *
9306 * Return:
9307 * encoding type
9308 **************************************************************************
9309 */
9310icFloatColorEncoding CIccCmm::GetFloatColorEncoding(const icChar* val)
9311{
9312 if (!stricmp(val, "icEncodePercent")) {
9313 return icEncodePercent;
9314 }
9315 else if (!stricmp(val, "icEncodeUnitFloat")) {
9316 return icEncodeUnitFloat;
9317 }
9318 else if (!stricmp(val, "icEncodeFloat")) {
9319 return icEncodeFloat;
9320 }
9321 else if (!stricmp(val, "icEncode8Bit")) {
9322 return icEncode8Bit;
9323 }
9324 else if (!stricmp(val, "icEncode16Bit")) {
9325 return icEncode16Bit;
9326 }
9327 else if (!stricmp(val, "icEncode16BitV2")) {
9328 return icEncode16BitV2;
9329 }
9330 else if (!stricmp(val, "icEncodeValue")) {
9331 return icEncodeValue;
9332 }
9333 else {
9334 return icEncodeUnknown;
9335 }
9336
9337}
9338
9339/**
9340 **************************************************************************
9341 * Name: CIccCmm::GetNumXforms
9342 *
9343 * Purpose:
9344 * Get number of xforms in the xform list
9345 *
9346 * Return:
9347 * number of m_Xforms
9348 **************************************************************************
9349 */
9350icUInt32Number CIccCmm::GetNumXforms() const
9351{
9352 return (icUInt32Number)m_Xforms->size();
9353}
9354
9355
9356/**
9357 **************************************************************************
9358 * Name: CIccCmm::IterateXforms
9359 *
9360 * Purpose:
9361 * Get information from xform in the list
9362 *
9363 **************************************************************************
9364 */
9365void CIccCmm::IterateXforms( IXformIterator* pIterater) const
9366{
9367 for (auto x = m_Xforms->begin(); x != m_Xforms->end(); x++) {
9368 pIterater->iterate(x->ptr);
9369 }
9370}
9371
9372
9373/**
9374**************************************************************************
9375* Name: CIccCmm::GetFirstXformSource
9376*
9377* Purpose:
9378* Get source colorspace of first transform (similar to m_nSrcSpace with differences in dev colorimetric spaces)
9379*
9380* Return:
9381* colorspace
9382**************************************************************************
9383*/
9384icColorSpaceSignature CIccCmm::GetFirstXformSource()
9385{
9386 if (!m_Xforms->size())
9387 return m_nSrcSpace;
9388
9389 return m_Xforms->begin()->ptr->GetSrcSpace();
9390}
9391
9392/**
9393**************************************************************************
9394* Name: CIccCmm::GetNumXforms
9395*
9396* Purpose:
9397* Get source colorspace of last transform (similar to m_nSrcSpace with differences in dev colorimetric spaces)
9398*
9399* Return:
9400* colorspace
9401**************************************************************************
9402*/
9403icColorSpaceSignature CIccCmm::GetLastXformDest()
9404{
9405 if (!m_Xforms->size())
9406 return m_nDestSpace;
9407
9408 return m_Xforms->rbegin()->ptr->GetDstSpace();
9409}
9410
9411/**
9412**************************************************************************
9413* Name: CIccApplyCmm::CIccApplyCmm
9414*
9415* Purpose:
9416* Constructor
9417*
9418* Args:
9419* pCmm = ptr to CMM to apply against
9420**************************************************************************
9421*/
9422CIccApplyNamedColorCmm::CIccApplyNamedColorCmm(CIccNamedColorCmm *pCmm) : CIccApplyCmm(pCmm)
9423{
9424}
9425
9426
9427/**
9428**************************************************************************
9429* Name: CIccApplyCmm::CIccApplyCmm
9430*
9431* Purpose:
9432* Destructor
9433**************************************************************************
9434*/
9435CIccApplyNamedColorCmm::~CIccApplyNamedColorCmm()
9436{
9437}
9438
9439
9440/**
9441**************************************************************************
9442* Name: CIccApplyNamedColorCmm::Apply
9443*
9444* Purpose:
9445* Does the actual application of the Xforms in the list.
9446*
9447* Args:
9448* DstPixel = Destination pixel where the result is stored,
9449* SrcPixel = Source pixel which is to be applied.
9450**************************************************************************
9451*/
9452icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
9453{
9454 icFloatNumber *pDst, *pTmp;
9455 const icFloatNumber *pSrc;
9456 CIccApplyXformList::iterator i;
9457 int j, n = (int)m_Xforms->size();
9458 CIccApplyXform *pApply;
9459 const CIccXform *pApplyXform;
9460 CIccXformNamedColor *pXform;
9461
9462 if (!n)
9463 return icCmmStatBadXform;
9464
9465 if (!m_Pixel && !InitPixel()) {
9466 return icCmmStatAllocErr;
9467 }
9468
9469 icChar NamedColor[256];
9470 icStatusCMM rv;
9471
9472 m_pPCS->Reset(m_pCmm->GetSourceSpace());
9473
9474 pSrc = SrcPixel;
9475 pDst = m_Pixel;
9476
9477#ifdef DEBUG_CMM_APPLY
9478 int nCount = 0;
9479 printf("Start ApplyNamedCmm\n");
9480 DumpCmmApplyPixel(nCount++, pSrc, icGetSpaceSamples(m_pCmm->GetSourceSpace()));
9481#endif
9482
9483
9484 if (n>1) {
9485 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
9486
9487 pApply = i->ptr;
9488 pApplyXform = pApply->GetXform();
9489 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9490 pXform = (CIccXformNamedColor*)pApplyXform;
9491
9492 switch(pXform->GetInterface()) {
9493 case icApplyPixel2Pixel:
9494 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9495#ifdef DEBUG_CMM_APPLY
9496 DumpCmmApplyPixel(nCount++, pDst, pXform->GetNumDstSamples());
9497#endif
9498 break;
9499
9500 case icApplyPixel2Named:
9501 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
9502#ifdef DEBUG_CMM_APPLY
9503 printf("Xfm%d: \"%s\"\n", nCount++, NamedColor);
9504#endif
9505 break;
9506
9507 case icApplyNamed2Pixel:
9508 if (j==0) {
9510 }
9511
9512 rv = pXform->Apply(pApply, pDst, NamedColor);
9513#ifdef DEBUG_CMM_APPLY
9514 DumpCmmApplyPixel(nCount++, pDst, pXform->GetNumDstSamples());
9515#endif
9516
9517 if (rv) {
9518 return rv;
9519 }
9520 break;
9521
9522 default:
9523 break;
9524 }
9525 }
9526 else {
9527 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
9528#ifdef DEBUG_CMM_APPLY
9529 DumpCmmApplyPixel(nCount++, pDst, pApplyXform->GetNumDstSamples());
9530#endif
9531 }
9532 pTmp = (icFloatNumber*)pSrc;
9533 pSrc = pDst;
9534 if (pTmp==SrcPixel)
9535 pDst = m_Pixel2;
9536 else
9537 pDst = pTmp;
9538 }
9539
9540 pApply = i->ptr;
9541 pApplyXform = pApply->GetXform();
9542 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9543 pXform = (CIccXformNamedColor*)pApplyXform;
9544
9545 switch(pXform->GetInterface()) {
9546 case icApplyPixel2Pixel:
9547 pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform));
9548#ifdef DEBUG_CMM_APPLY
9549 DumpCmmApplyPixel(nCount++, DstPixel, pXform->GetNumDstSamples());
9550#endif
9551 break;
9552
9553 case icApplyPixel2Named:
9554 default:
9556 break;
9557
9558 case icApplyNamed2Pixel:
9559 rv = pXform->Apply(pApply, DstPixel, NamedColor);
9560#ifdef DEBUG_CMM_APPLY
9561 DumpCmmApplyPixel(nCount++, DstPixel, pXform->GetNumDstSamples());
9562#endif
9563 if (rv) {
9564 return rv;
9565 }
9566 break;
9567
9568 }
9569 }
9570 else {
9571 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9572#ifdef DEBUG_CMM_APPLY
9573 DumpCmmApplyPixel(nCount++, DstPixel, pApplyXform->GetNumDstSamples());
9574#endif
9575 }
9576
9577 }
9578 else if (n==1) {
9579 i = m_Xforms->begin();
9580
9581 pApply = i->ptr;
9582 pApplyXform = pApply->GetXform();
9583 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9585 }
9586
9587 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9588#ifdef DEBUG_CMM_APPLY
9589 DumpCmmApplyPixel(nCount++, DstPixel, pApplyXform->GetNumDstSamples());
9590#endif
9591 }
9592
9593 m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace(), true);
9594#ifdef DEBUG_CMM_APPLY
9595 DumpCmmApplyPixel(nCount++, DstPixel, icGetSpaceSamples(m_pCmm->GetDestSpace()));
9596 printf("End ApplyNamedCmm\n\n");
9597#endif
9598
9599 return icCmmStatOk;
9600}
9601
9602
9603/**
9604**************************************************************************
9605* Name: CIccApplyNamedColorCmm::Apply
9606*
9607* Purpose:
9608* Does the actual application of the Xforms in the list.
9609*
9610* Args:
9611* DstPixel = Destination pixel where the result is stored,
9612* SrcPixel = Source pixel which is to be applied.
9613**************************************************************************
9614*/
9615icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
9616{
9617 icFloatNumber *pDst;
9618 const icFloatNumber *pSrc;
9619 CIccApplyXformList::iterator i;
9620 int j, n = (int)m_Xforms->size();
9621 CIccApplyXform *pApply;
9622 const CIccXform *pApplyXform;
9623 CIccXformNamedColor *pXform;
9624 icUInt32Number k;
9625
9626 if (!n)
9627 return icCmmStatBadXform;
9628
9629 if (!m_Pixel && !InitPixel()) {
9630 return icCmmStatAllocErr;
9631 }
9632
9633 icChar NamedColor[255];
9634 icStatusCMM rv;
9635
9636 for (k=0; k<nPixels; k++) {
9637 m_pPCS->Reset(m_pCmm->GetSourceSpace());
9638
9639 pSrc = SrcPixel;
9640 pDst = m_Pixel;
9641
9642 if (n>1) {
9643 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
9644
9645 pApply = i->ptr;
9646 pApplyXform = pApply->GetXform();
9647 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9648 pXform = (CIccXformNamedColor*)pApplyXform;
9649
9650 switch(pXform->GetInterface()) {
9651 case icApplyPixel2Pixel:
9652 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9653 break;
9654
9655 case icApplyPixel2Named:
9656 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
9657 break;
9658
9659 case icApplyNamed2Pixel:
9660 if (j==0) {
9662 }
9663
9664 rv = pXform->Apply(pApply, pDst, NamedColor);
9665
9666 if (rv) {
9667 return rv;
9668 }
9669 break;
9670
9671 default:
9672 break;
9673 }
9674 }
9675 else {
9676 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
9677 }
9678 pSrc = pDst;
9679 }
9680
9681 pApply = i->ptr;
9682 pApplyXform = pApply->GetXform();
9683 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9684 pXform = (CIccXformNamedColor*)pApplyXform;
9685
9686 switch(pXform->GetInterface()) {
9687 case icApplyPixel2Pixel:
9688 pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform));
9689 break;
9690
9691 case icApplyPixel2Named:
9692 default:
9694 break;
9695
9696 case icApplyNamed2Pixel:
9697 rv = pXform->Apply(pApply, DstPixel, NamedColor);
9698 if (rv) {
9699 return rv;
9700 }
9701 break;
9702
9703 }
9704 }
9705 else {
9706 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9707 }
9708
9709 }
9710 else if (n==1) {
9711 i = m_Xforms->begin();
9712
9713 pApply = i->ptr;
9714 pApplyXform = pApply->GetXform();
9715 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9717 }
9718
9719 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9720 }
9721
9722 m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace());
9723
9724 SrcPixel += m_pCmm->GetSourceSamples();
9725 DstPixel += m_pCmm->GetDestSamples();
9726 }
9727
9728 return icCmmStatOk;
9729}
9730
9731
9732/**
9733**************************************************************************
9734* Name: CIccApplyNamedColorCmm::Apply
9735*
9736* Purpose:
9737* Does the actual application of the Xforms in the list.
9738*
9739* Args:
9740* DstColorName = Destination string where the result is stored,
9741* SrcPixel = Source pixel which is to be applied.
9742**************************************************************************
9743*/
9744icStatusCMM CIccApplyNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel)
9745{
9746 icFloatNumber *pDst, *pTmp;
9747 const icFloatNumber *pSrc;
9748 CIccApplyXformList::iterator i;
9749 int j, n = (int)m_Xforms->size();
9750 CIccApplyXform *pApply;
9751 const CIccXform *pApplyXform;
9752 CIccXformNamedColor *pXform;
9753
9754 if (!n)
9755 return icCmmStatBadXform;
9756
9757 if (!m_Pixel && !InitPixel()) {
9758 return icCmmStatAllocErr;
9759 }
9760
9761 icChar NamedColor[256];
9762 icStatusCMM rv;
9763
9764 m_pPCS->Reset(m_pCmm->GetSourceSpace());
9765
9766 pSrc = SrcPixel;
9767 pDst = m_Pixel;
9768
9769 if (n>1) {
9770 for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) {
9771
9772 pApply = i->ptr;
9773 pApplyXform = pApply->GetXform();
9774 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9775 pXform = (CIccXformNamedColor*)pApplyXform;
9776 switch(pXform->GetInterface()) {
9777 case icApplyPixel2Pixel:
9778 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9779 break;
9780
9781 case icApplyPixel2Named:
9782 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
9783 break;
9784
9785 case icApplyNamed2Pixel:
9786 if (j==0) {
9788 }
9789 rv = pXform->Apply(pApply, pDst, NamedColor);
9790 if (rv) {
9791 return rv;
9792 }
9793 break;
9794
9795 default:
9796 break;
9797 }
9798 }
9799 else {
9800 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
9801 }
9802 pTmp = (icFloatNumber*)pSrc;
9803 pSrc = pDst;
9804 if (pTmp==SrcPixel)
9805 pDst = m_Pixel2;
9806 else
9807 pDst = pTmp;
9808 }
9809
9810 pApply = i->ptr;
9811 pApplyXform = pApply->GetXform();
9812 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9813 pXform = (CIccXformNamedColor*)pApplyXform;
9814 switch(pXform->GetInterface()) {
9815
9816 case icApplyPixel2Named:
9817 pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform));
9818 break;
9819
9820 case icApplyPixel2Pixel:
9821 case icApplyNamed2Pixel:
9822 default:
9824 break;
9825 }
9826 }
9827 else {
9829 }
9830
9831 }
9832 else if (n==1) {
9833 i = m_Xforms->begin();
9834 pApply = i->ptr;
9835 pApplyXform = pApply->GetXform();
9836 if (pApplyXform->GetXformType()!=icXformTypeNamedColor) {
9838 }
9839
9840 pXform = (CIccXformNamedColor*)pApplyXform;
9841 pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform));
9842 }
9843
9844 return icCmmStatOk;
9845}
9846
9847
9848/**
9849**************************************************************************
9850* Name: CIccApplyNamedColorCmm::Apply
9851*
9852* Purpose:
9853* Does the actual application of the Xforms in the list.
9854*
9855* Args:
9856* DstPixel = Destination pixel where the result is stored,
9857* SrcColorName = Source color name which is to be searched.
9858**************************************************************************
9859*/
9860icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/)
9861{
9862 icFloatNumber *pDst, *pTmp;
9863 const icFloatNumber *pSrc;
9864 CIccApplyXformList::iterator i;
9865 int j, n = (int)m_Xforms->size();
9866 CIccApplyXform *pApply;
9867 const CIccXform *pApplyXform;
9868 CIccXformNamedColor *pXform;
9869
9870 if (!n)
9871 return icCmmStatBadXform;
9872
9873 if (!m_Pixel && !InitPixel()) {
9874 return icCmmStatAllocErr;
9875 }
9876
9877 icChar NamedColor[255];
9878 icStatusCMM rv;
9879
9880 i=m_Xforms->begin();
9881 pApply = i->ptr;
9882 pApplyXform = pApply->GetXform();
9883 if (pApplyXform->GetXformType()!=icXformTypeNamedColor)
9885
9886 pXform = (CIccXformNamedColor*)pApplyXform;
9887 m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS());
9888
9889 pDst = m_Pixel;
9890
9891 if (n>1) {
9892 rv = pXform->Apply(pApply, pDst, SrcColorName, tint);
9893 if (rv) {
9894 return rv;
9895 }
9896
9897 pSrc = pDst;
9898 pDst = m_Pixel2;
9899
9900 for (j=0, i++; j<n-2 && i!=m_Xforms->end(); i++, j++) {
9901
9902 pApply = i->ptr;
9903 pApplyXform = pApply->GetXform();
9904 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9905 CIccXformNamedColor *pXform = (CIccXformNamedColor*)pApplyXform;
9906 switch(pXform->GetInterface()) {
9907 case icApplyPixel2Pixel:
9908 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
9909 break;
9910
9911 case icApplyPixel2Named:
9912 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
9913 break;
9914
9915 case icApplyNamed2Pixel:
9916 rv = pXform->Apply(pApply, pDst, NamedColor);
9917 if (rv) {
9918 return rv;
9919 }
9920 break;
9921
9922 default:
9923 break;
9924 }
9925 }
9926 else {
9927 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform));
9928 }
9929 pTmp = (icFloatNumber*)pSrc;
9930 pSrc = pDst;
9931 pDst = pTmp;
9932 }
9933
9934 pApply = i->ptr;
9935 pApplyXform = pApply->GetXform();
9936 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
9937 pXform = (CIccXformNamedColor*)pApplyXform;
9938 switch(pXform->GetInterface()) {
9939 case icApplyPixel2Pixel:
9940 pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform));
9941 break;
9942
9943 case icApplyPixel2Named:
9944 default:
9946 break;
9947
9948 case icApplyNamed2Pixel:
9949 rv = pXform->Apply(pApply, DstPixel, NamedColor);
9950 if (rv) {
9951 return rv;
9952 }
9953 break;
9954
9955 }
9956 }
9957 else {
9958 pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform));
9959 }
9960
9961 }
9962 else if (n==1) {
9963 rv = pXform->Apply(pApply, DstPixel, SrcColorName, tint);
9964 if (rv) {
9965 return rv;
9966 }
9967 m_pPCS->Check(DstPixel, pXform);
9968 }
9969
9970 m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace());
9971
9972 return icCmmStatOk;
9973}
9974
9975/**
9976**************************************************************************
9977* Name: CIccApplyNamedColorCmm::Apply
9978*
9979* Purpose:
9980* Does the actual application of the Xforms in the list.
9981*
9982* Args:
9983* DstColorName = Destination string where the result is stored,
9984* SrcColorName = Source color name which is to be searched.
9985**************************************************************************
9986*/
9987icStatusCMM CIccApplyNamedColorCmm::Apply(icChar *DstColorName, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/)
9988{
9989 icFloatNumber *pDst, *pTmp;
9990 const icFloatNumber *pSrc;
9991 CIccApplyXformList::iterator i;
9992 int j, n = (int)m_Xforms->size();
9993 icChar NamedColor[256];
9994 icStatusCMM rv;
9995 CIccApplyXform *pApply;
9996 const CIccXform *pApplyXform;
9997 CIccXformNamedColor *pXform;
9998
9999 if (!n)
10000 return icCmmStatBadXform;
10001
10002 if (!m_Pixel && !InitPixel()) {
10003 return icCmmStatAllocErr;
10004 }
10005
10006 i=m_Xforms->begin();
10007
10008 pApply = i->ptr;
10009 pApplyXform = pApply->GetXform();
10010 if (pApplyXform->GetXformType()!=icXformTypeNamedColor)
10012
10013 pXform = (CIccXformNamedColor*)pApplyXform;
10014
10015 m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS());
10016
10017 pDst = m_Pixel;
10018
10019 if (n>1) {
10020 rv = pXform->Apply(pApply, pDst, SrcColorName, tint);
10021
10022 if (rv) {
10023 return rv;
10024 }
10025
10026 pSrc = pDst;
10027 pDst = m_Pixel2;
10028
10029 for (j=0, i++; j<n-2 && i!=m_Xforms->end(); i++, j++) {
10030
10031 pApply = i->ptr;
10032 pApplyXform = pApply->GetXform();
10033 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
10034 pXform = (CIccXformNamedColor*)pApplyXform;
10035 switch(pXform->GetInterface()) {
10036 case icApplyPixel2Pixel:
10037 pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
10038 break;
10039
10040
10041 case icApplyPixel2Named:
10042 pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform));
10043 break;
10044
10045 case icApplyNamed2Pixel:
10046 rv = pXform->Apply(pApply, pDst, NamedColor);
10047 if (rv) {
10048 return rv;
10049 }
10050 break;
10051
10052 default:
10053 break;
10054 }
10055 }
10056 else {
10057 pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform));
10058 }
10059 pTmp = (icFloatNumber*)pSrc;
10060 pSrc = pDst;
10061 pDst = pTmp;
10062 }
10063
10064 pApply = i->ptr;
10065 pApplyXform = pApply->GetXform();
10066 if (pApplyXform->GetXformType()==icXformTypeNamedColor) {
10067 pXform = (CIccXformNamedColor*)pApplyXform;
10068 switch(pXform->GetInterface()) {
10069 case icApplyPixel2Named:
10070 pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform));
10071 break;
10072
10073 case icApplyPixel2Pixel:
10074 case icApplyNamed2Pixel:
10075 default:
10077 break;
10078 }
10079 }
10080 else {
10082 }
10083
10084 }
10085 else if (n==1) {
10087 }
10088
10089 return icCmmStatOk;
10090}
10091
10092/**
10093 **************************************************************************
10094 * Name: CIccNamedColorCmm::CIccNamedColorCmm
10095 *
10096 * Purpose:
10097 * Constructor
10098 *
10099 * Args:
10100 * nSrcSpace = signature of the source color space,
10101 * nDestSpace = signature of the destination color space,
10102 * bFirstInput = true if the first profile added is an input profile
10103 **************************************************************************
10104 */
10105CIccNamedColorCmm::CIccNamedColorCmm(icColorSpaceSignature nSrcSpace, icColorSpaceSignature nDestSpace,
10106 bool bFirstInput) : CIccCmm(nSrcSpace, nDestSpace, bFirstInput)
10107{
10108 m_nApplyInterface = icApplyPixel2Pixel;
10109}
10110
10111/**
10112 **************************************************************************
10113 * Name: CIccNamedColorCmm::~CIccNamedColorCmm
10114 *
10115 * Purpose:
10116 * Destructor
10117 **************************************************************************
10118 */
10119CIccNamedColorCmm::~CIccNamedColorCmm()
10120{
10121}
10122
10123
10124/**
10125 **************************************************************************
10126 * Name: CIccNamedColorCmm::AddXform
10127 *
10128 * Purpose:
10129 * Adds a profile at the end of the Xform list
10130 *
10131 * Args:
10132 * szProfilePath = file name of the profile to be added,
10133 * nIntent = rendering intent to be used with the profile,
10134 * nInterp = type of interpolation to be used with the profile
10135 * pHintManager = hints for creating the xform
10136 *
10137 * Return:
10138 * icCmmStatOk, if the profile was added to the list succesfully
10139 **************************************************************************
10140 */
10141icStatusCMM CIccNamedColorCmm::AddXform(const icChar *szProfilePath,
10142 icRenderingIntent nIntent /*=icUnknownIntent*/,
10143 icXformInterp nInterp /*icXformInterp*/,
10144 IIccProfileConnectionConditions *pPcc/*=NULL*/,
10145 icXformLutType nLutType /*=icXformLutColor*/,
10146 bool bUseD2BxB2DxTags /*=true*/,
10147 CIccCreateXformHintManager *pHintManager /*=NULL*/,
10148 bool bUseSubProfile /*=false*/)
10149{
10150 CIccProfile *pProfile = OpenIccProfile(szProfilePath, bUseSubProfile);
10151
10152 if (!pProfile)
10154
10155 icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager);
10156
10157 if (rv != icCmmStatOk)
10158 delete pProfile;
10159
10160 return rv;
10161}
10162
10163/**
10164 **************************************************************************
10165 * Name: CIccNamedColorCmm::AddXform
10166 *
10167 * Purpose:
10168 * Adds a profile at the end of the Xform list
10169 *
10170 * Args:
10171 * pProfile = pointer to the CIccProfile object to be added,
10172 * nIntent = rendering intent to be used with the profile,
10173 * nInterp = type of interpolation to be used with the profile
10174 * nLutType = type of lut to use from the profile
10175 * pHintManager = hints for creating the xform
10176 *
10177 * Return:
10178 * icCmmStatOk, if the profile was added to the list succesfully
10179 **************************************************************************
10180 */
10181icStatusCMM CIccNamedColorCmm::AddXform(CIccProfile *pProfile,
10182 icRenderingIntent nIntent /*=icUnknownIntent*/,
10183 icXformInterp nInterp /*=icInterpLinear*/,
10184 IIccProfileConnectionConditions *pPcc/*=NULL*/,
10185 icXformLutType nLutType /*=icXformLutColor*/,
10186 bool bUseD2BxB2DxTags /*=true*/,
10187 CIccCreateXformHintManager *pHintManager /*=NULL*/)
10188{
10189 icColorSpaceSignature nSrcSpace, nDstSpace;
10190 CIccXformPtr Xform;
10191 bool bInput = !m_bLastInput;
10192 icStatusCMM rv;
10193 icXformLutType nUseLutType = nLutType;
10194
10195 switch(pProfile->m_Header.deviceClass) {
10198 nIntent = icPerceptual;
10199 nLutType = icXformLutMCS;
10200 break;
10201
10203 nLutType = icXformLutMCS;
10204 break;
10205
10206 default:
10207 break;
10208 }
10209
10210 Xform.ptr = NULL;
10211 switch (nUseLutType) {
10212 //Automatically choose which one
10213 case icXformLutColor:
10215 case icXformLutSpectral:
10217 {
10218 CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag);
10219
10220 if (pTag && (pProfile->m_Header.deviceClass==icSigNamedColorClass || nLutType == icXformLutNamedColor)) {
10221 if (bInput) {
10222 nSrcSpace = icSigNamedData;
10223 }
10224 else if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) {
10225 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
10226 bUseD2BxB2DxTags = true;
10227 }
10228 else {
10229 nSrcSpace = pProfile->m_Header.pcs;
10230 }
10231
10232 if (!m_Xforms->size()) {
10233 if (m_nSrcSpace==icSigUnknownData) {
10234 m_nSrcSpace = nSrcSpace;
10235 }
10236 else {
10237 nSrcSpace = m_nSrcSpace;
10238 }
10239 }
10240 else {
10241 if (m_nLastSpace==icSigUnknownData) {
10242 m_nLastSpace = nSrcSpace;
10243 }
10244 else {
10245 nSrcSpace = m_nLastSpace;
10246 }
10247 }
10248
10249 if (nSrcSpace==icSigNamedData) {
10250 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) {
10251 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
10252 bUseD2BxB2DxTags = true;
10253 }
10254 else {
10255 nDstSpace = pProfile->m_Header.pcs;
10256 }
10257 bInput = true;
10258 }
10259 else {
10260 nDstSpace = icSigNamedData;
10261 bInput = false;
10262 }
10263
10264 Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, icXformLutNamedColor, bUseD2BxB2DxTags, pHintManager);
10265 if (!Xform.ptr) {
10266 return icCmmStatBadXform;
10267 }
10268 CIccXformNamedColor *pXform = (CIccXformNamedColor *)Xform.ptr;
10269 rv = pXform->SetSrcSpace(nSrcSpace);
10270 if (rv)
10271 return rv;
10272
10273 rv = pXform->SetDestSpace(nDstSpace);
10274 if (rv)
10275 return rv;
10276 }
10277 else {
10278 //It isn't named color so make we will use color lut.
10279 if (nUseLutType==icXformLutNamedColor)
10280 nUseLutType = icXformLutColor;
10281
10282 //Check pProfile if nIntent and input can be found.
10283 if (bInput) {
10284 nSrcSpace = pProfile->m_Header.colorSpace;
10285
10286 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) {
10287 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
10288 bUseD2BxB2DxTags = true;
10289 }
10290 else
10291 nDstSpace = pProfile->m_Header.pcs;
10292 }
10293 else {
10294 if (pProfile->m_Header.deviceClass == icSigLinkClass) {
10295 return icCmmStatBadSpaceLink;
10296 }
10297 if (pProfile->m_Header.deviceClass == icSigAbstractClass) {
10298 bInput = true;
10299 nIntent = icPerceptual; // Note: icPerceptualIntent = 0
10300 }
10301
10302 if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) {
10303 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
10304 bUseD2BxB2DxTags = true;
10305 }
10306 else
10307 nSrcSpace = pProfile->m_Header.pcs;
10308
10309 nDstSpace = pProfile->m_Header.colorSpace;
10310 }
10311 }
10312 }
10313 break;
10314
10315 case icXformLutPreview:
10316 nSrcSpace = pProfile->m_Header.pcs;
10317 nDstSpace = pProfile->m_Header.pcs;
10318 bInput = false;
10319 break;
10320
10321 case icXformLutGamut:
10322 nSrcSpace = pProfile->m_Header.pcs;
10323 nDstSpace = icSigGamutData;
10324 bInput = true;
10325 break;
10326
10328 nSrcSpace = pProfile->m_Header.colorSpace;
10329 nDstSpace = icSigUnknownData;
10330 break;
10331
10333 nSrcSpace = pProfile->m_Header.colorSpace;
10334 nDstSpace = icSigUnknownData;
10335 break;
10336
10337 case icXformLutMCS:
10338 switch(pProfile->m_Header.deviceClass)
10339 {
10340 case icSigInputClass:
10342 nSrcSpace = pProfile->m_Header.colorSpace;
10343 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
10344 break;
10346 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
10347 if (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS) {
10348 nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS;
10349 }
10350 else {
10351 nDstSpace = pProfile->m_Header.pcs;
10352 }
10353 bInput = true;
10354 break;
10355
10357 nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs;
10358 nDstSpace = pProfile->m_Header.colorSpace;
10359 break;
10360
10361 default:
10362 return icCmmStatBadLutType;
10363 }
10364 break;
10365
10366 default:
10367 return icCmmStatBadLutType;
10368 }
10369
10370 //Make sure color spaces match with previous xforms
10371 if (!m_Xforms->size()) {
10372 if (m_nSrcSpace == icSigUnknownData) {
10373 m_nLastSpace = nSrcSpace;
10374 m_nSrcSpace = nSrcSpace;
10375 }
10376 else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace) && !IsNChannelCompat(m_nSrcSpace, nSrcSpace)) {
10377 return icCmmStatBadSpaceLink;
10378 }
10379 }
10380 else if (!IsCompatSpace(m_nLastSpace, nSrcSpace) && !IsNChannelCompat(m_nSrcSpace, nSrcSpace)) {
10381 return icCmmStatBadSpaceLink;
10382 }
10383
10384 //Automatic creation of intent from header/last profile
10385 if (nIntent==icUnknownIntent) {
10386 if (bInput) {
10387 nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent;
10388 }
10389 else {
10390 nIntent = m_nLastIntent;
10391 }
10392 if (nIntent == icUnknownIntent)
10393 nIntent = icPerceptual;
10394 }
10395
10396 if (!Xform.ptr)
10397 Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, nUseLutType, bUseD2BxB2DxTags, pHintManager);
10398
10399 if (!Xform.ptr) {
10400 return icCmmStatBadXform;
10401 }
10402
10403 m_nLastSpace = Xform.ptr->GetDstSpace();
10404 m_nLastIntent = nIntent;
10405
10406 if (pProfile->m_Header.deviceClass == icSigLinkClass)
10407 bInput = false;
10408 m_bLastInput = bInput;
10409
10410 m_Xforms->push_back(Xform);
10411
10412 return icCmmStatOk;
10413}
10414
10415/**
10416 **************************************************************************
10417 * Name: CIccNamedColorCmm::Begin
10418 *
10419 * Purpose:
10420 * Does the initialization of the Xforms in the list before Apply() is called.
10421 * Must be called before Apply().
10422 *
10423 **************************************************************************
10424 */
10425 icStatusCMM CIccNamedColorCmm::Begin(bool bAllocNewApply/* =true */, bool bUsePcsConversion/*=false*/)
10426{
10427 if (m_nDestSpace==icSigUnknownData) {
10428 m_nDestSpace = m_nLastSpace;
10429 }
10430 else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)) {
10431 return icCmmStatBadSpaceLink;
10432 }
10433
10434 if (m_nSrcSpace != icSigNamedData) {
10435 if (m_nDestSpace != icSigNamedData) {
10436 m_nApplyInterface = icApplyPixel2Pixel;
10437 }
10438 else {
10439 m_nApplyInterface = icApplyPixel2Named;
10440 }
10441 }
10442 else {
10443 if (m_nDestSpace != icSigNamedData) {
10444 m_nApplyInterface = icApplyNamed2Pixel;
10445 }
10446 else {
10447 m_nApplyInterface = icApplyNamed2Named;
10448 }
10449 }
10450
10451 CheckPCSRangeConversions();
10452 SetLateBindingCC();
10453
10454 icStatusCMM rv;
10455 CIccXformList::iterator i;
10456
10457 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
10458 rv = i->ptr->Begin();
10459
10460 if (rv!= icCmmStatOk) {
10461 return rv;
10462 }
10463 }
10464
10465 rv = CheckPCSConnections(bUsePcsConversion);
10466 if (rv != icCmmStatOk && rv!=icCmmStatIdentityXform)
10467 return rv;
10468
10469 if (bAllocNewApply) {
10470 rv = icCmmStatOk;
10471
10472 m_pApply = GetNewApplyCmm(rv);
10473 }
10474 else
10475 rv = icCmmStatOk;
10476
10477 return rv;
10478}
10479
10480 /**
10481 **************************************************************************
10482 * Name: CIccNamedColorCmm::GetNewApplyCmm
10483 *
10484 * Purpose:
10485 * Allocates a CIccApplyCmm object that allows one to call apply from
10486 * multiple threads.
10487 *
10488 **************************************************************************
10489 */
10490 CIccApplyCmm *CIccNamedColorCmm::GetNewApplyCmm(icStatusCMM &status)
10491 {
10492 CIccApplyCmm *pApply = new CIccApplyNamedColorCmm(this);
10493
10494 CIccXformList::iterator i;
10495
10496 for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) {
10497 CIccApplyXform *pXform = i->ptr->GetNewApply(status);
10498 if (status != icCmmStatOk || !pXform) {
10499 delete pApply;
10500 return NULL;
10501 }
10502 pApply->AppendApplyXform(pXform);
10503 }
10504
10505 m_bValid = true;
10506
10507 status = icCmmStatOk;
10508 return pApply;
10509}
10510
10511
10512 /**
10513 **************************************************************************
10514 * Name: CIccApplyNamedColorCmm::Apply
10515 *
10516 * Purpose:
10517 * Does the actual application of the Xforms in the list.
10518 *
10519 * Args:
10520 * DstColorName = Destination string where the result is stored,
10521 * SrcPoxel = Source pixel
10522 **************************************************************************
10523 */
10524icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel)
10525{
10526 return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcPixel);
10527}
10528
10529
10530/**
10531**************************************************************************
10532* Name: CIccApplyNamedColorCmm::Apply
10533*
10534* Purpose:
10535* Does the actual application of the Xforms in the list.
10536*
10537* Args:
10538* DestPixel = Destination pixel where the result is stored,
10539* SrcColorName = Source color name which is to be searched.
10540**************************************************************************
10541*/
10542icStatusCMM CIccNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/)
10543{
10544 return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstPixel, SrcColorName, tint);
10545}
10546
10547
10548/**
10549**************************************************************************
10550* Name: CIccApplyNamedColorCmm::Apply
10551*
10552* Purpose:
10553* Does the actual application of the Xforms in the list.
10554*
10555* Args:
10556* DstColorName = Destination string where the result is stored,
10557* SrcColorName = Source color name which is to be searched.
10558**************************************************************************
10559*/
10560icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/)
10561{
10562 return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcColorName, tint);
10563}
10564
10565
10566/**
10567 **************************************************************************
10568 * Name: CIccNamedColorCmm::SetLastXformDest
10569 *
10570 * Purpose:
10571 * Sets the destination Color space of the last Xform in the list
10572 *
10573 * Args:
10574 * nDestSpace = signature of the color space to be set
10575 **************************************************************************
10576 */
10577icStatusCMM CIccNamedColorCmm::SetLastXformDest(icColorSpaceSignature nDestSpace)
10578{
10579 int n = (int)m_Xforms->size();
10580 CIccXformPtr *pLastXform;
10581
10582 if (!n)
10583 return icCmmStatBadXform;
10584
10585 pLastXform = &m_Xforms->back();
10586
10587 if (pLastXform->ptr->GetXformType()==icXformTypeNamedColor) {
10588 CIccXformNamedColor *pXform = (CIccXformNamedColor *)pLastXform->ptr;
10589 if (pXform->GetSrcSpace() == icSigNamedData &&
10590 nDestSpace == icSigNamedData) {
10591 return icCmmStatBadSpaceLink;
10592 }
10593
10594 if (nDestSpace != icSigNamedData &&
10595 pXform->GetDstSpace() == icSigNamedData) {
10596 return icCmmStatBadSpaceLink;
10597 }
10598
10599 return pXform->SetDestSpace(nDestSpace);
10600 }
10601
10602 return icCmmStatBadXform;
10603}
10604
10605
10606/**
10607****************************************************************************
10608* Name: CIccMruCmm::CIccMruCmm
10609*
10610* Purpose: private constructor - Use Attach to create CIccMruCmm objects
10611*****************************************************************************
10612*/
10613CIccMruCmm::CIccMruCmm()
10614{
10615 m_pCmm = NULL;
10616 m_bDeleteCmm = false;
10617 m_nCacheSize = 0;
10618}
10619
10620
10621/**
10622****************************************************************************
10623* Name: CIccMruCmm::~CIccMruCmm
10624*
10625* Purpose: destructor
10626*****************************************************************************
10627*/
10628CIccMruCmm::~CIccMruCmm()
10629{
10630 if (m_pCmm && m_bDeleteCmm)
10631 delete m_pCmm;
10632}
10633
10634
10635/**
10636****************************************************************************
10637* Name: CIccMruCmm::Attach
10638*
10639* Purpose: Create a Cmm decorator object that implements a cache of most
10640* recently used pixel transformations.
10641*
10642* Args:
10643* pCmm - pointer to cmm object that we are attaching to.
10644* nCacheSize - number of most recently used transformations to cache
10645* bDeleteCmm - flag to indicate whether cmm should be deleted when
10646* this is destroyed.
10647*
10648* Return:
10649* A CIccMruCmm object that represents a cached form of the pCmm passed in.
10650* The pCmm will be owned by the returned object unless.
10651*
10652* If this function fails the pCmm object will be deleted.
10653*****************************************************************************
10654*/
10655CIccMruCmm* CIccMruCmm::Attach(CIccCmm *pCmm, icUInt8Number nCacheSize/* =4 */, bool bDeleteCmm/*=true*/)
10656{
10657 if (!pCmm || !nCacheSize)
10658 return NULL;
10659
10660 if (!pCmm->Valid()) {
10661 if (bDeleteCmm)
10662 delete pCmm;
10663 return NULL;
10664 }
10665
10666 CIccMruCmm *rv = new CIccMruCmm();
10667
10668 rv->m_pCmm = pCmm;
10669 rv->m_nCacheSize = nCacheSize;
10670 rv->m_bDeleteCmm = bDeleteCmm;
10671
10672 rv->m_nSrcSpace = pCmm->GetSourceSpace();
10673 rv->m_nDestSpace = pCmm->GetDestSpace();
10674 rv->m_nLastSpace = pCmm->GetLastSpace();
10675 rv->m_nLastIntent = pCmm->GetLastIntent();
10676
10677 if (rv->Begin()!=icCmmStatOk) {
10678 delete rv;
10679 return NULL;
10680 }
10681
10682 return rv;
10683}
10684
10685CIccApplyCmm *CIccMruCmm::GetNewApplyCmm(icStatusCMM &status)
10686{
10687 CIccApplyMruCmm *rv = new CIccApplyMruCmm(this);
10688
10689 if (!rv) {
10690 status = icCmmStatAllocErr;
10691 return NULL;
10692 }
10693
10694 if (!rv->Init(m_pCmm, m_nCacheSize)) {
10695 delete rv;
10696 status = icCmmStatBad;
10697 return NULL;
10698 }
10699
10700 return rv;
10701}
10702
10703/**
10704****************************************************************************
10705* Name: CIccMruCache::CIccMruCache
10706*
10707* Purpose: constructor
10708*****************************************************************************
10709*/
10710template<class T>
10711CIccMruCache<T>::CIccMruCache()
10712{
10713 m_cache = NULL;
10714 m_nNumPixel = 0;
10715 m_pixelData = NULL;
10716 m_nSrcSamples = 0;
10717 m_pFirst = NULL;
10718}
10719
10720/**
10721****************************************************************************
10722* Name: CIccMruCache::~CIccMruCache
10723*
10724* Purpose: destructor
10725*****************************************************************************
10726*/
10727template<class T>
10728CIccMruCache<T>::~CIccMruCache()
10729{
10730 if (m_cache)
10731 delete[] m_cache;
10732
10733 if (m_pixelData)
10734 free(m_pixelData);
10735}
10736
10737/**
10738****************************************************************************
10739* Name: CIccMruCache::Init
10740*
10741* Purpose: Initialize the object and set up the cache
10742*
10743* Args:
10744* pCmm - pointer to cmm object that we are attaching to.
10745* nCacheSize - number of most recently used transformations to cache
10746*
10747* Return:
10748* true if successful
10749*****************************************************************************
10750*/
10751template<class T>
10752bool CIccMruCache<T>::Init(icUInt16Number nSrcSamples, icUInt16Number nDstSamples, icUInt16Number nCacheSize)
10753{
10754 m_nSrcSamples = nSrcSamples;
10755 m_nSrcSize = nSrcSamples * sizeof(T);
10756 m_nDstSize = nDstSamples * sizeof(T);
10757
10758 m_nTotalSamples = m_nSrcSamples + nDstSamples;
10759
10760 m_nNumPixel = 0;
10761 m_nCacheSize = nCacheSize;
10762
10763 m_pFirst = NULL;
10764 m_cache = new CIccMruPixel<T>[nCacheSize];
10765
10766 if (!m_cache)
10767 return false;
10768
10769 m_pixelData = (T*)malloc((int)nCacheSize * m_nTotalSamples * sizeof(T));
10770
10771 if (!m_pixelData)
10772 return false;
10773
10774 return true;
10775}
10776
10777template<class T>
10778CIccMruCache<T> *CIccMruCache<T>::NewMruCache(icUInt16Number nSrcSamples, icUInt16Number nDstSamples, icUInt16Number nCacheSize /* = 4 */)
10779{
10780 CIccMruCache<T> *rv = new CIccMruCache<T>;
10781
10782 if (!rv->Init(nSrcSamples, nDstSamples, nCacheSize)) {
10783 delete rv;
10784 return NULL;
10785 }
10786
10787 return rv;
10788}
10789
10790/**
10791****************************************************************************
10792* Name: CIccMruCache::Apply
10793*
10794* Purpose: Apply a transformation to a pixel.
10795*
10796* Args:
10797* DstPixel - Location to store pixel results
10798* SrcPixel - Location to get pixel values from
10799*
10800* Return:
10801* true if SrcPixel found in cache and DstPixel initialized with value
10802* fails if SrcPixel not found (DstPixel not touched)
10803*****************************************************************************
10804*/
10805template<class T>
10806bool CIccMruCache<T>::Apply(T *DstPixel, const T *SrcPixel)
10807{
10808 CIccMruPixel<T> *ptr, *prev = NULL, *last = NULL;
10809 int i;
10810 T *pixel;
10811
10812 for (ptr = m_pFirst, i = 0; ptr; ptr = ptr->pNext, i++) {
10813 if (!memcmp(SrcPixel, ptr->pPixelData, m_nSrcSize)) {
10814 memcpy(DstPixel, &ptr->pPixelData[m_nSrcSamples], m_nDstSize);
10815 if (ptr != m_pFirst) {
10816 last->pNext = ptr->pNext;
10817
10818 ptr->pNext = m_pFirst;
10819 m_pFirst = ptr;
10820 }
10821 return true;
10822 }
10823 prev = last;
10824 last = ptr;
10825 }
10826
10827 //If we get here SrcPixel is not in the cache
10828 if (i < m_nCacheSize) {
10829 pixel = &m_pixelData[i*m_nTotalSamples];
10830
10831 ptr = &m_cache[i];
10832 ptr->pPixelData = pixel;
10833
10834 if (m_pFirst) {
10835 ptr->pNext = m_pFirst;
10836 }
10837 m_pFirst = ptr;
10838 }
10839 else { //Reuse oldest value and put it at the front of the list
10840 prev->pNext = NULL;
10841 last->pNext = m_pFirst;
10842
10843 m_pFirst = last;
10844 pixel = last->pPixelData;
10845 }
10846 T *dest = &pixel[m_nSrcSamples];
10847
10848 memcpy(pixel, SrcPixel, m_nSrcSize);
10849
10850 return false;
10851}
10852
10853template<class T>
10854void CIccMruCache<T>::Update(T* DstPixel)
10855{
10856 memcpy(&m_pFirst->pPixelData[m_nSrcSamples], DstPixel, m_nDstSize);
10857}
10858
10859//Make sure typedef classes get built
10860template class CIccMruCache<icFloatNumber>;
10861template class CIccMruCache<icUInt8Number>;
10862template class CIccMruCache<icUInt16Number>;
10863
10864
10865CIccApplyMruCmm::CIccApplyMruCmm(CIccMruCmm *pCmm) : CIccApplyCmm(pCmm)
10866{
10867 m_pCachedCmm = NULL;
10868 m_pCache = NULL;
10869}
10870
10871/**
10872****************************************************************************
10873* Name: CIccApplyMruCmm::~CIccApplyMruCmm
10874*
10875* Purpose: destructor
10876*****************************************************************************
10877*/
10878CIccApplyMruCmm::~CIccApplyMruCmm()
10879{
10880 if (m_pCache)
10881 delete m_pCache;
10882
10883}
10884
10885/**
10886****************************************************************************
10887* Name: CIccApplyMruCmm::Init
10888*
10889* Purpose: Initialize the object and set up the cache
10890*
10891* Args:
10892* pCmm - pointer to cmm object that we are attaching to.
10893* nCacheSize - number of most recently used transformations to cache
10894*
10895* Return:
10896* true if successful
10897*****************************************************************************
10898*/
10899bool CIccApplyMruCmm::Init(CIccCmm *pCachedCmm, icUInt16Number nCacheSize)
10900{
10901 m_pCachedCmm = pCachedCmm;
10902
10903 m_pCache = CIccMruCacheFloat::NewMruCache(m_pCmm->GetSourceSamples(), m_pCmm->GetDestSamples(), nCacheSize);
10904
10905 if (!m_pCache)
10906 return false;
10907
10908 return true;
10909}
10910
10911/**
10912****************************************************************************
10913* Name: CIccMruCmm::Apply
10914*
10915* Purpose: Apply a transformation to a pixel.
10916*
10917* Args:
10918* DstPixel - Location to store pixel results
10919* SrcPixel - Location to get pixel values from
10920*
10921* Return:
10922* icCmmStatOk if successful
10923*****************************************************************************
10924*/
10925icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel)
10926{
10927#if defined(_DEBUG)
10928 if (!m_pCache)
10929 return icCmmStatInvalidLut;
10930#endif
10931
10932 if (!m_pCache->Apply(DstPixel, SrcPixel)) {
10933
10934 m_pCachedCmm->Apply(DstPixel, SrcPixel);
10935
10936 m_pCache->Update(DstPixel);
10937 }
10938
10939 return icCmmStatOk;
10940}
10941
10942/**
10943****************************************************************************
10944* Name: CIccMruCmm::Apply
10945*
10946* Purpose: Apply a transformation to a pixel.
10947*
10948* Args:
10949* DstPixel - Location to store pixel results
10950* SrcPixel - Location to get pixel values from
10951* nPixels - number of pixels to convert
10952*
10953* Return:
10954* icCmmStatOk if successful
10955*****************************************************************************
10956*/
10957icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels)
10958{
10960
10961#if defined(_DEBUG)
10962 if (!m_pCache)
10963 return icCmmStatInvalidLut;
10964#endif
10965
10966 for (k=0; k<nPixels;k++) {
10967 if (!m_pCache->Apply(DstPixel, SrcPixel)) {
10968 m_pCachedCmm->Apply(DstPixel, SrcPixel);
10969 m_pCache->Update(DstPixel);
10970 }
10971 SrcPixel += m_pCmm->GetSourceSamples();
10972 DstPixel += m_pCmm->GetDestSamples();
10973 }
10974
10975 return icCmmStatOk;
10976}
10977
10978
10979#ifdef USEREFICCMAXNAMESPACE
10980} //namespace refIccMAX
10981#endif
File: IccApplyBPC.h.
File: IccArrayBasic.h.
icArraySignature sig
static __inline bool IsSpaceSpectralPCS(icUInt32Number sig)
Definition IccCmm.cpp:96
#define ICCPCSSTEPDUMPFMT
Definition IccCmm.cpp:118
#define IsCompatSpace(x, y)
Definition IccCmm.cpp:115
static icFloatNumber RGBClip(icFloatNumber v, CIccCurve *pCurve)
Definition IccCmm.cpp:5196
icFloatNumber icD50XYZ[3]
Definition IccUtil.cpp:782
static icFloatNumber XYZScale(icFloatNumber v)
Definition IccCmm.cpp:5185
#define IsSpaceColorimetricPCS(x)
Definition IccCmm.cpp:107
#define IsNChannelCompat(x, y)
Definition IccCmm.cpp:113
#define ICCDUMPPIXEL(n, pix)
Definition IccCmm.cpp:3387
static icFloatNumber XYZDescale(icFloatNumber v)
Definition IccCmm.cpp:5191
#define IsSpacePCS(x)
Definition IccCmm.cpp:109
icXformLutType
CMM Xform LUT types.
Definition IccCmm.h:125
@ icXformLutNamedColor
Definition IccCmm.h:127
@ icXformLutBRDFDirect
Definition IccCmm.h:132
@ icXformLutBRDFMcsParam
Definition IccCmm.h:133
@ icXformLutGamut
Definition IccCmm.h:129
@ icXformLutColorimetric
Definition IccCmm.h:135
@ icXformLutMCS
Definition IccCmm.h:134
@ icXformLutColor
Definition IccCmm.h:126
@ icXformLutSpectral
Definition IccCmm.h:136
@ icXformLutPreview
Definition IccCmm.h:128
@ icXformLutBRDFParam
Definition IccCmm.h:131
#define icPerceptualRefWhiteX
Definition IccCmm.h:143
icXformInterp
CMM Interpolation types.
Definition IccCmm.h:113
@ icInterpLinear
Definition IccCmm.h:114
#define icPerceptualRefBlackZ
Definition IccCmm.h:141
#define icPerceptualRefBlackY
Definition IccCmm.h:140
#define icPerceptualRefWhiteZ
Definition IccCmm.h:145
icStatusCMM
CMM return status values.
Definition IccCmm.h:90
@ icCmmStatBadLutType
Definition IccCmm.h:103
@ icCmmStatInvalidProfile
Definition IccCmm.h:95
@ icCmmStatTooManySamples
Definition IccCmm.h:108
@ icCmmStatProfileMissingTag
Definition IccCmm.h:98
@ icCmmStatBadSpaceLink
Definition IccCmm.h:94
@ icCmmStatBadMCSLink
Definition IccCmm.h:109
@ icCmmStatIncorrectApply
Definition IccCmm.h:100
@ icCmmStatUnsupportedPcsLink
Definition IccCmm.h:105
@ icCmmStatBadColorEncoding
Definition IccCmm.h:101
@ icCmmStatCantOpenProfile
Definition IccCmm.h:93
@ icCmmStatBadConnection
Definition IccCmm.h:106
@ icCmmStatBadXform
Definition IccCmm.h:96
@ icCmmStatBad
Definition IccCmm.h:91
@ icCmmStatBadTintXform
Definition IccCmm.h:107
@ icCmmStatColorNotFound
Definition IccCmm.h:99
@ icCmmStatOk
Definition IccCmm.h:92
@ icCmmStatIdentityXform
Definition IccCmm.h:104
@ icCmmStatInvalidLut
Definition IccCmm.h:97
@ icCmmStatAllocErr
Definition IccCmm.h:102
icMCSConnectionType
Definition IccCmm.h:118
@ icNoMCS
Definition IccCmm.h:119
@ icToMCS
Definition IccCmm.h:120
@ icFromMCS
Definition IccCmm.h:121
#define icPerceptualRefWhiteY
Definition IccCmm.h:144
@ icXformTypeMpe
Definition IccCmm.h:154
@ icXformTypeMatrixTRC
Definition IccCmm.h:149
@ icXformTypeNDLut
Definition IccCmm.h:152
@ icXformTypeMonochrome
Definition IccCmm.h:155
@ icXformType3DLut
Definition IccCmm.h:150
@ icXformType4DLut
Definition IccCmm.h:151
@ icXformTypeNamedColor
Definition IccCmm.h:153
@ icXformTypePCS
Definition IccCmm.h:157
#define icPerceptualRefBlackX
Definition IccCmm.h:139
unsigned char icUChar
Definition IccDefs.h:110
float icFloatNumber
All floating point operations/variables in IccProfLib use the icFloatNumber data type.
Definition IccDefs.h:100
icUInt16Number icU1Fixed15Number
Definition IccDefs.h:82
#define icSigDevXYZData
Definition IccDefs.h:92
char icChar
Definition IccDefs.h:109
#define icSigDevLabData
Additional convenience color space signatures to distinguish between device encoding and PCS encoding...
Definition IccDefs.h:91
icStatusEncConvert icConvertEncodingProfile(CIccProfilePtr &newIcc, CIccProfile *pEncodeIcc)
File: IccEncode.h.
@ icEncConvertOk
Definition IccEncoding.h:75
File: IccIO.h.
File: IccCmm.h.
#define icNearRange
File: IccMpeBasic.h.
#define stricmp
CIccProfile * OpenIccProfile(const icChar *szFilename, bool bUseSubProfile)
Name: OpenIccProfile.
File: IccSparseMatrix.h.
File: IccStructBasic.h.
File: IccTag.h.
CIccCurve * LPIccCurve
Definition IccTagLut.h:112
@ icElemInterpLinear
Definition IccTagMPE.h:94
icU1Fixed15Number icDtoUSF(icFloatNumber num)
Definition IccUtil.cpp:587
icFloatNumber icU8toAB(icUInt8Number num)
Definition IccUtil.cpp:777
icFloatNumber icU16toF(icUInt16Number num)
Definition IccUtil.cpp:759
icUInt8Number icABtoU8(icFloatNumber num)
Definition IccUtil.cpp:766
void icXyzToPcs(icFloatNumber *XYZ)
Definition IccUtil.cpp:941
void icXyzFromPcs(icFloatNumber *XYZ)
Floating point encoding of XYZ in PCS is in range 0.0 to 1.0 (Note: X=1.0 is encoded as about 0....
Definition IccUtil.cpp:934
bool icSameSpectralRange(const icSpectralRange &rng1, const icSpectralRange &rng2)
Definition IccUtil.cpp:1399
bool icMatrixInvert3x3(icFloatNumber *M)
Name: icMatrixInvert3x3.
Definition IccUtil.cpp:391
icUInt32Number icGetSpaceSamples(icColorSpaceSignature sig)
Definition IccUtil.cpp:1303
icFloatNumber icFtoD(icS15Fixed16Number num)
Definition IccUtil.cpp:559
icFloatNumber icU8toF(icUInt8Number num)
Definition IccUtil.cpp:738
icUInt32Number icGetSpectralSpaceSamples(const icHeader *pHdr)
Definition IccUtil.cpp:1367
void icLabFromPcs(icFloatNumber *Lab)
Floating point encoding of Lab in PCS is in range 0.0 to 1.0.
Definition IccUtil.cpp:919
icUInt8Number icFtoU8(icFloatNumber num)
Definition IccUtil.cpp:724
void icLabToPcs(icFloatNumber *Lab)
Definition IccUtil.cpp:927
void icLabtoXYZ(icFloatNumber *XYZ, const icFloatNumber *Lab, const icFloatNumber *WhiteXYZ)
Definition IccUtil.cpp:830
icFloat16Number icFtoF16(icFloat32Number num)
Definition IccUtil.cpp:673
bool icIsSpaceCLR(icColorSpaceSignature sig)
Definition IccUtil.cpp:262
icS15Fixed16Number icDtoF(icFloatNumber num)
Definition IccUtil.cpp:545
icUInt16Number icFtoU16(icFloatNumber num)
Definition IccUtil.cpp:745
icFloatNumber icUSFtoD(icU1Fixed15Number num)
Definition IccUtil.cpp:601
void icXYZtoLab(icFloatNumber *Lab, const icFloatNumber *XYZ, const icFloatNumber *WhiteXYZ)
Definition IccUtil.cpp:846
icFloatNumber icF16toF(icFloat16Number num)
Definition IccUtil.cpp:629
#define icUtf8StrCmp(x, y)
Definition IccUtil.h:188
#define icNotZero(v)
Definition IccUtil.h:89
File: IccXformFactory.h.
unsigned int icUInt32Number
Class: CIccApplyCLUT.
Definition IccTagLut.h:302
Class: CIccArrayNamedColor.
CIccStructNamedColor * FindColor(const icChar *szColor) const
bool GetSpectralTint(icFloatNumber *dstColor, const CIccStructNamedColor *pColor, icFloatNumber tint=1.0f, icNamedColorlMemberSignature sig=icSigNmclSpectralDataMbr) const
CIccStructNamedColor * FindSpectralColor(const icFloatNumber *pSpec, icFloatNumber dMinRms=1000.0) const
void SetColorSpaces(icColorSpaceSignature csPcs, icColorSpaceSignature csDevice, icSpectralColorSignature csSpectralPCS=icSigNoSpectralData, const icSpectralRange *pSpectralRange=NULL, const icSpectralRange *pBiSPectralRange=NULL)
CIccStructNamedColor * FindDeviceColor(const icFloatNumber *pDevColor) const
CIccStructNamedColor * FindPcsColor(const icFloatNumber *pPCS, icFloatNumber dMinDE=1000.0) const
bool GetDeviceTint(icFloatNumber *dstColor, const CIccStructNamedColor *pColor, icFloatNumber tint=1.0f, icNamedColorlMemberSignature sig=icSigNmclDeviceDataMbr) const
bool GetPcsTint(icFloatNumber *dstColor, const CIccStructNamedColor *pColor, icFloatNumber tint=1.0f, icNamedColorlMemberSignature sig=icSigNmclPcsDataMbr) const
Class: CIccCLUT.
Definition IccTagLut.h:326
CIccApplyCLUT * GetNewApply()
Class: CIccCurve.
Definition IccTagLut.h:91
virtual icFloatNumber Apply(icFloatNumber v) const
Definition IccTagLut.h:101
virtual void Begin()
Definition IccTagLut.h:100
icFloatNumber Find(icFloatNumber v)
Definition IccTagLut.h:103
Class: CIccMBB.
Definition IccTagLut.h:428
Type: Class.
Definition IccIO.h:217
bool Attach(icUInt8Number *pData, icUInt32Number nSize, bool bWrite=false)
Definition IccIO.cpp:686
Class: CIccMpeMatrix.
icFloatNumber * GetConstants() const
virtual bool Begin(icElemInterp nInterp, CIccTagMultiProcessElement *pMPE)
Name: CIccMpeMatrix::Begin.
icFloatNumber * GetMatrix() const
bool GetApplyConstants() const
Class: CIccMultiProcessElement.
Definition IccTagMPE.h:146
virtual icUInt16Number NumInputChannels() const
Definition IccTagMPE.h:159
virtual icUInt16Number NumOutputChannels() const
Definition IccTagMPE.h:160
virtual icElemTypeSignature GetType() const =0
static icUInt32Number MemSize(icUInt32Number nMaxEntries, icUInt16Number nRows, icUInt8Number nTypeSize)
Class: CIccStructBRDF.
Class: CIccStructNamedColor.
std::string getName() const
CIccTag * GetElem(icSignature sigElem) const
Class: CIccTagArray.
bool AreAllOfType(icTagTypeSignature sigTagType)
Name: CIccTagArray::AreAllOftype.
IIccArray * GetArrayHandler()
Name: CIccTagArray::GetArrayHandler.
CIccTag * GetIndex(icUInt32Number index) const
Name: CIccTagArray::GetIndex.
icUInt32Number GetSize() const
Returns the size of the data array.
virtual icArraySignature GetTagArrayType() const
Class: CIccTagCurve.
Definition IccTagLut.h:128
Class: CIccTag.
virtual icTagTypeSignature GetType() const
Function: GetType()
virtual bool IsSupported()
Function: IsSupported(size, pIO) - Check if tag fully supported for apply purposes.
virtual bool IsMBBType()
virtual bool IsNumArrayType() const
virtual icArraySignature GetTagArrayType() const
Class: CIccTagMultiProcessElement.
Definition IccTagMPE.h:358
icUInt16Number NumInputChannels() const
Definition IccTagMPE.h:393
icUInt16Number NumOutputChannels() const
Definition IccTagMPE.h:394
virtual CIccTag * NewCopy() const
Function: NewCopy(sDescription) Each derived tag will implement it's own NewCopy() function.
Definition IccTagMPE.h:363
virtual void Apply(CIccApplyTagMpe *pApply, icFloatNumber *pDestPixel, const icFloatNumber *pSrcPixel) const
Name: CIccTagMultiProcessElement::Apply.
icUInt32Number NumElements() const
Definition IccTagMPE.h:398
CIccMultiProcessElement * GetElement(int nIndex)
Name: CIccTagMultiProcessElement::GetElement.
Class: CIccTagNamedColor2.
icInt32Number FindDeviceColor(icFloatNumber *pDevColor) const
Name: CIccTagNamedColor2::FindDeviceColor.
bool GetColorName(std::string &sColorName, icInt32Number index) const
Name: CIccTagNamedColor2::GetColorName.
icInt32Number FindColor(const icChar *szColor) const
Name: CIccTagNamedColor2::FindColor.
icColorSpaceSignature GetPCS() const
icUInt32Number GetDeviceCoords() const
icColorSpaceSignature GetDeviceSpace() const
icInt32Number FindCachedPCSColor(icFloatNumber *pPCS, icFloatNumber dMinDE=1000.0) const
Name: CIccTagNamedColor2::FindPCSColor.
SIccNamedColorEntry * GetEntry(icUInt32Number index) const
Class: CIccTagNumArray.
virtual bool GetValues(icFloatNumber *DstVector, icUInt32Number nStart=0, icUInt32Number nVectorSize=1) const =0
Class: CIccTagSpectralViewingConditions.
const icFloatNumber * getObserver(icSpectralRange &observerRange) const
icFloatNumber getIlluminantCCT() const
icIlluminant getStdIllumiant() const
const icFloatNumber * getIlluminant(icSpectralRange &illumRange) const
icFloatNumber * applyRangeToObserver(const icSpectralRange &newRange) const
Class: CIccTagUtf8Text()
Class: CIccTagXYZ.
static CIccXform * CreateXform(icXformType xformType, CIccTag *pTag=NULL, CIccCreateXformHintManager *pHintManager=NULL)
Function: CreateXform(xformTypeSig) Create a xform of type xformTypeSig.
virtual CIccTagMultiProcessElement * getStandardToCustomPcc()=0
virtual const CIccTagSpectralViewingConditions * getPccViewingConditions()=0
virtual CIccTagMultiProcessElement * getCustomToStandardPcc()=0
virtual void getLumIlluminantXYZ(icFloatNumber *pXYZ)=0
virtual bool getMediaWhiteXYZ(icFloatNumber *pXYZ)=0
icFloatNumber getObserverWhiteScaleFactor(const icFloatNumber *pWhite, const icSpectralRange &whiteRange)
Definition IccPcc.cpp:198
virtual void getNormIlluminantXYZ(icFloatNumber *pXYZ)=0
bool isEquivalentPcc(IIccProfileConnectionConditions &IPCC)
Definition IccPcc.cpp:79
#define icSigLabPcsData
Allowable icColorSpaceSignature values for xform PCS purposes.
unsigned char icUInt8Number
Number definitions.
#define icUnknownIntent
Convenience Enum Definitions - Not defined in ICC specification.
#define icSigBRDFDirect
unsigned short icUInt16Number
#define icSigRadiantSpectralPcsData
long icInt32Number
#define icSigSparseMatrixSpectralPcsData
icProfileClassSignature
profileClass enumerations
@ icSigAbstractClass
@ icSigColorEncodingClass
@ icSigMaterialVisualizationClass
@ icSigInputClass
@ icSigMaterialLinkClass
@ icSigNamedColorClass
@ icSigMaterialIdentificationClass
@ icSigLinkClass
@ icIlluminantUnknown
#define icSigXYZPcsData
#define icGetColorSpaceType(sig)
#define icSparseMatrixFloatNum
Convenience Enum Definition - Not defined in ICC specification.
@ icSigMatrixElemType
icColorSpaceSignature
Color Space Signatures.
@ icSigLabData
@ icSigLuvData
@ icSigXYZData
@ icSigNamedData
@ icSigCmykData
@ icSigRgbData
@ icSigHlsData
@ icSig4colorData
@ icSigYCbCrData
@ icSigCmyData
@ icSigGrayData
@ icSig3colorData
@ icSigHsvData
@ icSigYxyData
icUInt32Number icSignature
@ icSigUtf8TextType
@ icSigTagArrayType
@ icSigMultiProcessElementType
@ icSigParametricCurveType
@ icSigXYZType
@ icSigCurveType
@ icSigNamedColor2Type
#define icSigUnknownData
#define icVersionNumberV5
icSpectralColorSignature
icSpectralColorSignature enumerations
@ icSigNamedColorArray
@ icSigUtf8TextTypeArray
#define icSigReflectanceSpectralPcsData
#define icSigBRDFParameters
@ icSigBToD0Tag
@ icSigGrayTRCTag
@ icSigBRDFMToB1Tag
@ icSigBRDFMToB3Tag
@ icSigBRDFDToB0Tag
@ icSigAToB3Tag
@ icSigBlueMatrixColumnTag
@ icSigMaterialDefaultValuesTag
@ icSigMToS3Tag
@ icSigBrdfSpectralParameter0Tag
@ icSigGreenTRCTag
@ icSigAToM0Tag
@ icSigMToB0Tag
@ icSigAToB0Tag
@ icSigMToB3Tag
@ icSigBToA1Tag
@ icSigDToB3Tag
@ icSigBRDFAToB0Tag
@ icSigDToB0Tag
@ icSigBToD3Tag
@ icSigBToA0Tag
@ icSigMToS0Tag
@ icSigRedTRCTag
@ icSigHToS1Tag
@ icSigBToD1Tag
@ icSigBlueTRCTag
@ icSigMToB1Tag
@ icSigHToS0Tag
@ icSigGreenMatrixColumnTag
@ icSigMediaWhitePointTag
@ icSigBRDFMToS3Tag
@ icSigAToB1Tag
@ icSigBToA3Tag
@ icSigBRDFMToS1Tag
@ icSigBRDFMToS0Tag
@ icSigPreview0Tag
@ icSigNamedColor2Tag
@ icSigRedMatrixColumnTag
@ icSigGamutTag
@ icSigMToA0Tag
@ icSigMToS1Tag
@ icSigDToB1Tag
@ icSigBrdfColorimetricParameter0Tag
@ icSigMaterialTypeArrayTag
@ icSigBRDFMToB0Tag
icRenderingIntent
Rendering Intents, used in the profile header.
@ icPerceptual
@ icRelativeColorimetric
@ icAbsoluteColorimetric
#define icMCSNeedsSubsetTrue
#define icSigBiDirReflectanceSpectralPcsData
@ icSigBrdfTransformMbr
#define icSigTransmissionSpectralPcsData
#define icSigGamutData
Convenience Enum Definitions - Not defined in ICC specification.
static icFloatNumber UnitClip(icFloatNumber v)
icFloatNumber deviceCoords[1]
icFloatNumber pcsCoords[3]
spectral range
icUInt16Number steps
icFloat16Number start
icFloat16Number end
icS15Fixed16Number Y
icS15Fixed16Number Z
icS15Fixed16Number X