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::Extra