1 /** @file
2     File:       IccTagLut.cpp
3 
4     Contains:   Implementation of the Lut Tag classes
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-2010 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 //
69 // -Moved LUT tags to separate file 4-30-2005
70 //
71 //////////////////////////////////////////////////////////////////////
72 
73 #if defined(WIN32) || defined(WIN64)
74   #pragma warning( disable: 4786) //disable warning in <list.h>
75   #include <windows.h>
76 #endif
77 #include <stdio.h>
78 #include <math.h>
79 #include <string.h>
80 #include <stdlib.h>
81 #include "IccTag.h"
82 #include "IccUtil.h"
83 #include "IccProfile.h"
84 
85 #ifdef USESAMPLEICCNAMESPACE
86 namespace sampleICC {
87 #endif
88 
89 /**
90 ****************************************************************************
91 * Name: CIccCurve::Find
92 *
93 * Purpose: Read in the tag contents into a data block
94 *
95 * Args:
96 *  v = index to be searched,
97 *  v0 = index less than/equal to v,
98 *  p0 = the value at index v0,
99 *  v1 = index greater than/equal to v,
100 *  p1 = value at index v1
101 *
102 * Return: The value at the requested index
103 *
104 *****************************************************************************
105 */
Find(icFloatNumber v,icFloatNumber p0,icFloatNumber v0,icFloatNumber p1,icFloatNumber v1)106 icFloatNumber CIccCurve::Find(icFloatNumber v,
107   icFloatNumber p0, icFloatNumber v0,
108   icFloatNumber p1, icFloatNumber v1)
109 {
110   if (v<=v0)
111     return p0;
112   if (v>=v1)
113     return p1;
114 
115   if (p1-p0 <= 0.00001) {
116     icFloatNumber d0 = fabs(v-v0);
117     icFloatNumber d1 = fabs(v1-v);
118 
119     if (d0<d1)
120       return p0;
121     return p1;
122   }
123 
124   icFloatNumber np = (icFloatNumber)((p0 + p1)/2.0);
125   icFloatNumber nv = Apply(np);
126 
127   if (v<=nv) {
128     return Find(v, p0, v0, np, nv);
129   }
130   return Find(v, np, nv, p1, v1);
131 }
132 
133 
134 /**
135 ****************************************************************************
136 * Name: CIccTagCurve::CIccTagCurve
137 *
138 * Purpose: Constructor
139 *
140 *****************************************************************************
141 */
CIccTagCurve(int nSize)142 CIccTagCurve::CIccTagCurve(int nSize/*=0*/)
143 {
144   m_nSize = nSize;
145   if (m_nSize <0)
146     m_nSize = 0;
147   if (m_nSize>0)
148     m_Curve = (icFloatNumber*)calloc(nSize, sizeof(icFloatNumber));
149   else
150     m_Curve = NULL;
151 }
152 
153 
154 /**
155 ****************************************************************************
156 * Name: CIccTagCurve::CIccTagCurve
157 *
158 * Purpose: Copy Constructor
159 *
160 * Args:
161 *  ITCurve = The CIccTagCurve object to be copied
162 *****************************************************************************
163 */
CIccTagCurve(const CIccTagCurve & ITCurve)164 CIccTagCurve::CIccTagCurve(const CIccTagCurve &ITCurve)
165 {
166   m_nSize = ITCurve.m_nSize;
167   m_nMaxIndex = ITCurve.m_nMaxIndex;
168 
169   m_Curve = (icFloatNumber*)calloc(m_nSize, sizeof(icFloatNumber));
170   memcpy(m_Curve, ITCurve.m_Curve, m_nSize*sizeof(icFloatNumber));
171 }
172 
173 
174 /**
175 ****************************************************************************
176 * Name: CIccTagCurve::operator=
177 *
178 * Purpose: Copy Operator
179 *
180 * Args:
181 *  CurveTag = The CIccTagCurve object to be copied
182 *****************************************************************************
183 */
operator =(const CIccTagCurve & CurveTag)184 CIccTagCurve &CIccTagCurve::operator=(const CIccTagCurve &CurveTag)
185 {
186   if (&CurveTag == this)
187     return *this;
188 
189   m_nSize = CurveTag.m_nSize;
190   m_nMaxIndex = CurveTag.m_nMaxIndex;
191 
192   if (m_Curve)
193     free(m_Curve);
194   m_Curve = (icFloatNumber*)calloc(m_nSize, sizeof(icFloatNumber));
195   memcpy(m_Curve, CurveTag.m_Curve, m_nSize*sizeof(icFloatNumber));
196 
197   return *this;
198 }
199 
200 
201 /**
202 ****************************************************************************
203 * Name: CIccTagCurve::~CIccTagCurve
204 *
205 * Purpose: Destructor
206 *
207 *****************************************************************************
208 */
~CIccTagCurve()209 CIccTagCurve::~CIccTagCurve()
210 {
211   if (m_Curve)
212     free(m_Curve);
213 }
214 
215 
216 /**
217 ****************************************************************************
218 * Name: CIccTagCurve::Read
219 *
220 * Purpose: Read in the tag contents into a data block
221 *
222 * Args:
223 *  size - # of bytes in tag,
224 *  pIO - IO object to read tag from
225 *
226 * Return:
227 *  true = successful, false = failure
228 *****************************************************************************
229 */
Read(icUInt32Number size,CIccIO * pIO)230 bool CIccTagCurve::Read(icUInt32Number size, CIccIO *pIO)
231 {
232   icTagTypeSignature sig;
233 
234   if (sizeof(icTagTypeSignature) +
235     sizeof(icUInt32Number) +
236     sizeof(icUInt32Number) > size)
237     return false;
238 
239   if (!pIO) {
240     return false;
241   }
242 
243   if (!pIO->Read32(&sig))
244     return false;
245 
246   if (!pIO->Read32(&m_nReserved))
247     return false;
248 
249   icUInt32Number nSize;
250 
251   if (!pIO->Read32(&nSize))
252     return false;
253 
254   SetSize(nSize, icInitNone);
255 
256   if (m_nSize) {
257     if (pIO->Read16Float(m_Curve, m_nSize)!=(icInt32Number)m_nSize)
258       return false;
259   }
260 
261   return true;
262 }
263 
264 
265 /**
266 ****************************************************************************
267 * Name: CIccTagCurve::Write
268 *
269 * Purpose: Write the tag to a file
270 *
271 * Args:
272 *  pIO - The IO object to write tag to.
273 *
274 * Return:
275 *  true = succesful, false = failure
276 *****************************************************************************
277 */
Write(CIccIO * pIO)278 bool CIccTagCurve::Write(CIccIO *pIO)
279 {
280   icTagTypeSignature sig = GetType();
281 
282   if (!pIO)
283     return false;
284 
285   if (!pIO->Write32(&sig))
286     return false;
287 
288   if (!pIO->Write32(&m_nReserved))
289     return false;
290 
291   if (!pIO->Write32(&m_nSize))
292     return false;
293 
294   if (m_nSize)
295     if (pIO->Write16Float(m_Curve, m_nSize)!=(icInt32Number)m_nSize)
296       return false;
297 
298   pIO->Align32();
299 
300   return true;
301 }
302 
303 
304 /**
305 ****************************************************************************
306 * Name: CIccTagCurve::Describe
307 *
308 * Purpose: Dump data associated with the tag to a string
309 *
310 * Args:
311 *  sDescription - string to concatenate tag dump to
312 *****************************************************************************
313 */
Describe(std::string & sDescription)314 void CIccTagCurve::Describe(std::string &sDescription)
315 {
316   icChar buf[128], *ptr;
317 
318   if (!m_nSize) {
319     sprintf(buf, "BEGIN_CURVE In_Out\r\n");
320     sDescription += buf;
321     sDescription += "Y = X\r\n";
322   }
323   else if (m_nSize==1) {
324     icFloatNumber dGamma = (icFloatNumber)(m_Curve[0] * 256.0);
325     sprintf(buf, "BEGIN_CURVE In_Out\r\n");
326     sDescription += buf;
327     sprintf(buf, "Y = X ^ %.4lf\r\n", dGamma);
328     sDescription += buf;
329   }
330   else {
331     int i;
332 
333     sprintf(buf, "BEGIN_LUT In_Out 1 1\r\n");
334     sDescription += buf;
335     sDescription += "IN OUT\r\n";
336 
337     for (i=0; i<(int)m_nSize; i++) {
338       ptr = buf;
339 
340       icColorValue(buf, (icFloatNumber)i/(m_nSize-1), icSigMCH1Data, 1);
341       ptr += strlen(buf);
342 
343       strcpy(ptr, " ");
344       ptr ++;
345 
346       icColorValue(ptr, m_Curve[i], icSigMCH1Data, 1);
347 
348       ptr += strlen(ptr);
349 
350       strcpy(ptr, "\r\n");
351 
352       sDescription += buf;
353     }
354   }
355   sDescription += "\r\n";
356 }
357 
358 
359 /**
360 ****************************************************************************
361 * Name: CIccTagCurve::DumpLut
362 *
363 * Purpose: Dump data associated with the tag to a string. Basically has
364 *  the same function as Describe()
365 *
366 * Args:
367 *  sDescription = string to concatenate tag dump to,
368 *  szName = name of the curve to be printed,
369 *  csSig = color space signature of the LUT data,
370 *  nIndex = the channel number of color space
371 *****************************************************************************
372 */
DumpLut(std::string & sDescription,const icChar * szName,icColorSpaceSignature csSig,int nIndex)373 void CIccTagCurve::DumpLut(std::string &sDescription, const icChar *szName,
374   icColorSpaceSignature csSig, int nIndex)
375 {
376   icChar buf[128], *ptr;
377 
378   if (!m_nSize) {
379     sprintf(buf, "BEGIN_CURVE %s\r\n", szName);
380     sDescription += buf;
381     sDescription += "Y = X\r\n";
382   }
383   else if (m_nSize==1) {
384     icFloatNumber dGamma = (icFloatNumber)(m_Curve[0] * 256.0);
385     sprintf(buf, "BEGIN_CURVE %s\r\n", szName);
386     sDescription += buf;
387     sprintf(buf, "Y = X ^ %.4lf\r\n", dGamma);
388     sDescription += buf;
389   }
390   else {
391     int i;
392 
393     sprintf(buf, "BEGIN_LUT %s 1 1\r\n", szName);
394     sDescription += buf;
395     sDescription += "IN OUT\r\n";
396 
397     sDescription.reserve(sDescription.size() + m_nSize * 20);
398 
399     for (i=0; i<(int)m_nSize; i++) {
400       ptr = buf;
401 
402       icColorValue(buf, (icFloatNumber)i/(m_nSize-1), csSig, nIndex);
403       ptr += strlen(buf);
404 
405       strcpy(ptr, " ");
406       ptr ++;
407 
408       icColorValue(ptr, m_Curve[i], csSig, nIndex);
409 
410       ptr += strlen(ptr);
411 
412       strcpy(ptr, "\r\n");
413 
414       sDescription += buf;
415     }
416   }
417   sDescription += "\r\n";
418 }
419 
420 
421 /**
422 ****************************************************************************
423 * Name: CIccTagCurve::SetSize
424 *
425 * Purpose: Sets the size of the curve array.
426 *
427 * Args:
428 *  nSize - number of entries in the curve,
429 *  nSizeOpt - flag to zero newly formed values
430 *****************************************************************************
431 */
SetSize(icUInt32Number nSize,icTagCurveSizeInit nSizeOpt)432 void CIccTagCurve::SetSize(icUInt32Number nSize, icTagCurveSizeInit nSizeOpt/*=icInitZero*/)
433 {
434   if (nSize==m_nSize)
435     return;
436 
437   if (!nSize && m_Curve) {
438     free(m_Curve);
439     m_Curve = NULL;
440   }
441   else {
442     if (!m_Curve)
443       m_Curve = (icFloatNumber*)malloc(nSize*sizeof(icFloatNumber));
444     else
445       m_Curve = (icFloatNumber*)realloc(m_Curve, nSize*sizeof(icFloatNumber));
446 
447     switch (nSizeOpt) {
448     case icInitNone:
449     default:
450       break;
451 
452     case icInitZero:
453       if (m_nSize < nSize) {
454         memset(&m_Curve[m_nSize], 0, (nSize-m_nSize)*sizeof(icFloatNumber));
455       }
456       break;
457 
458     case icInitIdentity:
459       if (nSize>1) {
460         icUInt32Number i;
461         icFloatNumber last = (icFloatNumber)(nSize-1);
462 
463         for (i=0; i<nSize; i++) {
464           m_Curve[i] = (icFloatNumber)i/last;
465         }
466       }
467       else if (nSize==1) {
468         //Encode a gamma 1.0 u8Fixed8Number converted to 16 bit as a 0.0 to 1.0 float
469         m_Curve[0] = (icFloatNumber)(0x0100) / (icFloatNumber)65535.0;
470       }
471       break;
472     }
473   }
474   m_nSize = nSize;
475   m_nMaxIndex = (icUInt16Number)(nSize - 1);
476 }
477 
478 /**
479 ****************************************************************************
480 * Name: sampleICC::CIccTagCurve::SetGamma
481 *
482 * Purpose: Set the curve with a single gamma value.
483 *
484 * Args:
485 *  gamma - gamma value to use
486 *****************************************************************************
487 */
SetGamma(icFloatNumber gamma)488 void CIccTagCurve::SetGamma(icFloatNumber gamma)
489 {
490   SetSize(1, icInitNone);
491 
492   icInt16Number whole = (icInt16Number)gamma;
493   icFloatNumber frac = gamma - (icFloatNumber)whole;
494 
495   m_Curve[0] = (icFloatNumber)((whole * 256) + (frac*256.0)) / (icFloatNumber)65535.0;
496 }
497 
498 /**
499 ****************************************************************************
500 *
501 *****************************************************************************
502 */
503 const icFloatNumber VERYSMALLNUM = (icFloatNumber)0.0000001;
IsUnity(const icFloatNumber & num)504 static bool IsUnity(const icFloatNumber& num)
505 {
506   return (num>(1.0-VERYSMALLNUM) && num<(1.0+VERYSMALLNUM));
507 }
508 
509 /**
510 ****************************************************************************
511 * Name: CIccTagCurve::IsIdentity
512 *
513 * Purpose: Checks if this is an identity curve.
514 *
515 * Return: true if the curve is an identity
516 *
517 *****************************************************************************
518 */
IsIdentity()519 bool CIccTagCurve::IsIdentity()
520 {
521   if (!m_nSize) {
522     return true;
523   }
524 
525   if (m_nSize==1) {
526     return  IsUnity(icFloatNumber(m_Curve[0]*65535.0/256.0));
527   }
528 
529   icUInt32Number i;
530   for (i=0; i<m_nSize; i++) {
531     if (fabs(m_Curve[i]-((icFloatNumber)i/(icFloatNumber)m_nMaxIndex))>VERYSMALLNUM) {
532       return false;
533     }
534   }
535 
536   return true;
537 }
538 
539 /**
540 ****************************************************************************
541 * Name: CIccTagCurve::Apply
542 *
543 * Purpose: Applies the curve to the value passed.
544 *
545 * Args:
546 *  v = value to be passed through the curve.
547 *
548 * Return: The value modified by the curve.
549 *
550 *****************************************************************************
551 */
Apply(icFloatNumber v)552 icFloatNumber CIccTagCurve::Apply(icFloatNumber v)
553 {
554   if(v<0.0) v = 0.0;
555   else if(v>1.0) v = 1.0;
556 
557   icUInt32Number nIndex = (icUInt32Number)(v * m_nMaxIndex);
558 
559   if (!m_nSize) {
560     return v;
561   }
562   if (m_nSize==1) {
563     //Convert 0.0 to 1.0 float to 16bit and then convert from u8Fixed8Number
564     icFloatNumber dGamma = (icFloatNumber)(m_Curve[0] * 65535.0 / 256.0);
565     return pow(v, dGamma);
566   }
567   if (nIndex == m_nMaxIndex) {
568     return m_Curve[nIndex];
569   }
570   else {
571     icFloatNumber nDif = v*m_nMaxIndex - nIndex;
572     icFloatNumber p0 = m_Curve[nIndex];
573 
574     icFloatNumber rv = p0 + (m_Curve[nIndex+1]-p0)*nDif;
575     if (rv>1.0)
576       rv=1.0;
577 
578     return rv;
579   }
580 }
581 
582 
583 /**
584 ******************************************************************************
585 * Name: CIccTagCurve::Validate
586 *
587 * Purpose: Check tag data validity.
588 *
589 * Args:
590 *  sig = signature of tag being validated,
591 *  sReport = String to add report information to
592 *
593 * Return:
594 *  icValidateStatusOK if valid, or other error status.
595 ******************************************************************************
596 */
Validate(icTagSignature sig,std::string & sReport,const CIccProfile * pProfile) const597 icValidateStatus CIccTagCurve::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const
598 {
599   icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile);
600 
601   CIccInfo Info;
602   std::string sSigName = Info.GetSigName(sig);
603 
604   if (sig==icSigBlueTRCTag || sig==icSigRedTRCTag || sig==icSigGreenTRCTag || sig==icSigGrayTRCTag) {
605     if (m_nSize>1) {
606       if (m_Curve) {
607         if (m_Curve[0]>0.0 || m_Curve[m_nSize-1]<1.0) {
608           sReport += icValidateWarningMsg;
609           sReport += sSigName;
610           sReport += " - Curve cannot be accurately inverted.\r\n";
611           rv = icMaxStatus(rv, icValidateWarning);
612         }
613       }
614     }
615   }
616 
617   return rv;
618 }
619 
620 
621 /**
622 ****************************************************************************
623 * Name: CIccTagParametricCurve::CIccTagParametricCurve
624 *
625 * Purpose: Constructor
626 *
627 *****************************************************************************
628 */
CIccTagParametricCurve()629 CIccTagParametricCurve::CIccTagParametricCurve()
630 {
631   m_nFunctionType = 0xffff;
632   m_nNumParam = 0;
633   m_dParam = NULL;
634   m_nReserved2 = 0;
635 }
636 
637 
638 /**
639 ****************************************************************************
640 * Name: CIccTagParametricCurve::CIccTagParametricCurve
641 *
642 * Purpose: Copy Constructor
643 *
644 * Args:
645 *  ITPC = The CIccTagParametricCurve object to be copied
646 *****************************************************************************
647 */
CIccTagParametricCurve(const CIccTagParametricCurve & ITPC)648 CIccTagParametricCurve::CIccTagParametricCurve(const CIccTagParametricCurve &ITPC)
649 {
650   m_nFunctionType = ITPC.m_nFunctionType;
651   m_nNumParam = ITPC.m_nNumParam;
652 
653   m_dParam = new icFloatNumber[m_nNumParam];
654   memcpy(m_dParam, ITPC.m_dParam, m_nNumParam*sizeof(icFloatNumber));
655 }
656 
657 
658 /**
659 ****************************************************************************
660 * Name: CIccTagParametricCurve::operator=
661 *
662 * Purpose: Copy Operator
663 *
664 * Args:
665 *  ParamCurveTag = The CIccTagParametricCurve object to be copied
666 *****************************************************************************
667 */
operator =(const CIccTagParametricCurve & ParamCurveTag)668 CIccTagParametricCurve &CIccTagParametricCurve::operator=(const CIccTagParametricCurve &ParamCurveTag)
669 {
670   if (&ParamCurveTag == this)
671     return *this;
672 
673   m_nFunctionType = ParamCurveTag.m_nFunctionType;
674   m_nNumParam = ParamCurveTag.m_nNumParam;
675 
676   if (m_dParam)
677     delete [] m_dParam;
678 	m_dParam = new icFloatNumber[m_nNumParam];
679 	memcpy(m_dParam, ParamCurveTag.m_dParam, m_nNumParam*sizeof(icFloatNumber));
680 
681   return *this;
682 }
683 
684 
685 /**
686 ****************************************************************************
687 * Name: CIccTagParametricCurve::~CIccTagParametricCurve
688 *
689 * Purpose: Destructor
690 *
691 *****************************************************************************
692 */
~CIccTagParametricCurve()693 CIccTagParametricCurve::~CIccTagParametricCurve()
694 {
695   if (m_dParam)
696     delete [] m_dParam;
697 }
698 
699 
700 /**
701 ****************************************************************************
702 * Name: CIccTagParametricCurve::Read
703 *
704 * Purpose: Read in the tag contents into a data block
705 *
706 * Args:
707 *  size - # of bytes in tag,
708 *  pIO - IO object to read tag from
709 *
710 * Return:
711 *  true = successful, false = failure
712 *****************************************************************************
713 */
Read(icUInt32Number size,CIccIO * pIO)714 bool CIccTagParametricCurve::Read(icUInt32Number size, CIccIO *pIO)
715 {
716   icTagTypeSignature sig;
717   icUInt16Number nFunctionType;
718 
719   icUInt32Number nHdrSize = sizeof(icTagTypeSignature) +
720     sizeof(icUInt32Number) +
721     2*sizeof(icUInt16Number);
722 
723   if ( nHdrSize > size)
724     return false;
725 
726   if (!pIO) {
727     return false;
728   }
729 
730   if (!pIO->Read32(&sig) ||
731     !pIO->Read32(&m_nReserved) ||
732     !pIO->Read16(&nFunctionType) ||
733     !pIO->Read16(&m_nReserved2))
734     return false;
735 
736   SetFunctionType(nFunctionType);
737 
738   if (!m_nNumParam) {
739     m_nNumParam = (icUInt16Number)((size-nHdrSize) / sizeof(icS15Fixed16Number));
740     m_dParam = new icFloatNumber[m_nNumParam];
741   }
742 
743   if (m_nNumParam) {
744     int i;
745     if (nHdrSize + m_nNumParam*sizeof(icS15Fixed16Number) > size)
746       return false;
747 
748     for (i=0; i<m_nNumParam; i++) {
749       icS15Fixed16Number num;
750       if (!pIO->Read32(&num, 1))
751         return false;
752       m_dParam[i]=icFtoD(num);
753     }
754   }
755 
756   return true;
757 }
758 
759 
760 /**
761 ****************************************************************************
762 * Name: CIccTagParametricCurve::Write
763 *
764 * Purpose: Write the tag to a file
765 *
766 * Args:
767 *  pIO - The IO object to write tag to.
768 *
769 * Return:
770 *  true = succesful, false = failure
771 *****************************************************************************
772 */
Write(CIccIO * pIO)773 bool CIccTagParametricCurve::Write(CIccIO *pIO)
774 {
775   icTagTypeSignature sig;
776 
777   if (!pIO) {
778     return false;
779   }
780 
781   sig = GetType();
782 
783   if (!pIO->Write32(&sig) ||
784     !pIO->Write32(&m_nReserved) ||
785     !pIO->Write16(&m_nFunctionType) ||
786     !pIO->Write16(&m_nReserved2))
787     return false;
788 
789   if (m_nNumParam) {
790     int i;
791     for (i=0; i<m_nNumParam; i++) {
792       icS15Fixed16Number num = icDtoF(m_dParam[i]);
793       if (!pIO->Write32(&num, 1))
794         return false;
795     }
796   }
797 
798   if (!pIO->Align32())
799     return false;
800 
801   return true;
802 }
803 
804 
805 /**
806 ****************************************************************************
807 * Name: CIccTagParametricCurve::Describe
808 *
809 * Purpose: Dump data associated with the tag to a string
810 *
811 * Args:
812 *  sDescription - string to concatenate tag dump to
813 *****************************************************************************
814 */
Describe(std::string & sDescription)815 void CIccTagParametricCurve::Describe(std::string &sDescription)
816 {
817   icChar buf[128];
818 
819   sprintf(buf, "FunctionType: %04Xh\r\n", m_nFunctionType);
820   sDescription += buf;
821 
822   switch(m_nFunctionType) {
823 case 0x0000:
824   sprintf(buf, "Y = X ^ %.4lf\r\n", m_dParam[0]);
825   sDescription += buf;
826   return;
827 
828 case 0x0001:
829   sprintf(buf, "Y = 0 when (X < %.4lf / %.4lf)\r\n",
830     -m_dParam[2], m_dParam[1]);
831   sDescription += buf;
832 
833   sprintf(buf, "Y = (%.4lf * X + %.4lf) ^ %.4lf   when (X >= %.4lf / %.4lf)\r\n",
834     m_dParam[1], m_dParam[2], m_dParam[0],
835     m_dParam[2], m_dParam[1]);
836   sDescription += buf;
837   return;
838 
839 case 0x0002:
840   sprintf(buf, "Y = %.4lf   when (X < %.4lf / %.4lf)\r\n", m_dParam[3],
841     -m_dParam[2], m_dParam[1]);
842   sDescription += buf;
843 
844   sprintf(buf, "Y = (%.4lf * X + %.4lf) ^ %.4lf + %.4lf   when (X >= %.4lf / %.4lf)\r\n",
845     m_dParam[1], m_dParam[2], m_dParam[0],
846     m_dParam[3],
847     -m_dParam[2], m_dParam[1]);
848   sDescription += buf;
849   return;
850 
851 case 0x0003:
852   sprintf(buf, "Y = %lf * X   when (X < %.4lf)\r\n",
853     m_dParam[3], m_dParam[4]);
854   sDescription += buf;
855 
856   sprintf(buf, "Y = (%.4lf * X + %.4lf) ^ %.4lf   when (X >= %.4lf)\r\n",
857     m_dParam[1], m_dParam[2], m_dParam[0],
858     m_dParam[4]);
859   sDescription += buf;
860   return;
861 
862 case 0x0004:
863   sprintf(buf, "Y = %lf * X + %.4lf  when (X < %.4lf)\r\n",
864     m_dParam[3], m_dParam[6], m_dParam[4]);
865   sDescription += buf;
866 
867   sprintf(buf, "Y = (%.4lf * X + %.4lf) ^ %.4lf + %.4lf  when (X >= %.4lf)\r\n",
868     m_dParam[1], m_dParam[2], m_dParam[0],
869     m_dParam[5], m_dParam[4]);
870   sDescription += buf;
871   return;
872 
873 default:
874   int i;
875   sprintf(buf, "Unknown Function with %d parameters:\r\n", m_nNumParam);
876   sDescription += buf;
877 
878   for (i=0; i<m_nNumParam; i++) {
879     sprintf(buf, "Param[%d] = %.4lf\r\n", i, m_dParam[i]);
880     sDescription += buf;
881   }
882   }
883 }
884 
885 /**
886 ****************************************************************************
887 * Name: CIccTagParametricCurve::DumpLut
888 *
889 * Purpose: Dump data associated with the tag to a string. Basically has
890 *  the same function as Describe()
891 *
892 * Args:
893 *  sDescription = string to concatenate tag dump to,
894 *  szName = name of the curve to be printed,
895 *  csSig = color space signature of the curve data,
896 *  nIndex = the channel number of color space
897 *****************************************************************************
898 */
DumpLut(std::string & sDescription,const icChar * szName,icColorSpaceSignature csSig,int nIndex)899 void CIccTagParametricCurve::DumpLut(std::string &sDescription, const icChar *szName,
900   icColorSpaceSignature csSig, int nIndex)
901 {
902   icChar buf[128];
903 
904   sprintf(buf, "BEGIN_CURVE %s\r\n", szName);
905   sDescription += buf;
906   Describe(sDescription);
907   sDescription += "\r\n";
908 }
909 
910 
911 /**
912 ****************************************************************************
913 * Name: CIccTagParametricCurve::SetFunctionType
914 *
915 * Purpose: Sets the type of the function the Parametric curve represents
916 *
917 * Args:
918 *  nFunctionType = the type of the function encoded as 0-4
919 *
920 * Return:
921 *  always true!!
922 *****************************************************************************
923 */
SetFunctionType(icUInt16Number nFunctionType)924 bool CIccTagParametricCurve::SetFunctionType(icUInt16Number nFunctionType)
925 {
926   icUInt16Number nNumParam;
927 
928   switch(nFunctionType) {
929     case 0x0000:
930       nNumParam = 1;
931       break;
932 
933     case 0x0001:
934       nNumParam = 3;
935       break;
936 
937     case 0x0002:
938       nNumParam = 4;
939       break;
940 
941     case 0x0003:
942       nNumParam = 5;
943       break;
944 
945     case 0x0004:
946       nNumParam = 7;
947       break;
948 
949     default:
950       nNumParam = 0;
951   }
952 
953   if (m_dParam)
954     delete m_dParam;
955   m_nNumParam = nNumParam;
956   m_nFunctionType = nFunctionType;
957 
958   if (m_nNumParam)
959     m_dParam = new icFloatNumber[m_nNumParam];
960   else
961     m_dParam = NULL;
962 
963   return true;
964 }
965 
966 
967 /**
968 ****************************************************************************
969 * Name: CIccTagParametricCurve::IsIdentity
970 *
971 * Purpose: Checks if this is an identity curve.
972 *
973 * Return: true if the curve is an identity
974 *
975 *****************************************************************************
976 */
IsIdentity()977 bool CIccTagParametricCurve::IsIdentity()
978 {
979   switch(m_nFunctionType) {
980     case 0x0000:
981       return IsUnity(m_dParam[0]);
982 
983     case 0x0001:
984     case 0x0002:
985     case 0x0003:
986     case 0x0004:
987       return false;
988 
989     default:
990       return true;
991   }
992 }
993 
994 /**
995 ****************************************************************************
996 * Name: CIccTagParametricCurve::DoApply
997 *
998 * Purpose: Applies the curve to the value passed.
999 *
1000 * Args:
1001 *  x = value to be passed through the curve.
1002 *
1003 * Return: The value modified by the curve.
1004 *
1005 *****************************************************************************
1006 */
DoApply(icFloatNumber X) const1007 icFloatNumber CIccTagParametricCurve::DoApply(icFloatNumber X) const
1008 {
1009   double a, b;
1010 
1011   switch(m_nFunctionType) {
1012     case 0x0000:
1013       return pow(X, m_dParam[0]);
1014 
1015     case 0x0001:
1016       a=m_dParam[1];
1017       b=m_dParam[2];
1018 
1019       if (X >= -b/a) {
1020         return (icFloatNumber)pow((double)a*X + b, (double)m_dParam[0]);
1021       }
1022       else {
1023         return 0;
1024       }
1025 
1026     case 0x0002:
1027       a=m_dParam[1];
1028       b=m_dParam[2];
1029 
1030       if (X >= -b/a) {
1031         return (icFloatNumber)pow((double)a*X + b, (double)m_dParam[0]) + m_dParam[3];
1032       }
1033       else {
1034         return m_dParam[3];
1035       }
1036 
1037     case 0x0003:
1038       if (X >= m_dParam[4]) {
1039         return (icFloatNumber)pow((double)m_dParam[1]*X + m_dParam[2], (double)m_dParam[0]);
1040       }
1041       else {
1042         return m_dParam[3]*X;
1043       }
1044 
1045     case 0x0004:
1046       if (X >= m_dParam[4]) {
1047         return (icFloatNumber)pow((double)m_dParam[1]*X + m_dParam[2], (double)m_dParam[0]) + m_dParam[5];
1048       }
1049       else {
1050         return m_dParam[3]*X + m_dParam[6];
1051       }
1052 
1053     default:
1054       return X;
1055   }
1056 }
1057 
1058 
1059 /**
1060 ******************************************************************************
1061 * Name: CIccTagParametricCurve::Validate
1062 *
1063 * Purpose: Check tag data validity.
1064 *
1065 * Args:
1066 *  sig = signature of tag being validated,
1067 *  sReport = String to add report information to
1068 *
1069 * Return:
1070 *  icValidateStatusOK if valid, or other error status.
1071 ******************************************************************************
1072 */
Validate(icTagSignature sig,std::string & sReport,const CIccProfile * pProfile) const1073 icValidateStatus CIccTagParametricCurve::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const
1074 {
1075   icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile);
1076 
1077   CIccInfo Info;
1078   std::string sSigName = Info.GetSigName(sig);
1079 
1080   if (m_nReserved2!=0) {
1081     sReport += icValidateNonCompliantMsg;
1082     sReport += sSigName;
1083     sReport += " - Reserved Value must be zero.\r\n";
1084 
1085     rv = icMaxStatus(rv, icValidateNonCompliant);
1086   }
1087 
1088   switch(m_nFunctionType) {
1089 case 0x0000:
1090   if (m_nNumParam!=1) {
1091     sReport += icValidateCriticalErrorMsg;
1092     sReport += sSigName;
1093     sReport += " - Number of parameters inconsistent with function type.\r\n";
1094     rv = icMaxStatus(rv, icValidateCriticalError);
1095   }
1096   break;
1097 
1098 case 0x0001:
1099   if (m_nNumParam!=3) {
1100     sReport += icValidateCriticalErrorMsg;
1101     sReport += sSigName;
1102     sReport += " - Number of parameters inconsistent with function type.\r\n";
1103     rv = icMaxStatus(rv, icValidateCriticalError);
1104   }
1105   break;
1106 
1107 case 0x0002:
1108   if (m_nNumParam!=4) {
1109     sReport += icValidateCriticalErrorMsg;
1110     sReport += sSigName;
1111     sReport += " - Number of parameters inconsistent with function type.\r\n";
1112     rv = icMaxStatus(rv, icValidateCriticalError);
1113   }
1114   break;
1115 
1116 case 0x0003:
1117   if (m_nNumParam!=5) {
1118     sReport += icValidateCriticalErrorMsg;
1119     sReport += sSigName;
1120     sReport += " - Number of parameters inconsistent with function type.\r\n";
1121     rv = icMaxStatus(rv, icValidateCriticalError);
1122   }
1123   break;
1124 
1125 case 0x0004:
1126   if (m_nNumParam!=7) {
1127     sReport += icValidateCriticalErrorMsg;
1128     sReport += sSigName;
1129     sReport += " - Number of parameters inconsistent with function type.\r\n";
1130     rv = icMaxStatus(rv, icValidateCriticalError);
1131   }
1132   break;
1133 
1134 default:
1135   sReport += icValidateCriticalErrorMsg;
1136   sReport += sSigName;
1137   sReport += " - Unknown function type.\r\n";
1138   rv = icMaxStatus(rv, icValidateCriticalError);
1139   }
1140 
1141   if (sig==icSigBlueTRCTag || sig==icSigRedTRCTag || sig==icSigGreenTRCTag || sig==icSigGrayTRCTag) {
1142     icFloatNumber lval = DoApply(0.0);
1143     icFloatNumber uval = DoApply(1.0);
1144     if (lval>0.0 || uval<1.0) {
1145       sReport += icValidateWarningMsg;
1146       sReport += sSigName;
1147       sReport += " - Curve cannot be accurately inverted.\r\n";
1148       rv = icMaxStatus(rv, icValidateWarning);
1149     }
1150   }
1151 
1152   return rv;
1153 }
1154 
1155 /**
1156 ****************************************************************************
1157 * Name: CIccMatrix::CIccMatrix
1158 *
1159 * Purpose: Constructor
1160 *
1161 * Args:
1162 *  bUseConstants = true if the matrix contains additional row for constants
1163 *****************************************************************************
1164 */
CIccMatrix(bool bUseConstants)1165 CIccMatrix::CIccMatrix(bool bUseConstants/*=true*/)
1166 {
1167   m_bUseConstants = bUseConstants;
1168   m_e[0] = m_e[4] = m_e[8] = 1.0;
1169   m_e[1] = m_e[2] = m_e[3] =
1170     m_e[5] = m_e[6] = m_e[7] = 0.0;
1171 
1172   if (!m_bUseConstants) {
1173     m_e[9] = m_e[10] = m_e[11] = 0.0;
1174   }
1175 }
1176 
1177 
1178 /**
1179 ****************************************************************************
1180 * Name: CIccMatrix::CIccMatrix
1181 *
1182 * Purpose: Copy Constructor
1183 *
1184 * Args:
1185 *  MatrixClass = The CIccMatrix object to be copied
1186 *****************************************************************************
1187 */
CIccMatrix(const CIccMatrix & MatrixClass)1188 CIccMatrix::CIccMatrix(const CIccMatrix &MatrixClass)
1189 {
1190   m_bUseConstants = MatrixClass.m_bUseConstants;
1191   memcpy(m_e, MatrixClass.m_e, sizeof(m_e));
1192 }
1193 
1194 
1195 /**
1196 ****************************************************************************
1197 * Name: CIccMatrix::operator=
1198 *
1199 * Purpose: Copy Operator
1200 *
1201 * Args:
1202 *  MatrixClass = The CIccMatrix object to be copied
1203 *****************************************************************************
1204 */
operator =(const CIccMatrix & MatrixClass)1205 CIccMatrix &CIccMatrix::operator=(const CIccMatrix &MatrixClass)
1206 {
1207   if (&MatrixClass == this)
1208     return *this;
1209 
1210   m_bUseConstants = MatrixClass.m_bUseConstants;
1211   memcpy(m_e, MatrixClass.m_e, sizeof(m_e));
1212 
1213   return *this;
1214 }
1215 
1216 
1217 /**
1218 ****************************************************************************
1219 * Name: CIccTagParametricCurve::DumpLut
1220 *
1221 * Purpose: Dump the matrix data to a string.
1222 *
1223 * Args:
1224 *  sDescription = string to concatenate tag dump to,
1225 *  szName = name of the curve to be printed
1226 *****************************************************************************
1227 */
DumpLut(std::string & sDescription,const icChar * szName)1228 void CIccMatrix::DumpLut(std::string &sDescription, const icChar *szName)
1229 {
1230   icChar buf[128];
1231 
1232   sprintf(buf, "BEGIN_MATRIX %s\r\n", szName);
1233   sDescription += buf;
1234 
1235   if (!m_bUseConstants) {
1236     sprintf(buf, "%8.4lf %8.4lf %8.4lf\r\n",
1237       m_e[0], m_e[1], m_e[2]);
1238     sDescription += buf;
1239     sprintf(buf, "%8.4lf %8.4lf %8.4lf\r\n",
1240       m_e[3], m_e[4], m_e[5]);
1241     sDescription += buf;
1242     sprintf(buf, "%8.4lf %8.4lf %8.4lf\r\n",
1243       m_e[6], m_e[7], m_e[8]);
1244     sDescription += buf;
1245   }
1246   else {
1247     sprintf(buf, "%8.4lf %8.4lf %8.4lf  +  %8.4lf\r\n",
1248       m_e[0], m_e[1], m_e[2], m_e[9]);
1249     sDescription += buf;
1250     sprintf(buf, "%8.4lf %8.4lf %8.4lf  +  %8.4lf\r\n",
1251       m_e[3], m_e[4], m_e[5], m_e[10]);
1252     sDescription += buf;
1253     sprintf(buf, "%8.4lf %8.4lf %8.4lf  +  %8.4lf\r\n",
1254       m_e[6], m_e[7], m_e[8], m_e[11]);
1255     sDescription += buf;
1256   }
1257   sDescription += "\r\n";
1258 }
1259 
1260 /**
1261 ****************************************************************************
1262 * Name: CIccMatrix::IsIdentity
1263 *
1264 * Purpose: Checks if the matrix is identity
1265 *
1266 * Return:
1267 *  true if matrix is identity and uses no constants, else false
1268 *
1269 *****************************************************************************
1270 */
IsIdentity()1271 bool CIccMatrix::IsIdentity()
1272 {
1273   if (m_bUseConstants) {
1274     if (fabs(m_e[9])>0.0 || fabs(m_e[10])>0.0 || fabs(m_e[11])>0.0) {
1275       return false;
1276     }
1277   }
1278 
1279   if (!IsUnity(m_e[0]) || !IsUnity(m_e[4]) || !IsUnity(m_e[8])) {
1280     return false;
1281   }
1282 
1283   if (fabs(m_e[1])>0.0 || fabs(m_e[2])>0.0 || fabs(m_e[3])>0.0 ||
1284       fabs(m_e[5])>0.0 || fabs(m_e[6])>0.0 || fabs(m_e[7])>0.0)
1285   {
1286     return false;
1287   }
1288 
1289   return true;
1290 }
1291 
1292 /**
1293 ****************************************************************************
1294 * Name: CIccMatrix::Apply
1295 *
1296 * Purpose: Multiplies the pixel by the matrix.
1297 *
1298 * Args:
1299 *  Pixel = Pixel to be multiplied by the matrix
1300 *
1301 *****************************************************************************
1302 */
Apply(icFloatNumber * Pixel) const1303 void CIccMatrix::Apply(icFloatNumber *Pixel) const
1304 {
1305   icFloatNumber a=Pixel[0];
1306   icFloatNumber b=Pixel[1];
1307   icFloatNumber c=Pixel[2];
1308 
1309   icFloatNumber x = m_e[0]*a + m_e[1]*b + m_e[2]*c;
1310   icFloatNumber y = m_e[3]*a + m_e[4]*b + m_e[5]*c;
1311   icFloatNumber z = m_e[6]*a + m_e[7]*b + m_e[8]*c;
1312 
1313   if (m_bUseConstants) {
1314     x += m_e[9];
1315     y += m_e[10];
1316     z += m_e[11];
1317   }
1318 
1319   Pixel[0] = x;
1320   Pixel[1] = y;
1321   Pixel[2] = z;
1322 }
1323 
1324 
1325 /**
1326 ******************************************************************************
1327 * Name: CIccMatrix::Validate
1328 *
1329 * Purpose: Check tag data validity.
1330 *
1331 * Args:
1332 *  sig = signature of tag being validated,
1333 *  sReport = String to add report information to
1334 *
1335 * Return:
1336 *  icValidateStatusOK if valid, or other error status.
1337 ******************************************************************************
1338 */
Validate(icTagTypeSignature sig,std::string & sReport,const CIccProfile * pProfile) const1339 icValidateStatus CIccMatrix::Validate(icTagTypeSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const
1340 {
1341   icValidateStatus rv = icValidateOK;
1342 
1343   if (sig==icSigLut8Type || sig==icSigLut16Type) {
1344     if (pProfile->m_Header.pcs!=icSigXYZData) {
1345       CIccInfo Info;
1346       std::string sSigName = Info.GetSigName(sig);
1347       icFloatNumber sum=0.0;
1348       for (int i=0; i<9; i++) {
1349         sum += m_e[i];
1350       }
1351       if (m_e[0]!=1.0 || m_e[4]!=1.0 || m_e[9]!=1.0 || sum!=3.0) {
1352         sReport += icValidateNonCompliantMsg;
1353         sReport += sSigName;
1354         sReport += " - Matrix must be identity.\r\n";
1355         rv = icValidateNonCompliant;
1356       }
1357     }
1358   }
1359 
1360   return rv;
1361 }
1362 
1363 
ClutUnitClip(icFloatNumber v)1364 static icFloatNumber ClutUnitClip(icFloatNumber v)
1365 {
1366   if (v<0)
1367     return 0;
1368   else if (v>1.0)
1369     return 1.0;
1370 
1371   return v;
1372 }
1373 
1374 /**
1375  ****************************************************************************
1376  * Name: CIccCLUT::CIccCLUT
1377  *
1378  * Purpose: Constructor
1379  *
1380  * Args:
1381  *  nInputChannels = number of input channels,
1382  *  nOutputChannels = number of output channels
1383  *
1384  *****************************************************************************
1385  */
CIccCLUT(icUInt8Number nInputChannels,icUInt16Number nOutputChannels,icUInt8Number nPrecision)1386 CIccCLUT::CIccCLUT(icUInt8Number nInputChannels, icUInt16Number nOutputChannels, icUInt8Number nPrecision/*=2*/)
1387 {
1388   m_nInput = nInputChannels;
1389   m_nOutput = nOutputChannels;
1390   m_nPrecision = nPrecision;
1391   m_pData = NULL;
1392   m_nOffset = NULL;
1393   m_g = NULL;
1394   m_ig = NULL;
1395   m_s = NULL;
1396   m_df = NULL;
1397   memset(&m_nReserved2, 0 , sizeof(m_nReserved2));
1398 
1399   UnitClip = ClutUnitClip;
1400 }
1401 
1402 
1403 /**
1404  ****************************************************************************
1405  * Name: CIccCLUT::CIccCLUT
1406  *
1407  * Purpose: Copy Constructor
1408  *
1409  * Args:
1410  *  ICLUT = The CIccCLUT object to be copied
1411  *****************************************************************************
1412  */
CIccCLUT(const CIccCLUT & ICLUT)1413 CIccCLUT::CIccCLUT(const CIccCLUT &ICLUT)
1414 {
1415   m_pData = NULL;
1416   m_nOffset = NULL;
1417   m_g = NULL;
1418   m_ig = NULL;
1419   m_s = NULL;
1420   m_df = NULL;
1421   m_nInput = ICLUT.m_nInput;
1422   m_nOutput = ICLUT.m_nOutput;
1423   m_nPrecision = ICLUT.m_nPrecision;
1424   m_nNumPoints = ICLUT.m_nNumPoints;
1425 
1426   m_csInput = ICLUT.m_csInput;
1427   m_csOutput = ICLUT.m_csOutput;
1428 
1429   memcpy(m_GridPoints, ICLUT.m_GridPoints, sizeof(m_GridPoints));
1430   memcpy(m_DimSize, ICLUT.m_DimSize, sizeof(m_DimSize));
1431   memcpy(m_GridAdr, ICLUT.m_GridAdr, sizeof(m_GridAdr));
1432   memcpy(&m_nReserved2, &ICLUT.m_nReserved2, sizeof(m_nReserved2));
1433 
1434   int num = NumPoints()*m_nOutput;
1435   m_pData = new icFloatNumber[num];
1436   memcpy(m_pData, ICLUT.m_pData, num*sizeof(icFloatNumber));
1437 
1438   UnitClip = ICLUT.UnitClip;
1439 }
1440 
1441 
1442 /**
1443  ****************************************************************************
1444  * Name: CIccCLUT::operator=
1445  *
1446  * Purpose: Copy Operator
1447  *
1448  * Args:
1449  *  CLUTTag = The CIccCLUT object to be copied
1450  *****************************************************************************
1451  */
operator =(const CIccCLUT & CLUTTag)1452 CIccCLUT &CIccCLUT::operator=(const CIccCLUT &CLUTTag)
1453 {
1454   if (&CLUTTag == this)
1455     return *this;
1456 
1457   m_nInput = CLUTTag.m_nInput;
1458   m_nOutput = CLUTTag.m_nOutput;
1459   m_nPrecision = CLUTTag.m_nPrecision;
1460   m_nNumPoints = CLUTTag.m_nNumPoints;
1461 
1462   m_csInput = CLUTTag.m_csInput;
1463   m_csOutput = CLUTTag.m_csOutput;
1464 
1465   memcpy(m_GridPoints, CLUTTag.m_GridPoints, sizeof(m_GridPoints));
1466   memcpy(m_DimSize, CLUTTag.m_DimSize, sizeof(m_DimSize));
1467   memcpy(m_GridAdr, CLUTTag.m_GridAdr, sizeof(m_GridAdr));
1468   memcpy(m_nReserved2, &CLUTTag.m_nReserved2, sizeof(m_nReserved2));
1469 
1470   int num;
1471   if (m_pData)
1472     delete [] m_pData;
1473   num = NumPoints()*m_nOutput;
1474   m_pData = new icFloatNumber[num];
1475   memcpy(m_pData, CLUTTag.m_pData, num*sizeof(icFloatNumber));
1476 
1477   UnitClip = CLUTTag.UnitClip;
1478 
1479   return *this;
1480 }
1481 
1482 
1483 
1484 /**
1485  ****************************************************************************
1486  * Name: CIccCLUT::~CIccCLUT
1487  *
1488  * Purpose: Destructor
1489  *
1490  *****************************************************************************
1491  */
~CIccCLUT()1492 CIccCLUT::~CIccCLUT()
1493 {
1494   if (m_pData)
1495     delete [] m_pData;
1496 
1497   if (m_nOffset)
1498     delete [] m_nOffset;
1499 
1500   if (m_g)
1501     delete [] m_g;
1502 
1503   if (m_ig)
1504     delete [] m_ig;
1505 
1506   if (m_s)
1507     delete [] m_s;
1508 
1509   if (m_df)
1510     delete [] m_df;
1511 }
1512 
1513 /**
1514  ****************************************************************************
1515  * Name: CIccCLUT::Init
1516  *
1517  * Purpose: Initializes and sets the size of the CLUT
1518  *
1519  * Args:
1520  *  nGridPoints = number of grid points in the CLUT
1521  *****************************************************************************
1522  */
Init(icUInt8Number nGridPoints)1523 bool CIccCLUT::Init(icUInt8Number nGridPoints)
1524 {
1525   memset(&m_GridPoints, 0, sizeof(m_GridPoints));
1526   memset(m_GridPoints, nGridPoints, m_nInput);
1527   return Init(&m_GridPoints[0]);
1528 }
1529 
1530 /**
1531  ****************************************************************************
1532  * Name: CIccCLUT::Init
1533  *
1534  * Purpose: Initializes and sets the size of the CLUT
1535  *
1536  * Args:
1537  *  pGridPoints = number of grid points in the CLUT
1538  *****************************************************************************
1539  */
Init(icUInt8Number * pGridPoints)1540 bool CIccCLUT::Init(icUInt8Number *pGridPoints)
1541 {
1542   memset(m_nReserved2, 0, sizeof(m_nReserved2));
1543   if (pGridPoints!=&m_GridPoints[0]) {
1544     memcpy(m_GridPoints, pGridPoints, m_nInput);
1545     if (m_nInput<16)
1546       memset(m_GridPoints+m_nInput, 0, 16-m_nInput);
1547   }
1548 
1549   if (m_pData) {
1550     delete [] m_pData;
1551   }
1552 
1553   int i=m_nInput-1;
1554 
1555   m_DimSize[i] = m_nOutput;
1556   m_nNumPoints = m_GridPoints[i];
1557   for (i--; i>=0; i--) {
1558     m_DimSize[i] = m_DimSize[i+1] * m_GridPoints[i+1];
1559     m_nNumPoints *= m_GridPoints[i];
1560   }
1561 
1562   icUInt32Number nSize = NumPoints() * m_nOutput;
1563 
1564   if (!nSize)
1565     return false;
1566 
1567   m_pData = new icFloatNumber[nSize];
1568 
1569   return (m_pData != NULL);
1570 }
1571 
1572 
1573 /**
1574  ****************************************************************************
1575  * Name: CIccCLUT::ReadData
1576  *
1577  * Purpose: Reads the CLUT data points into the data buffer
1578  *
1579  * Args:
1580  *  size = # of bytes in the tag,
1581  *  pIO = IO object to read data from,
1582  *  nPrecision = data precision (8bit encoded as 1 or 16bit encoded as 2)
1583  *
1584  * Return:
1585  *  true = data read succesfully,
1586  *  false = read data failed
1587  *****************************************************************************
1588  */
ReadData(icUInt32Number size,CIccIO * pIO,icUInt8Number nPrecision)1589 bool CIccCLUT::ReadData(icUInt32Number size, CIccIO *pIO, icUInt8Number nPrecision)
1590 {
1591   icUInt32Number nNum=NumPoints() * m_nOutput;
1592 
1593   if (nNum * nPrecision > size)
1594     return false;
1595 
1596   if (nPrecision==1) {
1597     if (pIO->Read8Float(m_pData, nNum)!=(icInt32Number)nNum)
1598       return false;
1599   }
1600   else if (nPrecision==2) {
1601     if (pIO->Read16Float(m_pData, nNum)!=(icInt32Number)nNum)
1602       return false;
1603   }
1604   else
1605     return false;
1606 
1607   return true;
1608 }
1609 
1610 
1611 /**
1612  ****************************************************************************
1613  * Name: CIccCLUT::WriteData
1614  *
1615  * Purpose: Writes the CLUT data points from the data buffer
1616  *
1617  * Args:
1618  *  pIO = IO object to write data to,
1619  *  nPrecision = data precision (8bit encoded as 1 or 16bit encoded as 2)
1620  *
1621  * Return:
1622  *  true = data written succesfully,
1623  *  false = write operation failed
1624  *****************************************************************************
1625  */
WriteData(CIccIO * pIO,icUInt8Number nPrecision)1626 bool CIccCLUT::WriteData(CIccIO *pIO, icUInt8Number nPrecision)
1627 {
1628   icUInt32Number nNum=NumPoints() * m_nOutput;
1629 
1630   if (nPrecision==1) {
1631     if (pIO->Write8Float(m_pData, nNum)!=(icInt32Number)nNum)
1632       return false;
1633   }
1634   else if (nPrecision==2) {
1635     if (pIO->Write16Float(m_pData, nNum)!=(icInt32Number)nNum)
1636       return false;
1637   }
1638   else
1639     return false;
1640 
1641   return true;
1642 }
1643 
1644 
1645 /**
1646  ****************************************************************************
1647  * Name: CIccCLUT::Read
1648  *
1649  * Purpose: Read in the tag contents into a data block
1650  *
1651  * Args:
1652  *  size - # of bytes in tag,
1653  *  pIO - IO object to read tag from
1654  *
1655  * Return:
1656  *  true = successful, false = failure
1657  *****************************************************************************
1658  */
Read(icUInt32Number size,CIccIO * pIO)1659 bool CIccCLUT::Read(icUInt32Number size, CIccIO *pIO)
1660 {
1661   if (size < 20)
1662     return false;
1663 
1664   if (pIO->Read8(m_GridPoints, 16)!=16 ||
1665       !pIO->Read8(&m_nPrecision) ||
1666       pIO->Read8(&m_nReserved2[0], 3)!=3)
1667     return false;
1668 
1669   Init(m_GridPoints);
1670 
1671   return ReadData(size-20, pIO, m_nPrecision);
1672 }
1673 
1674 
1675 /**
1676  ****************************************************************************
1677  * Name: CIccCLUT::Write
1678  *
1679  * Purpose: Write the tag to a file
1680  *
1681  * Args:
1682  *  pIO - The IO object to write tag to.
1683  *
1684  * Return:
1685  *  true = succesful, false = failure
1686  *****************************************************************************
1687  */
Write(CIccIO * pIO)1688 bool CIccCLUT::Write(CIccIO *pIO)
1689 {
1690   if (pIO->Write8(m_GridPoints, 16)!=16 ||
1691       !pIO->Write8(&m_nPrecision) ||
1692       pIO->Write8(&m_nReserved2[0], 3)!=3)
1693     return false;
1694 
1695   return WriteData(pIO, m_nPrecision);
1696 }
1697 
1698 /**
1699  ****************************************************************************
1700  * Name: CIccCLUT::Iterate
1701  *
1702  * Purpose: Iterate through the CLUT to dump the data
1703  *
1704  * Args:
1705  *  sDescription = string to concatenate data dump to,
1706  *  nIndex = the channel number,
1707  *  nPos = the current position in the CLUT
1708  *
1709  *****************************************************************************
1710  */
Iterate(std::string & sDescription,icUInt8Number nIndex,icUInt32Number nPos,bool bUseLegacy)1711 void CIccCLUT::Iterate(std::string &sDescription, icUInt8Number nIndex, icUInt32Number nPos, bool bUseLegacy)
1712 {
1713   if (nIndex < m_nInput) {
1714     int i;
1715     for (i=0; i<m_GridPoints[nIndex]; i++) {
1716       m_GridAdr[nIndex] = i;
1717       Iterate(sDescription, nIndex+1, nPos, bUseLegacy);
1718       nPos += m_DimSize[nIndex];
1719     }
1720   }
1721   else {
1722     icChar *ptr = m_pOutText;
1723     icFloatNumber *pData = &m_pData[nPos];
1724     int i;
1725 
1726     for (i=0; i<m_nInput; i++) {
1727       icColorValue(m_pVal, (icFloatNumber)m_GridAdr[i] / (m_GridPoints[i]-1) , m_csInput, i, bUseLegacy);
1728 
1729       ptr += sprintf(ptr, " %s", m_pVal);
1730     }
1731     strcpy(ptr, "  ");
1732     ptr += 2;
1733 
1734     for (i=0; i<m_nOutput; i++) {
1735       icColorValue(m_pVal, pData[i], m_csOutput, i, bUseLegacy);
1736 
1737       ptr += sprintf(ptr, " %s", m_pVal);
1738     }
1739     strcpy(ptr, "\r\n");
1740     sDescription += (const icChar*)m_pOutText;
1741 
1742   }
1743 }
1744 
1745 
1746 /**
1747  ****************************************************************************
1748  * Name: CIccCLUT::Iterate
1749  *
1750  * Purpose: Iterate through the CLUT to get the data and execute PixelOp
1751  *
1752  * Args:
1753  *  pExec = pointer to the IIccCLUTExec object that implements the
1754  *          IIccCLUTExec::Apply() function
1755  *
1756  *****************************************************************************
1757  */
Iterate(IIccCLUTExec * pExec)1758 void CIccCLUT::Iterate(IIccCLUTExec* pExec)
1759 {
1760   memset(&m_fGridAdr[0], 0, sizeof(m_fGridAdr));
1761   if (m_nInput==3) {
1762     int i,j,k;
1763     icUInt32Number index=0;
1764     for (i=0; i<m_GridPoints[0]; i++) {
1765       for (j=0; j<m_GridPoints[1]; j++) {
1766         for (k=0; k<m_GridPoints[2]; k++) {
1767           m_fGridAdr[2] = (icFloatNumber)k/(icFloatNumber)(m_GridPoints[2]-1);
1768           m_fGridAdr[1] = (icFloatNumber)j/(icFloatNumber)(m_GridPoints[1]-1);
1769           m_fGridAdr[0] = (icFloatNumber)i/(icFloatNumber)(m_GridPoints[0]-1);
1770 
1771           index = (m_DimSize[0]*i + m_DimSize[1]*j + m_DimSize[2]*k);
1772           pExec->PixelOp(m_fGridAdr, &m_pData[index]);
1773 
1774         }
1775       }
1776     }
1777   }
1778   else if (m_nInput==4) {
1779     int i,j,k,l;
1780     icUInt32Number index=0;
1781     for (i=0; i<m_GridPoints[0]; i++) {
1782       for (j=0; j<m_GridPoints[1]; j++) {
1783         for (k=0; k<m_GridPoints[2]; k++) {
1784           for (l=0; l<m_GridPoints[3]; l++) {
1785             m_fGridAdr[3] = (icFloatNumber)l/(icFloatNumber)(m_GridPoints[3]-1);
1786             m_fGridAdr[2] = (icFloatNumber)k/(icFloatNumber)(m_GridPoints[2]-1);
1787             m_fGridAdr[1] = (icFloatNumber)j/(icFloatNumber)(m_GridPoints[1]-1);
1788             m_fGridAdr[0] = (icFloatNumber)i/(icFloatNumber)(m_GridPoints[0]-1);
1789 
1790             index = (m_DimSize[0]*i + m_DimSize[1]*j +
1791                      m_DimSize[2]*k + m_DimSize[3]*l);
1792             pExec->PixelOp(m_fGridAdr, &m_pData[index]);
1793 
1794           }
1795         }
1796       }
1797     }
1798   }
1799   else
1800     SubIterate(pExec, 0, 0);
1801 }
1802 
1803 
1804 /**
1805  ****************************************************************************
1806  * Name: CIccCLUT::SubIterate
1807  *
1808  * Purpose: Iterate through the CLUT to get the data
1809  *
1810  * Args:
1811  *  pExec = pointer to the IIccCLUTExec object that implements the
1812  *          IIccCLUTExec::Apply() function,
1813  *  nIndex = the channel number,
1814  *  nPos = the current position in the CLUT
1815  *
1816  *****************************************************************************
1817  */
SubIterate(IIccCLUTExec * pExec,icUInt8Number nIndex,icUInt32Number nPos)1818 void CIccCLUT::SubIterate(IIccCLUTExec* pExec, icUInt8Number nIndex, icUInt32Number nPos)
1819 {
1820   if (nIndex < m_nInput) {
1821     int i;
1822     for (i=0; i<m_GridPoints[nIndex]; i++) {
1823       m_fGridAdr[nIndex] = (icFloatNumber)i/(icFloatNumber)(m_GridPoints[nIndex]-1);
1824       SubIterate(pExec, nIndex+1, nPos);
1825       nPos += m_DimSize[nIndex];
1826     }
1827   }
1828   else
1829     pExec->PixelOp(m_fGridAdr, &m_pData[nPos]);
1830 }
1831 
1832 /**
1833  ****************************************************************************
1834  * Name: CIccCLUT::DumpLut
1835  *
1836  * Purpose: Dump data associated with the tag to a string.
1837  *
1838  * Args:
1839  *  sDescription = string to concatenate tag dump to,
1840  *  szName = name of the LUT to be printed,
1841  *  csInput = color space signature of the input data,
1842  *  csOutput = color space signature of the output data
1843  *****************************************************************************
1844  */
DumpLut(std::string & sDescription,const icChar * szName,icColorSpaceSignature csInput,icColorSpaceSignature csOutput,bool bUseLegacy)1845 void CIccCLUT::DumpLut(std::string  &sDescription, const icChar *szName,
1846                        icColorSpaceSignature csInput, icColorSpaceSignature csOutput,
1847                        bool bUseLegacy)
1848 {
1849   icChar szOutText[2048], szColor[40];
1850   int i, len;
1851 
1852   sprintf(szOutText, "BEGIN_LUT %s %d %d\r\n", szName, m_nInput, m_nOutput);
1853   sDescription += szOutText;
1854 
1855   for (i=0; i<m_nInput; i++) {
1856     icColorIndexName(szColor, csInput, i, m_nInput, "In");
1857     sprintf(szOutText, " %s=%d", szColor, m_GridPoints[i]);
1858     sDescription += szOutText;
1859   }
1860 
1861   sDescription += "  ";
1862 
1863   for (i=0; i<m_nOutput; i++) {
1864     icColorIndexName(szColor, csOutput, i, m_nOutput, "Out");
1865     sprintf(szOutText, " %s", szColor);
1866     sDescription += szOutText;
1867   }
1868 
1869   sDescription += "\r\n";
1870 
1871   len = 0;
1872   for (i=0; i<m_nInput; i++) {
1873     icColorValue(szColor, 1.0, csInput, i, bUseLegacy);
1874     len+= (int)strlen(szColor);
1875   }
1876   for (i=0; i<m_nOutput; i++) {
1877     icColorValue(szColor, 1.0, csOutput, i, bUseLegacy);
1878     len+= (int)strlen(szColor);
1879   }
1880   len += m_nInput + m_nOutput + 6;
1881 
1882   sDescription.reserve(sDescription.size() + NumPoints()*len);
1883 
1884   //Initialize iteration member variables
1885   m_csInput = csInput;
1886   m_csOutput = csOutput;
1887   m_pOutText = szOutText;
1888   m_pVal = szColor;
1889   memset(m_GridAdr, 0, 16);
1890 
1891   Iterate(sDescription, 0, 0, bUseLegacy);
1892 
1893   sDescription += "\r\n";
1894 }
1895 
1896 
1897 
1898 /**
1899  ****************************************************************************
1900  * Name: CIccCLUT::Begin
1901  *
1902  * Purpose: Initializes the CLUT. Must be called before Apply().
1903  *
1904  *****************************************************************************
1905  */
Begin()1906 void CIccCLUT::Begin()
1907 {
1908   int i;
1909   for (i=0; i<m_nInput; i++) {
1910     m_MaxGridPoint[i] = m_GridPoints[i] - 1;
1911   }
1912   m_nNodes = (1<<m_nInput);
1913 
1914   if (m_nOffset)
1915     delete [] m_nOffset;
1916 
1917   m_nOffset = new icUInt32Number[m_nNodes];
1918 
1919   if (m_nInput==3) {
1920     m_nOffset[0] = n000 = 0;
1921     m_nOffset[1] = n001 = m_DimSize[0];
1922     m_nOffset[2] = n010 = m_DimSize[1];
1923     m_nOffset[3] = n011 = n001 + n010;
1924     m_nOffset[4] = n100 = m_DimSize[2];
1925     m_nOffset[5] = n101 = n100 + n001;
1926     m_nOffset[6] = n110 = n100 + n010;
1927     m_nOffset[7] = n111 = n110 + n001;
1928   }
1929   else if (m_nInput == 4) {
1930     m_nOffset[ 0] = 0;
1931     m_nOffset[ 1] = n001 = m_DimSize[ 0];
1932     m_nOffset[ 2] = n010 = m_DimSize[ 1];
1933     m_nOffset[ 3] = m_nOffset[ 2] + m_nOffset[ 1];
1934     m_nOffset[ 4] = n100 = m_DimSize[ 2];
1935     m_nOffset[ 5] = m_nOffset[ 4] + m_nOffset[ 1];
1936     m_nOffset[ 6] = m_nOffset[ 4] + m_nOffset[ 2];
1937     m_nOffset[ 7] = m_nOffset[ 4] + m_nOffset[ 3];
1938     m_nOffset[ 8] = n1000 = m_DimSize[ 3];
1939     m_nOffset[ 9] = m_nOffset[ 8] + m_nOffset[ 1];
1940     m_nOffset[10] = m_nOffset[ 8] + m_nOffset[ 2];
1941     m_nOffset[11] = m_nOffset[ 8] + m_nOffset[ 3];
1942     m_nOffset[12] = m_nOffset[ 8] + m_nOffset[ 4];
1943     m_nOffset[13] = m_nOffset[ 8] + m_nOffset[ 5];
1944     m_nOffset[14] = m_nOffset[ 8] + m_nOffset[ 6];
1945     m_nOffset[15] = m_nOffset[ 8] + m_nOffset[ 7];
1946   }
1947   else if (m_nInput == 5) {
1948     m_nOffset[ 0] = 0;
1949     m_nOffset[ 1] = n001 = m_DimSize[ 0];
1950     m_nOffset[ 2] = n010 = m_DimSize[ 1];
1951     m_nOffset[ 3] = m_nOffset[ 2] + m_nOffset[ 1];
1952     m_nOffset[ 4] = n100 = m_DimSize[ 2];
1953     m_nOffset[ 5] = m_nOffset[ 4] + m_nOffset[ 1];
1954     m_nOffset[ 6] = m_nOffset[ 4] + m_nOffset[ 2];
1955     m_nOffset[ 7] = m_nOffset[ 4] + m_nOffset[ 3];
1956     m_nOffset[ 8] = n1000 = m_DimSize[ 3];
1957     m_nOffset[ 9] = m_nOffset[ 8] + m_nOffset[ 1];
1958     m_nOffset[10] = m_nOffset[ 8] + m_nOffset[ 2];
1959     m_nOffset[11] = m_nOffset[ 8] + m_nOffset[ 3];
1960     m_nOffset[12] = m_nOffset[ 8] + m_nOffset[ 4];
1961     m_nOffset[13] = m_nOffset[ 8] + m_nOffset[ 5];
1962     m_nOffset[14] = m_nOffset[ 8] + m_nOffset[ 6];
1963     m_nOffset[15] = m_nOffset[ 8] + m_nOffset[ 7];
1964     m_nOffset[16] = n10000 = m_DimSize[ 4];
1965     m_nOffset[17] = m_nOffset[16] + m_nOffset[ 1];
1966     m_nOffset[18] = m_nOffset[16] + m_nOffset[ 2];
1967     m_nOffset[19] = m_nOffset[16] + m_nOffset[ 3];
1968     m_nOffset[20] = m_nOffset[16] + m_nOffset[ 4];
1969     m_nOffset[21] = m_nOffset[16] + m_nOffset[ 5];
1970     m_nOffset[22] = m_nOffset[16] + m_nOffset[ 6];
1971     m_nOffset[23] = m_nOffset[16] + m_nOffset[ 7];
1972     m_nOffset[24] = m_nOffset[16] + m_nOffset[ 8];
1973     m_nOffset[25] = m_nOffset[16] + m_nOffset[ 9];
1974     m_nOffset[26] = m_nOffset[16] + m_nOffset[10];
1975     m_nOffset[27] = m_nOffset[16] + m_nOffset[11];
1976     m_nOffset[28] = m_nOffset[16] + m_nOffset[12];
1977     m_nOffset[29] = m_nOffset[16] + m_nOffset[13];
1978     m_nOffset[30] = m_nOffset[16] + m_nOffset[14];
1979     m_nOffset[31] = m_nOffset[16] + m_nOffset[15];
1980   }
1981   else if (m_nInput == 6) {
1982     m_nOffset[ 0] = 0;
1983     m_nOffset[ 1] = n001 = m_DimSize[ 0];
1984     m_nOffset[ 2] = n010 = m_DimSize[ 1];
1985     m_nOffset[ 3] = m_nOffset[ 2] + m_nOffset[ 1];
1986     m_nOffset[ 4] = n100 = m_DimSize[ 2];
1987     m_nOffset[ 5] = m_nOffset[ 4] + m_nOffset[ 1];
1988     m_nOffset[ 6] = m_nOffset[ 4] + m_nOffset[ 2];
1989     m_nOffset[ 7] = m_nOffset[ 4] + m_nOffset[ 3];
1990     m_nOffset[ 8] = n1000 = m_DimSize[ 3];
1991     m_nOffset[ 9] = m_nOffset[ 8] + m_nOffset[ 1];
1992     m_nOffset[10] = m_nOffset[ 8] + m_nOffset[ 2];
1993     m_nOffset[11] = m_nOffset[ 8] + m_nOffset[ 3];
1994     m_nOffset[12] = m_nOffset[ 8] + m_nOffset[ 4];
1995     m_nOffset[13] = m_nOffset[ 8] + m_nOffset[ 5];
1996     m_nOffset[14] = m_nOffset[ 8] + m_nOffset[ 6];
1997     m_nOffset[15] = m_nOffset[ 8] + m_nOffset[ 7];
1998     m_nOffset[16] = n10000 = m_DimSize[ 4];
1999     m_nOffset[17] = m_nOffset[16] + m_nOffset[ 1];
2000     m_nOffset[18] = m_nOffset[16] + m_nOffset[ 2];
2001     m_nOffset[19] = m_nOffset[16] + m_nOffset[ 3];
2002     m_nOffset[20] = m_nOffset[16] + m_nOffset[ 4];
2003     m_nOffset[21] = m_nOffset[16] + m_nOffset[ 5];
2004     m_nOffset[22] = m_nOffset[16] + m_nOffset[ 6];
2005     m_nOffset[23] = m_nOffset[16] + m_nOffset[ 7];
2006     m_nOffset[24] = m_nOffset[16] + m_nOffset[ 8];
2007     m_nOffset[25] = m_nOffset[16] + m_nOffset[ 9];
2008     m_nOffset[26] = m_nOffset[16] + m_nOffset[10];
2009     m_nOffset[27] = m_nOffset[16] + m_nOffset[11];
2010     m_nOffset[28] = m_nOffset[16] + m_nOffset[12];
2011     m_nOffset[29] = m_nOffset[16] + m_nOffset[13];
2012     m_nOffset[30] = m_nOffset[16] + m_nOffset[14];
2013     m_nOffset[31] = m_nOffset[16] + m_nOffset[15];
2014     m_nOffset[32] = n100000 = m_DimSize[5];
2015     m_nOffset[33] = m_nOffset[32] + m_nOffset[ 1];
2016     m_nOffset[34] = m_nOffset[32] + m_nOffset[ 2];
2017     m_nOffset[35] = m_nOffset[32] + m_nOffset[ 3];
2018     m_nOffset[36] = m_nOffset[32] + m_nOffset[ 4];
2019     m_nOffset[37] = m_nOffset[32] + m_nOffset[ 5];
2020     m_nOffset[38] = m_nOffset[32] + m_nOffset[ 6];
2021     m_nOffset[39] = m_nOffset[32] + m_nOffset[ 7];
2022     m_nOffset[40] = m_nOffset[32] + m_nOffset[ 8];
2023     m_nOffset[41] = m_nOffset[32] + m_nOffset[ 9];
2024     m_nOffset[42] = m_nOffset[32] + m_nOffset[10];
2025     m_nOffset[43] = m_nOffset[32] + m_nOffset[11];
2026     m_nOffset[44] = m_nOffset[32] + m_nOffset[12];
2027     m_nOffset[45] = m_nOffset[32] + m_nOffset[13];
2028     m_nOffset[46] = m_nOffset[32] + m_nOffset[14];
2029     m_nOffset[47] = m_nOffset[32] + m_nOffset[15];
2030     m_nOffset[48] = m_nOffset[32] + m_nOffset[16];
2031     m_nOffset[49] = m_nOffset[32] + m_nOffset[17];
2032     m_nOffset[50] = m_nOffset[32] + m_nOffset[18];
2033     m_nOffset[51] = m_nOffset[32] + m_nOffset[19];
2034     m_nOffset[52] = m_nOffset[32] + m_nOffset[20];
2035     m_nOffset[53] = m_nOffset[32] + m_nOffset[21];
2036     m_nOffset[54] = m_nOffset[32] + m_nOffset[22];
2037     m_nOffset[55] = m_nOffset[32] + m_nOffset[23];
2038     m_nOffset[56] = m_nOffset[32] + m_nOffset[24];
2039     m_nOffset[57] = m_nOffset[32] + m_nOffset[25];
2040     m_nOffset[58] = m_nOffset[32] + m_nOffset[26];
2041     m_nOffset[59] = m_nOffset[32] + m_nOffset[27];
2042     m_nOffset[60] = m_nOffset[32] + m_nOffset[28];
2043     m_nOffset[61] = m_nOffset[32] + m_nOffset[29];
2044     m_nOffset[62] = m_nOffset[32] + m_nOffset[30];
2045     m_nOffset[63] = m_nOffset[32] + m_nOffset[31];
2046   }
2047   else {
2048     //initialize ND interpolation variables
2049     m_g = new icFloatNumber[m_nInput];
2050     m_ig = new icUInt32Number[m_nInput];
2051     m_s = new icFloatNumber[m_nInput];
2052     m_df = new icFloatNumber[m_nNodes];
2053 
2054     m_nOffset[0] = 0;
2055     int count, nFlag;
2056     icUInt32Number nPower[2];
2057     nPower[0] = 0;
2058     nPower[1] = 1;
2059 
2060     for (count=0; count<m_nInput; count++) {
2061       m_nPower[count] = (1<<(m_nInput-1-count));
2062     }
2063 
2064     count = 0;
2065     nFlag = 1;
2066     for (icUInt32Number j=1; j<m_nNodes; j++) {
2067       if (j == nPower[1]) {
2068         m_nOffset[j] = m_DimSize[count];
2069         nPower[0] = (1<<count);
2070         count++;
2071         nPower[1] = (1<<count);
2072         nFlag = 1;
2073       }
2074       else {
2075         m_nOffset[j] = m_nOffset[nPower[0]] + m_nOffset[nFlag];
2076         nFlag++;
2077       }
2078     }
2079   }
2080 }
2081 
2082 
2083 
2084 /**
2085  ******************************************************************************
2086  * Name: CIccCLUT::Interp3dTetra
2087  *
2088  * Purpose: Tetrahedral interpolation function
2089  *
2090  * Args:
2091  *  Pixel = Pixel value to be found in the CLUT. Also used to store the result.
2092  *******************************************************************************
2093  */
Interp3dTetra(icFloatNumber * destPixel,const icFloatNumber * srcPixel) const2094 void CIccCLUT::Interp3dTetra(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const
2095 {
2096   icUInt8Number mx = m_MaxGridPoint[0];
2097   icUInt8Number my = m_MaxGridPoint[1];
2098   icUInt8Number mz = m_MaxGridPoint[2];
2099 
2100   icFloatNumber x = UnitClip(srcPixel[0]) * mx;
2101   icFloatNumber y = UnitClip(srcPixel[1]) * my;
2102   icFloatNumber z = UnitClip(srcPixel[2]) * mz;
2103 
2104   icUInt32Number ix = (icUInt32Number)x;
2105   icUInt32Number iy = (icUInt32Number)y;
2106   icUInt32Number iz = (icUInt32Number)z;
2107 
2108   icFloatNumber v = x - ix;
2109   icFloatNumber u = y - iy;
2110   icFloatNumber t = z - iz;
2111 
2112   if (ix==mx) {
2113     ix--;
2114     v = 1.0;
2115   }
2116   if (iy==my) {
2117     iy--;
2118     u = 1.0;
2119   }
2120   if (iz==mz) {
2121     iz--;
2122     t = 1.0;
2123   }
2124 
2125   int i;
2126   icFloatNumber *p = &m_pData[ix*n001 + iy*n010 + iz*n100];
2127 
2128   //Normalize grid units
2129 
2130   for (i=0; i<m_nOutput; i++, p++) {
2131     if (t<u) {
2132       if (t>v) {
2133         destPixel[i] = (p[n000] + t*(p[n110]-p[n010]) +
2134                                       u*(p[n010]-p[n000]) +
2135                                       v*(p[n111]-p[n110]));
2136       }
2137       else if (u<v) {
2138         destPixel[i] = (p[n000] + t*(p[n111]-p[n011]) +
2139                                       u*(p[n011]-p[n001]) +
2140                                       v*(p[n001]-p[n000]));
2141       }
2142       else {
2143         destPixel[i] = (p[n000] + t*(p[n111]-p[n011]) +
2144                                       u*(p[n010]-p[n000]) +
2145                                       v*(p[n011]-p[n010]));
2146       }
2147     }
2148     else {
2149       if (t<v) {
2150         destPixel[i] = (p[n000] + t*(p[n101]-p[n001]) +
2151                                       u*(p[n111]-p[n101]) +
2152                                       v*(p[n001]-p[n000]));
2153       }
2154       else if (u<v) {
2155         destPixel[i] = (p[n000] + t*(p[n100]-p[n000]) +
2156                                       u*(p[n111]-p[n101]) +
2157                                       v*(p[n101]-p[n100]));
2158       }
2159       else {
2160         destPixel[i] = (p[n000] + t*(p[n100]-p[n000]) +
2161                                       u*(p[n110]-p[n100]) +
2162                                       v*(p[n111]-p[n110]));
2163       }
2164     }
2165   }
2166 }
2167 
2168 
2169 
2170 /**
2171  ******************************************************************************
2172  * Name: CIccCLUT::Interp3d
2173  *
2174  * Purpose: Three dimensional interpolation function
2175  *
2176  * Args:
2177  *  Pixel = Pixel value to be found in the CLUT. Also used to store the result.
2178  *******************************************************************************
2179  */
Interp3d(icFloatNumber * destPixel,const icFloatNumber * srcPixel) const2180 void CIccCLUT::Interp3d(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const
2181 {
2182   icUInt8Number mx = m_MaxGridPoint[0];
2183   icUInt8Number my = m_MaxGridPoint[1];
2184   icUInt8Number mz = m_MaxGridPoint[2];
2185 
2186   icFloatNumber x = UnitClip(srcPixel[0]) * mx;
2187   icFloatNumber y = UnitClip(srcPixel[1]) * my;
2188   icFloatNumber z = UnitClip(srcPixel[2]) * mz;
2189 
2190   icUInt32Number ix = (icUInt32Number)x;
2191   icUInt32Number iy = (icUInt32Number)y;
2192   icUInt32Number iz = (icUInt32Number)z;
2193 
2194   icFloatNumber u = x - ix;
2195   icFloatNumber t = y - iy;
2196   icFloatNumber s = z - iz;
2197 
2198   if (ix==mx) {
2199     ix--;
2200     u = 1.0;
2201   }
2202   if (iy==my) {
2203     iy--;
2204     t = 1.0;
2205   }
2206   if (iz==mz) {
2207     iz--;
2208     s = 1.0;
2209   }
2210 
2211   icFloatNumber ns = (icFloatNumber)(1.0 - s);
2212   icFloatNumber nt = (icFloatNumber)(1.0 - t);
2213   icFloatNumber nu = (icFloatNumber)(1.0 - u);
2214 
2215   int i;
2216   icFloatNumber *p = &m_pData[ix*n001 + iy*n010 + iz*n100];
2217 
2218   //Normalize grid units
2219   icFloatNumber dF0, dF1, dF2, dF3, dF4, dF5, dF6, dF7, pv;
2220 
2221   dF0 = ns* nt* nu;
2222   dF1 = ns* nt*  u;
2223   dF2 = ns*  t* nu;
2224   dF3 = ns*  t*  u;
2225   dF4 =  s* nt* nu;
2226   dF5 =  s* nt*  u;
2227   dF6 =  s*  t* nu;
2228   dF7 =  s*  t*  u;
2229 
2230   for (i=0; i<m_nOutput; i++, p++) {
2231     pv = p[n000]*dF0 + p[n001]*dF1 + p[n010]*dF2 + p[n011]*dF3 +
2232          p[n100]*dF4 + p[n101]*dF5 + p[n110]*dF6 + p[n111]*dF7;
2233 
2234     destPixel[i] = pv;
2235   }
2236 }
2237 
2238 
2239 
2240 /**
2241  ******************************************************************************
2242  * Name: CIccCLUT::Interp4d
2243  *
2244  * Purpose: Four dimensional interpolation function
2245  *
2246  * Args:
2247  *  Pixel = Pixel value to be found in the CLUT. Also used to store the result.
2248  *******************************************************************************
2249  */
Interp4d(icFloatNumber * destPixel,const icFloatNumber * srcPixel) const2250 void CIccCLUT::Interp4d(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const
2251 {
2252   icUInt8Number mw = m_MaxGridPoint[0];
2253   icUInt8Number mx = m_MaxGridPoint[1];
2254   icUInt8Number my = m_MaxGridPoint[2];
2255   icUInt8Number mz = m_MaxGridPoint[3];
2256 
2257   icFloatNumber w = UnitClip(srcPixel[0]) * mw;
2258   icFloatNumber x = UnitClip(srcPixel[1]) * mx;
2259   icFloatNumber y = UnitClip(srcPixel[2]) * my;
2260   icFloatNumber z = UnitClip(srcPixel[3]) * mz;
2261 
2262   icUInt32Number iw = (icUInt32Number)w;
2263   icUInt32Number ix = (icUInt32Number)x;
2264   icUInt32Number iy = (icUInt32Number)y;
2265   icUInt32Number iz = (icUInt32Number)z;
2266 
2267   icFloatNumber v = w - iw;
2268   icFloatNumber u = x - ix;
2269   icFloatNumber t = y - iy;
2270   icFloatNumber s = z - iz;
2271 
2272   if (iw==mw) {
2273     iw--;
2274     v = 1.0;
2275   }
2276   if (ix==mx) {
2277     ix--;
2278     u = 1.0;
2279   }
2280   if (iy==my) {
2281     iy--;
2282     t = 1.0;
2283   }
2284   if (iz==mz) {
2285     iz--;
2286     s = 1.0;
2287   }
2288 
2289   icFloatNumber ns = (icFloatNumber)(1.0 - s);
2290   icFloatNumber nt = (icFloatNumber)(1.0 - t);
2291   icFloatNumber nu = (icFloatNumber)(1.0 - u);
2292   icFloatNumber nv = (icFloatNumber)(1.0 - v);
2293 
2294   int i, j;
2295   icFloatNumber *p = &m_pData[iw*n001 + ix*n010 + iy*n100 + iz*n1000];
2296 
2297   //Normalize grid units
2298   icFloatNumber dF[16], pv;
2299 
2300   dF[ 0] = ns* nt* nu* nv;
2301   dF[ 1] = ns* nt* nu*  v;
2302   dF[ 2] = ns* nt*  u* nv;
2303   dF[ 3] = ns* nt*  u*  v;
2304   dF[ 4] = ns*  t* nu* nv;
2305   dF[ 5] = ns*  t* nu*  v;
2306   dF[ 6] = ns*  t*  u* nv;
2307   dF[ 7] = ns*  t*  u*  v;
2308   dF[ 8] =  s* nt* nu* nv;
2309   dF[ 9] =  s* nt* nu*  v;
2310   dF[10] =  s* nt*  u* nv;
2311   dF[11] =  s* nt*  u*  v;
2312   dF[12] =  s*  t* nu* nv;
2313   dF[13] =  s*  t* nu*  v;
2314   dF[14] =  s*  t*  u* nv;
2315   dF[15] =  s*  t*  u*  v;
2316 
2317   for (i=0; i<m_nOutput; i++, p++) {
2318     for (pv=0, j=0; j<16; j++)
2319       pv += p[m_nOffset[j]] * dF[j];
2320 
2321     destPixel[i] = pv;
2322   }
2323 }
2324 
2325 
2326 
2327 /**
2328  ******************************************************************************
2329  * Name: CIccCLUT::Interp5d
2330  *
2331  * Purpose: Five dimensional interpolation function
2332  *
2333  * Args:
2334  *  Pixel = Pixel value to be found in the CLUT. Also used to store the result.
2335  *******************************************************************************
2336  */
Interp5d(icFloatNumber * destPixel,const icFloatNumber * srcPixel) const2337 void CIccCLUT::Interp5d(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const
2338 {
2339   icUInt8Number m0 = m_MaxGridPoint[0];
2340   icUInt8Number m1 = m_MaxGridPoint[1];
2341   icUInt8Number m2 = m_MaxGridPoint[2];
2342   icUInt8Number m3 = m_MaxGridPoint[3];
2343   icUInt8Number m4 = m_MaxGridPoint[4];
2344 
2345   icFloatNumber g0 = UnitClip(srcPixel[0]) * m0;
2346   icFloatNumber g1 = UnitClip(srcPixel[1]) * m1;
2347   icFloatNumber g2 = UnitClip(srcPixel[2]) * m2;
2348   icFloatNumber g3 = UnitClip(srcPixel[3]) * m3;
2349   icFloatNumber g4 = UnitClip(srcPixel[4]) * m4;
2350 
2351   icUInt32Number ig0 = (icUInt32Number)g0;
2352   icUInt32Number ig1 = (icUInt32Number)g1;
2353   icUInt32Number ig2 = (icUInt32Number)g2;
2354   icUInt32Number ig3 = (icUInt32Number)g3;
2355   icUInt32Number ig4 = (icUInt32Number)g4;
2356 
2357   icFloatNumber s4 = g0 - ig0;
2358   icFloatNumber s3 = g1 - ig1;
2359   icFloatNumber s2 = g2 - ig2;
2360   icFloatNumber s1 = g3 - ig3;
2361   icFloatNumber s0 = g4 - ig4;
2362 
2363   if (ig0==m0) {
2364     ig0--;
2365     s4 = 1.0;
2366   }
2367   if (ig1==m1) {
2368     ig1--;
2369     s3 = 1.0;
2370   }
2371   if (ig2==m2) {
2372     ig2--;
2373     s2 = 1.0;
2374   }
2375   if (ig3==m3) {
2376     ig3--;
2377     s1 = 1.0;
2378   }
2379   if (ig4==m4) {
2380     ig4--;
2381     s0 = 1.0;
2382   }
2383 
2384   icFloatNumber ns0 = (icFloatNumber)(1.0 - s0);
2385   icFloatNumber ns1 = (icFloatNumber)(1.0 - s1);
2386   icFloatNumber ns2 = (icFloatNumber)(1.0 - s2);
2387   icFloatNumber ns3 = (icFloatNumber)(1.0 - s3);
2388   icFloatNumber ns4 = (icFloatNumber)(1.0 - s4);
2389 
2390   int i, j;
2391   icFloatNumber *p = &m_pData[ig0*n001 + ig1*n010 + ig2*n100 + ig3*n1000 + ig4*n10000];
2392 
2393   //Normalize grid units
2394   icFloatNumber dF[32], pv;
2395 
2396   dF[ 0] = ns0 * ns1 * ns2 * ns3 * ns4;
2397   dF[ 1] = ns0 * ns1 * ns2 * ns3 *  s4;
2398   dF[ 2] = ns0 * ns1 * ns2 *  s3 * ns4;
2399   dF[ 3] = ns0 * ns1 * ns2 *  s3 *  s4;
2400   dF[ 4] = ns0 * ns1 *  s2 * ns3 * ns4;
2401   dF[ 5] = ns0 * ns1 *  s2 * ns3 *  s4;
2402   dF[ 6] = ns0 * ns1 *  s2 *  s3 * ns4;
2403   dF[ 7] = ns0 * ns1 *  s2 *  s3 *  s4;
2404   dF[ 8] = ns0 *  s1 * ns2 * ns3 * ns4;
2405   dF[ 9] = ns0 *  s1 * ns2 * ns3 *  s4;
2406   dF[10] = ns0 *  s1 * ns2 *  s3 * ns4;
2407   dF[11] = ns0 *  s1 * ns2 *  s3 *  s4;
2408   dF[12] = ns0 *  s1 *  s2 * ns3 * ns4;
2409   dF[13] = ns0 *  s1 *  s2 * ns3 *  s4;
2410   dF[14] = ns0 *  s1 *  s2 *  s3 * ns4;
2411   dF[15] = ns0 *  s1 *  s2 *  s3 *  s4;
2412   dF[16] =  s0 * ns1 * ns2 * ns3 * ns4;
2413   dF[17] =  s0 * ns1 * ns2 * ns3 *  s4;
2414   dF[18] =  s0 * ns1 * ns2 *  s3 * ns4;
2415   dF[19] =  s0 * ns1 * ns2 *  s3 *  s4;
2416   dF[20] =  s0 * ns1 *  s2 * ns3 * ns4;
2417   dF[21] =  s0 * ns1 *  s2 * ns3 *  s4;
2418   dF[22] =  s0 * ns1 *  s2 *  s3 * ns4;
2419   dF[23] =  s0 * ns1 *  s2 *  s3 *  s4;
2420   dF[24] =  s0 *  s1 * ns2 * ns3 * ns4;
2421   dF[25] =  s0 *  s1 * ns2 * ns3 *  s4;
2422   dF[26] =  s0 *  s1 * ns2 *  s3 * ns4;
2423   dF[27] =  s0 *  s1 * ns2 *  s3 *  s4;
2424   dF[28] =  s0 *  s1 *  s2 * ns3 * ns4;
2425   dF[29] =  s0 *  s1 *  s2 * ns3 *  s4;
2426   dF[30] =  s0 *  s1 *  s2 *  s3 * ns4;
2427   dF[31] =  s0 *  s1 *  s2 *  s3 *  s4;
2428 
2429   for (i=0; i<m_nOutput; i++, p++) {
2430     for (pv=0.0, j=0; j<32; j++)
2431       pv += p[m_nOffset[j]] * dF[j];
2432 
2433     destPixel[i] = pv;
2434   }
2435 }
2436 
2437 
2438 
2439 /**
2440  ******************************************************************************
2441  * Name: CIccCLUT::Interp6d
2442  *
2443  * Purpose: Six dimensional interpolation function
2444  *
2445  * Args:
2446  *  Pixel = Pixel value to be found in the CLUT. Also used to store the result.
2447  *******************************************************************************
2448  */
Interp6d(icFloatNumber * destPixel,const icFloatNumber * srcPixel) const2449 void CIccCLUT::Interp6d(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const
2450 {
2451   icUInt8Number m0 = m_MaxGridPoint[0];
2452   icUInt8Number m1 = m_MaxGridPoint[1];
2453   icUInt8Number m2 = m_MaxGridPoint[2];
2454   icUInt8Number m3 = m_MaxGridPoint[3];
2455   icUInt8Number m4 = m_MaxGridPoint[4];
2456   icUInt8Number m5 = m_MaxGridPoint[5];
2457 
2458   icFloatNumber g0 = UnitClip(srcPixel[0]) * m0;
2459   icFloatNumber g1 = UnitClip(srcPixel[1]) * m1;
2460   icFloatNumber g2 = UnitClip(srcPixel[2]) * m2;
2461   icFloatNumber g3 = UnitClip(srcPixel[3]) * m3;
2462   icFloatNumber g4 = UnitClip(srcPixel[4]) * m4;
2463   icFloatNumber g5 = UnitClip(srcPixel[5]) * m5;
2464 
2465   icUInt32Number ig0 = (icUInt32Number)g0;
2466   icUInt32Number ig1 = (icUInt32Number)g1;
2467   icUInt32Number ig2 = (icUInt32Number)g2;
2468   icUInt32Number ig3 = (icUInt32Number)g3;
2469   icUInt32Number ig4 = (icUInt32Number)g4;
2470   icUInt32Number ig5 = (icUInt32Number)g5;
2471 
2472   icFloatNumber s5 = g0 - ig0;
2473   icFloatNumber s4 = g1 - ig1;
2474   icFloatNumber s3 = g2 - ig2;
2475   icFloatNumber s2 = g3 - ig3;
2476   icFloatNumber s1 = g4 - ig4;
2477   icFloatNumber s0 = g5 - ig5;
2478 
2479   if (ig0==m0) {
2480     ig0--;
2481     s5 = 1.0;
2482   }
2483   if (ig1==m1) {
2484     ig1--;
2485     s4 = 1.0;
2486   }
2487   if (ig2==m2) {
2488     ig2--;
2489     s3 = 1.0;
2490   }
2491   if (ig3==m3) {
2492     ig3--;
2493     s2 = 1.0;
2494   }
2495   if (ig4==m4) {
2496     ig4--;
2497     s1 = 1.0;
2498   }
2499   if (ig5==m5) {
2500     ig5--;
2501     s0 = 1.0;
2502   }
2503 
2504   icFloatNumber ns0 = (icFloatNumber)(1.0 - s0);
2505   icFloatNumber ns1 = (icFloatNumber)(1.0 - s1);
2506   icFloatNumber ns2 = (icFloatNumber)(1.0 - s2);
2507   icFloatNumber ns3 = (icFloatNumber)(1.0 - s3);
2508   icFloatNumber ns4 = (icFloatNumber)(1.0 - s4);
2509   icFloatNumber ns5 = (icFloatNumber)(1.0 - s5);
2510 
2511   int i, j;
2512   icFloatNumber *p = &m_pData[ig0*n001 + ig1*n010 + ig2*n100 + ig3*n1000 + ig4*n10000 + ig5*n100000];
2513 
2514   //Normalize grid units
2515   icFloatNumber dF[64], pv;
2516 
2517   dF[ 0] = ns0 * ns1 * ns2 * ns3 * ns4 * ns5;
2518   dF[ 1] = ns0 * ns1 * ns2 * ns3 * ns4 *  s5;
2519   dF[ 2] = ns0 * ns1 * ns2 * ns3 *  s4 * ns5;
2520   dF[ 3] = ns0 * ns1 * ns2 * ns3 *  s4 *  s5;
2521   dF[ 4] = ns0 * ns1 * ns2 *  s3 * ns4 * ns5;
2522   dF[ 5] = ns0 * ns1 * ns2 *  s3 * ns4 *  s5;
2523   dF[ 6] = ns0 * ns1 * ns2 *  s3 *  s4 * ns5;
2524   dF[ 7] = ns0 * ns1 * ns2 *  s3 *  s4 *  s5;
2525   dF[ 8] = ns0 * ns1 *  s2 * ns3 * ns4 * ns5;
2526   dF[ 9] = ns0 * ns1 *  s2 * ns3 * ns4 *  s5;
2527   dF[10] = ns0 * ns1 *  s2 * ns3 *  s4 * ns5;
2528   dF[11] = ns0 * ns1 *  s2 * ns3 *  s4 *  s5;
2529   dF[12] = ns0 * ns1 *  s2 *  s3 * ns4 * ns5;
2530   dF[13] = ns0 * ns1 *  s2 *  s3 * ns4 *  s5;
2531   dF[14] = ns0 * ns1 *  s2 *  s3 *  s4 * ns5;
2532   dF[15] = ns0 * ns1 *  s2 *  s3 *  s4 *  s5;
2533   dF[16] = ns0 *  s1 * ns2 * ns3 * ns4 * ns5;
2534   dF[17] = ns0 *  s1 * ns2 * ns3 * ns4 *  s5;
2535   dF[18] = ns0 *  s1 * ns2 * ns3 *  s4 * ns5;
2536   dF[19] = ns0 *  s1 * ns2 * ns3 *  s4 *  s5;
2537   dF[20] = ns0 *  s1 * ns2 *  s3 * ns4 * ns5;
2538   dF[21] = ns0 *  s1 * ns2 *  s3 * ns4 *  s5;
2539   dF[22] = ns0 *  s1 * ns2 *  s3 *  s4 * ns5;
2540   dF[23] = ns0 *  s1 * ns2 *  s3 *  s4 *  s5;
2541   dF[24] = ns0 *  s1 *  s2 * ns3 * ns4 * ns5;
2542   dF[25] = ns0 *  s1 *  s2 * ns3 * ns4 *  s5;
2543   dF[26] = ns0 *  s1 *  s2 * ns3 *  s4 * ns5;
2544   dF[27] = ns0 *  s1 *  s2 * ns3 *  s4 *  s5;
2545   dF[28] = ns0 *  s1 *  s2 *  s3 * ns4 * ns5;
2546   dF[29] = ns0 *  s1 *  s2 *  s3 * ns4 *  s5;
2547   dF[30] = ns0 *  s1 *  s2 *  s3 *  s4 * ns5;
2548   dF[31] = ns0 *  s1 *  s2 *  s3 *  s4 *  s5;
2549   dF[32] =  s0 * ns1 * ns2 * ns3 * ns4 * ns5;
2550   dF[33] =  s0 * ns1 * ns2 * ns3 * ns4 *  s5;
2551   dF[34] =  s0 * ns1 * ns2 * ns3 *  s4 * ns5;
2552   dF[35] =  s0 * ns1 * ns2 * ns3 *  s4 *  s5;
2553   dF[36] =  s0 * ns1 * ns2 *  s3 * ns4 * ns5;
2554   dF[37] =  s0 * ns1 * ns2 *  s3 * ns4 *  s5;
2555   dF[38] =  s0 * ns1 * ns2 *  s3 *  s4 * ns5;
2556   dF[39] =  s0 * ns1 * ns2 *  s3 *  s4 *  s5;
2557   dF[40] =  s0 * ns1 *  s2 * ns3 * ns4 * ns5;
2558   dF[41] =  s0 * ns1 *  s2 * ns3 * ns4 *  s5;
2559   dF[42] =  s0 * ns1 *  s2 * ns3 *  s4 * ns5;
2560   dF[43] =  s0 * ns1 *  s2 * ns3 *  s4 *  s5;
2561   dF[44] =  s0 * ns1 *  s2 *  s3 * ns4 * ns5;
2562   dF[45] =  s0 * ns1 *  s2 *  s3 * ns4 *  s5;
2563   dF[46] =  s0 * ns1 *  s2 *  s3 *  s4 * ns5;
2564   dF[47] =  s0 * ns1 *  s2 *  s3 *  s4 *  s5;
2565   dF[48] =  s0 *  s1 * ns2 * ns3 * ns4 * ns5;
2566   dF[49] =  s0 *  s1 * ns2 * ns3 * ns4 *  s5;
2567   dF[50] =  s0 *  s1 * ns2 * ns3 *  s4 * ns5;
2568   dF[51] =  s0 *  s1 * ns2 * ns3 *  s4 *  s5;
2569   dF[52] =  s0 *  s1 * ns2 *  s3 * ns4 * ns5;
2570   dF[53] =  s0 *  s1 * ns2 *  s3 * ns4 *  s5;
2571   dF[54] =  s0 *  s1 * ns2 *  s3 *  s4 * ns5;
2572   dF[55] =  s0 *  s1 * ns2 *  s3 *  s4 *  s5;
2573   dF[56] =  s0 *  s1 *  s2 * ns3 * ns4 * ns5;
2574   dF[57] =  s0 *  s1 *  s2 * ns3 * ns4 *  s5;
2575   dF[58] =  s0 *  s1 *  s2 * ns3 *  s4 * ns5;
2576   dF[59] =  s0 *  s1 *  s2 * ns3 *  s4 *  s5;
2577   dF[60] =  s0 *  s1 *  s2 *  s3 * ns4 * ns5;
2578   dF[61] =  s0 *  s1 *  s2 *  s3 * ns4 *  s5;
2579   dF[62] =  s0 *  s1 *  s2 *  s3 *  s4 * ns5;
2580   dF[63] =  s0 *  s1 *  s2 *  s3 *  s4 *  s5;
2581 
2582   for (i=0; i<m_nOutput; i++, p++) {
2583     for (pv=0, j=0; j<64; j++)
2584       pv += p[m_nOffset[j]] * dF[j];
2585 
2586     destPixel[i] = pv;
2587   }
2588 }
2589 
2590 
2591 /**
2592  ******************************************************************************
2593  * Name: CIccCLUT::InterpND
2594  *
2595  * Purpose: Generic N-dimensional interpolation function
2596  *
2597  * Args:
2598  *  Pixel = Pixel value to be found in the CLUT. Also used to store the result.
2599  *******************************************************************************
2600  */
InterpND(icFloatNumber * destPixel,const icFloatNumber * srcPixel) const2601 void CIccCLUT::InterpND(icFloatNumber *destPixel, const icFloatNumber *srcPixel) const
2602 {
2603   icUInt32Number i,j, index = 0;
2604 
2605   for (i=0; i<m_nInput; i++) {
2606     m_g[i] = UnitClip(srcPixel[i]) * m_MaxGridPoint[i];
2607     m_ig[i] = (icUInt32Number)m_g[i];
2608     m_s[m_nInput-1-i] = m_g[i] - m_ig[i];
2609     if (m_ig[i]==m_MaxGridPoint[i]) {
2610       m_ig[i]--;
2611       m_s[m_nInput-1-i] = 1.0;
2612     }
2613     index += m_ig[i]*m_DimSize[i];
2614   }
2615 
2616   icFloatNumber *p = &m_pData[index];
2617   icFloatNumber temp[2];
2618   icFloatNumber pv;
2619   int nFlag = 0;
2620 
2621   for (i=0; i<m_nNodes; i++) {
2622     m_df[i] = 1.0;
2623   }
2624 
2625 
2626   for (i=0; i<m_nInput; i++) {
2627     temp[0] = (icFloatNumber)(1.0 - m_s[i]);
2628     temp[1] = (icFloatNumber)(m_s[i]);
2629     index = m_nPower[i];
2630     for (j=0; j<m_nNodes; j++) {
2631       m_df[j] *= temp[nFlag];
2632       if ((j+1)%index == 0)
2633         nFlag = !nFlag;
2634     }
2635     nFlag = 0;
2636   }
2637 
2638   for (i=0; i<m_nOutput; i++, p++) {
2639     for (pv=0, j=0; j<m_nNodes; j++)
2640       pv += p[m_nOffset[j]] * m_df[j];
2641 
2642     destPixel[i] = pv;
2643   }
2644 
2645 }
2646 
2647 
2648 /**
2649 ******************************************************************************
2650 * Name: CIccCLUT::Validate
2651 *
2652 * Purpose: Check tag data validity.
2653 *
2654 * Args:
2655 *  sig = signature of tag being validated,
2656 *  sReport = String to add report information to
2657 *
2658 * Return:
2659 *  icValidateStatusOK if valid, or other error status.
2660 ******************************************************************************
2661 */
Validate(icTagTypeSignature sig,std::string & sReport,const CIccProfile * pProfile) const2662 icValidateStatus CIccCLUT::Validate(icTagTypeSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const
2663 {
2664   icValidateStatus rv = icValidateOK;
2665 
2666   CIccInfo Info;
2667   std::string sSigName = Info.GetSigName(sig);
2668   if (m_nReserved2[0]!=0 || m_nReserved2[1]!=0 || m_nReserved2[2]!=0) {
2669     sReport += icValidateNonCompliantMsg;
2670     sReport += sSigName;
2671     sReport += " - Reserved Value must be zero.\r\n";
2672 
2673     rv = icValidateNonCompliant;
2674   }
2675 
2676   if (sig==icSigLutAtoBType || sig==icSigLutBtoAType) {
2677     char temp[256];
2678     for (int i=0; i<m_nInput; i++) {
2679       if (m_GridPoints[i]<2) {
2680         sReport += icValidateCriticalErrorMsg;
2681         sReport += sSigName;
2682         sprintf(temp, " - CLUT: At least 2 grid points should be present in dimension %u.\r\n",i );
2683         sReport += temp;
2684         rv = icMaxStatus(rv, icValidateCriticalError);
2685       }
2686     }
2687   }
2688 
2689   return rv;
2690 }
2691 
2692 
2693 /**
2694  ****************************************************************************
2695  * Name: CIccMBB::CIccMBB
2696  *
2697  * Purpose: Constructor
2698  *
2699  *****************************************************************************
2700  */
CIccMBB()2701 CIccMBB::CIccMBB()
2702 {
2703   m_nInput = 0;
2704   m_nOutput = 0;
2705 
2706   m_CurvesA = NULL;
2707   m_CLUT = NULL;
2708   m_Matrix = NULL;
2709   m_CurvesM = NULL;
2710   m_CurvesB = NULL;
2711 
2712   m_csInput  = icSigUnknownData;
2713   m_csOutput = icSigUnknownData;
2714 
2715   m_bInputMatrix = true;
2716   m_bUseMCurvesAsBCurves = false;
2717 }
2718 
2719 
2720 /**
2721  ****************************************************************************
2722  * Name: CIccMBB::CIccMBB
2723  *
2724  * Purpose: Copy Constructor
2725  *
2726  * Args:
2727  *  IMBB = The CIccMBB object to be copied
2728  *****************************************************************************
2729  */
CIccMBB(const CIccMBB & IMBB)2730 CIccMBB::CIccMBB(const CIccMBB &IMBB)
2731 {
2732  icUInt8Number nCurves;
2733  int i;
2734 
2735   m_bInputMatrix = IMBB.m_bInputMatrix;
2736   m_bUseMCurvesAsBCurves = IMBB.m_bUseMCurvesAsBCurves;
2737   m_nInput = IMBB.m_nInput;
2738   m_nOutput = IMBB.m_nOutput;
2739   m_csInput = IMBB.m_csInput;
2740   m_csOutput = IMBB.m_csOutput;
2741 
2742   if (IMBB.m_CLUT) {
2743     m_CLUT = new CIccCLUT(*IMBB.m_CLUT);
2744   }
2745   else
2746     m_CLUT = NULL;
2747 
2748   if (IMBB.m_CurvesA) {
2749     nCurves = !IsInputB() ? m_nInput : m_nOutput;
2750 
2751     m_CurvesA = new LPIccCurve[nCurves];
2752     for (i=0; i<nCurves; i++)
2753       m_CurvesA[i] = (CIccTagCurve*)IMBB.m_CurvesA[i]->NewCopy();
2754   }
2755   else {
2756     m_CurvesA = NULL;
2757   }
2758 
2759   if (IMBB.m_CurvesM) {
2760     nCurves = IsInputMatrix() ? m_nInput : m_nOutput;
2761 
2762     m_CurvesM = new LPIccCurve[nCurves];
2763     for (i=0; i<nCurves; i++)
2764       m_CurvesM[i] = (CIccTagCurve*)IMBB.m_CurvesM[i]->NewCopy();
2765   }
2766   else {
2767     m_CurvesM = NULL;
2768   }
2769 
2770   if (IMBB.m_CurvesB) {
2771     nCurves = IsInputB() ? m_nInput : m_nOutput;
2772 
2773     m_CurvesB = new LPIccCurve[nCurves];
2774     for (i=0; i<nCurves; i++)
2775       m_CurvesB[i] = (CIccTagCurve*)IMBB.m_CurvesB[i]->NewCopy();
2776   }
2777   else {
2778     m_CurvesB = NULL;
2779   }
2780 
2781   if (IMBB.m_Matrix) {
2782     m_Matrix = new CIccMatrix(*IMBB.m_Matrix);
2783   }
2784   else {
2785     m_Matrix = NULL;
2786   }
2787 }
2788 
2789 
2790 /**
2791  ****************************************************************************
2792  * Name: CIccMBB::operator=
2793  *
2794  * Purpose: Copy Operator
2795  *
2796  * Args:
2797  *  IMBB = The CIccMBB object to be copied
2798  *****************************************************************************
2799  */
operator =(const CIccMBB & IMBB)2800 CIccMBB &CIccMBB::operator=(const CIccMBB &IMBB)
2801 {
2802   if (&IMBB == this)
2803     return *this;
2804 
2805   Cleanup();
2806 
2807   icUInt8Number nCurves;
2808   int i;
2809 
2810   m_bInputMatrix = IMBB.m_bInputMatrix;
2811   m_bUseMCurvesAsBCurves = IMBB.m_bUseMCurvesAsBCurves;
2812   m_nInput = IMBB.m_nInput;
2813   m_nOutput = IMBB.m_nOutput;
2814   m_csInput = IMBB.m_csInput;
2815   m_csOutput = IMBB.m_csOutput;
2816 
2817   if (IMBB.m_CLUT) {
2818     m_CLUT = new CIccCLUT(*IMBB.m_CLUT);
2819   }
2820   else
2821     m_CLUT = NULL;
2822 
2823   if (IMBB.m_CurvesA) {
2824     nCurves = !IsInputB() ? m_nInput : m_nOutput;
2825 
2826     m_CurvesA = new LPIccCurve[nCurves];
2827     for (i=0; i<nCurves; i++)
2828       m_CurvesA[i] = (CIccTagCurve*)IMBB.m_CurvesA[i]->NewCopy();
2829   }
2830   else {
2831     m_CurvesA = NULL;
2832   }
2833 
2834   if (IMBB.m_CurvesM) {
2835     nCurves = IsInputMatrix() ? m_nInput : m_nOutput;
2836 
2837     m_CurvesM = new LPIccCurve[nCurves];
2838     for (i=0; i<nCurves; i++)
2839       m_CurvesM[i] = (CIccTagCurve*)IMBB.m_CurvesM[i]->NewCopy();
2840   }
2841   else {
2842     m_CurvesM = NULL;
2843   }
2844 
2845   if (IMBB.m_CurvesB) {
2846     nCurves = IsInputB() ? m_nInput : m_nOutput;
2847 
2848     m_CurvesB = new LPIccCurve[nCurves];
2849     for (i=0; i<nCurves; i++)
2850       m_CurvesB[i] = (CIccTagCurve*)IMBB.m_CurvesB[i]->NewCopy();
2851   }
2852   else {
2853     m_CurvesB = NULL;
2854   }
2855 
2856   if (IMBB.m_Matrix) {
2857     m_Matrix = new CIccMatrix(*IMBB.m_Matrix);
2858   }
2859   else {
2860     m_Matrix = NULL;
2861   }
2862 
2863   return *this;
2864 }
2865 
2866 
2867 /**
2868  ****************************************************************************
2869  * Name: CIccMBB::~CIccMBB
2870  *
2871  * Purpose: Destructor
2872  *
2873  *****************************************************************************
2874  */
~CIccMBB()2875 CIccMBB::~CIccMBB()
2876 {
2877   Cleanup();
2878 }
2879 
2880 /**
2881  ****************************************************************************
2882  * Name: CIccMBB::Cleanup
2883  *
2884  * Purpose: Frees the memory allocated to the object
2885  *
2886  *****************************************************************************
2887  */
Cleanup()2888 void CIccMBB::Cleanup()
2889 {
2890   int i;
2891 
2892   if (IsInputMatrix()) {
2893     if (m_CurvesB) {
2894       for (i=0; i<m_nInput; i++)
2895         if (m_CurvesB[i])
2896           delete m_CurvesB[i];
2897 
2898       delete [] m_CurvesB;
2899       m_CurvesB = NULL;
2900     }
2901 
2902     if (m_CurvesM) {
2903       for (i=0; i<m_nInput; i++)
2904         if (m_CurvesM[i])
2905           delete m_CurvesM[i];
2906 
2907       delete [] m_CurvesM;
2908       m_CurvesM = NULL;
2909     }
2910 
2911 
2912     if (m_CurvesA) {
2913       for (i=0; i<m_nOutput; i++)
2914         if (m_CurvesA[i])
2915           delete m_CurvesA[i];
2916 
2917       delete [] m_CurvesA;
2918       m_CurvesA = NULL;
2919     }
2920 
2921   }
2922   else {
2923     if (m_CurvesA) {
2924       for (i=0; i<m_nInput; i++)
2925         if (m_CurvesA[i])
2926           delete m_CurvesA[i];
2927 
2928       delete [] m_CurvesA;
2929       m_CurvesA = NULL;
2930     }
2931 
2932     if (m_CurvesM) {
2933       for (i=0; i<m_nOutput; i++)
2934         if (m_CurvesM[i])
2935           delete m_CurvesM[i];
2936 
2937       delete [] m_CurvesM;
2938       m_CurvesM = NULL;
2939     }
2940 
2941     if (m_CurvesB) {
2942       for (i=0; i<m_nOutput; i++)
2943         if (m_CurvesB[i])
2944           delete m_CurvesB[i];
2945 
2946       delete [] m_CurvesB;
2947       m_CurvesB = NULL;
2948     }
2949   }
2950 
2951   if (m_Matrix) {
2952     delete m_Matrix;
2953     m_Matrix = NULL;
2954   }
2955 
2956   if (m_CLUT) {
2957     delete m_CLUT;
2958     m_CLUT = NULL;
2959   }
2960 }
2961 
2962 /**
2963  ****************************************************************************
2964  * Name: CIccMBB::Init
2965  *
2966  * Purpose: Cleans up any prior memory and Initializes the object.
2967  *
2968  * Args:
2969  *  nInputChannels = number of input channels,
2970  *  nOutputChannels = number of output channels
2971  *****************************************************************************
2972  */
Init(icUInt8Number nInputChannels,icUInt8Number nOutputChannels)2973 void CIccMBB::Init(icUInt8Number nInputChannels, icUInt8Number nOutputChannels)
2974 {
2975   Cleanup();
2976   m_nInput = nInputChannels;
2977   m_nOutput = nOutputChannels;
2978 }
2979 
2980 /**
2981  ****************************************************************************
2982  * Name: CIccMBB::SetColorSpaces
2983  *
2984  * Purpose: Sets the input and output color spaces
2985  *
2986  * Args:
2987  *  csInput = input color space signature,
2988  *  csOutput = output color space signature
2989  *****************************************************************************
2990  */
SetColorSpaces(icColorSpaceSignature csInput,icColorSpaceSignature csOutput)2991 void CIccMBB::SetColorSpaces(icColorSpaceSignature csInput, icColorSpaceSignature csOutput)
2992 {
2993    m_csInput = csInput;
2994    m_csOutput = csOutput;
2995 }
2996 
2997 /**
2998  ****************************************************************************
2999  * Name: CIccMBB::Describe
3000  *
3001  * Purpose: Dump data associated with the tag to a string
3002  *
3003  * Args:
3004  *  sDescription - string to concatenate tag dump to
3005  *****************************************************************************
3006  */
Describe(std::string & sDescription)3007 void CIccMBB::Describe(std::string &sDescription)
3008 {
3009   int i;
3010   icChar buf[128], color[40];
3011 
3012 
3013   if (IsInputMatrix()) {
3014     if (m_CurvesB && !m_bUseMCurvesAsBCurves) {
3015       for (i=0; i<m_nInput; i++) {
3016         icColorIndexName(color, m_csInput, i, m_nInput, "");
3017         sprintf(buf, "B_Curve_%s", color);
3018         m_CurvesB[i]->DumpLut(sDescription, buf, m_csInput, i);
3019       }
3020     }
3021 
3022     if (m_Matrix)
3023       m_Matrix->DumpLut(sDescription, "Matrix");
3024 
3025     if (m_CurvesM) {
3026       for (i=0; i<m_nInput; i++) {
3027         icColorIndexName(color, m_csInput, i, m_nInput, "");
3028         if (!m_bUseMCurvesAsBCurves)
3029           sprintf(buf, "M_Curve_%s", color);
3030         else
3031           sprintf(buf, "B_Curve_%s", color);
3032         m_CurvesM[i]->DumpLut(sDescription, buf, m_csInput, i);
3033       }
3034     }
3035 
3036     if (m_CLUT)
3037       m_CLUT->DumpLut(sDescription, "CLUT", m_csInput, m_csOutput, GetType()==icSigLut16Type);
3038 
3039     if (m_CurvesA) {
3040       for (i=0; i<m_nOutput; i++) {
3041         icColorIndexName(color, m_csOutput, i, m_nOutput, "");
3042         sprintf(buf, "A_Curve_%s", color);
3043         m_CurvesA[i]->DumpLut(sDescription, buf, m_csOutput, i);
3044       }
3045     }
3046   }
3047   else {
3048     if (m_CurvesA) {
3049       for (i=0; i<m_nInput; i++) {
3050         icColorIndexName(color, m_csInput, i, m_nInput, "");
3051         sprintf(buf, "A_Curve_%s", color);
3052         m_CurvesA[i]->DumpLut(sDescription, buf, m_csInput, i);
3053       }
3054     }
3055 
3056     if (m_CLUT)
3057       m_CLUT->DumpLut(sDescription, "CLUT", m_csInput, m_csOutput);
3058 
3059     if (m_CurvesM && this->GetType()!=icSigLut8Type) {
3060       for (i=0; i<m_nOutput; i++) {
3061         icColorIndexName(color, m_csOutput, i, m_nOutput, "");
3062         sprintf(buf, "M_Curve_%s", color);
3063         m_CurvesM[i]->DumpLut(sDescription, buf, m_csOutput, i);
3064       }
3065     }
3066 
3067     if (m_Matrix)
3068       m_Matrix->DumpLut(sDescription, "Matrix");
3069 
3070     if (m_CurvesB) {
3071       for (i=0; i<m_nOutput; i++) {
3072         icColorIndexName(color, m_csOutput, i, m_nOutput, "");
3073         sprintf(buf, "B_Curve_%s", color);
3074         m_CurvesB[i]->DumpLut(sDescription, buf, m_csOutput, i);
3075       }
3076     }
3077   }
3078 }
3079 
3080 
3081 /**
3082 ******************************************************************************
3083 * Name: CIccMBB::Validate
3084 *
3085 * Purpose: Check tag data validity.
3086 *
3087 * Args:
3088 *  sig = signature of tag being validated,
3089 *  sReport = String to add report information to
3090 *
3091 * Return:
3092 *  icValidateStatusOK if valid, or other error status.
3093 ******************************************************************************
3094 */
Validate(icTagSignature sig,std::string & sReport,const CIccProfile * pProfile) const3095 icValidateStatus CIccMBB::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const
3096 {
3097   icValidateStatus rv = CIccTag::Validate(sig, sReport, pProfile);
3098 
3099   CIccInfo Info;
3100   std::string sSigName = Info.GetSigName(sig);
3101 
3102   if (!pProfile) {
3103     sReport += icValidateWarningMsg;
3104     sReport += sSigName;
3105     sReport += " - Tag validation incomplete: Pointer to profile unavailable.\r\n";
3106     rv = icMaxStatus(rv, icValidateWarning);
3107     return rv;
3108   }
3109   icUInt32Number nInput, nOutput;
3110 
3111   //Check # of channels
3112   switch(sig) {
3113   case icSigAToB0Tag:
3114   case icSigAToB1Tag:
3115   case icSigAToB2Tag:
3116     {
3117       nInput = icGetSpaceSamples(pProfile->m_Header.colorSpace);
3118       if (m_nInput!=nInput) {
3119         sReport += icValidateCriticalErrorMsg;
3120         sReport += sSigName;
3121         sReport += " - Incorrect number of input channels.\r\n";
3122         rv = icMaxStatus(rv, icValidateCriticalError);
3123       }
3124 
3125       nOutput = icGetSpaceSamples(pProfile->m_Header.pcs);
3126       if (m_nOutput!=nOutput) {
3127         sReport += icValidateCriticalErrorMsg;
3128         sReport += sSigName;
3129         sReport += " - Incorrect number of output channels.\r\n";
3130         rv = icMaxStatus(rv, icValidateCriticalError);
3131       }
3132 
3133       break;
3134     }
3135   case icSigBToA0Tag:
3136   case icSigBToA1Tag:
3137   case icSigBToA2Tag:
3138     {
3139       nInput = icGetSpaceSamples(pProfile->m_Header.pcs);
3140       if (m_nInput!=nInput) {
3141         sReport += icValidateCriticalErrorMsg;
3142         sReport += sSigName;
3143         sReport += " - Incorrect number of input channels.\r\n";
3144         rv = icMaxStatus(rv, icValidateCriticalError);
3145       }
3146 
3147       nOutput = icGetSpaceSamples(pProfile->m_Header.colorSpace);
3148       if (m_nOutput!=nOutput) {
3149         sReport += icValidateCriticalErrorMsg;
3150         sReport += sSigName;
3151         sReport += " - Incorrect number of output channels.\r\n";
3152         rv = icMaxStatus(rv, icValidateCriticalError);
3153       }
3154 
3155       break;
3156     }
3157   case icSigGamutTag:
3158     {
3159       nInput = 1;
3160       if (m_nInput!=nInput) {
3161         sReport += icValidateCriticalErrorMsg;
3162         sReport += sSigName;
3163         sReport += " - Incorrect number of input channels.\r\n";
3164         rv = icMaxStatus(rv, icValidateCriticalError);
3165       }
3166 
3167       nOutput = icGetSpaceSamples(pProfile->m_Header.colorSpace);
3168       if (m_nOutput!=nOutput) {
3169         sReport += icValidateCriticalErrorMsg;
3170         sReport += sSigName;
3171         sReport += " - Incorrect number of output channels.\r\n";
3172         rv = icMaxStatus(rv, icValidateCriticalError);
3173       }
3174 
3175       break;
3176     }
3177   default:
3178     {
3179       nInput = m_nInput;
3180       nOutput = m_nOutput;
3181     }
3182   }
3183 
3184   //CLUT check
3185   if (nInput!=nOutput) {
3186     if (!m_CLUT) {
3187       sReport += icValidateCriticalErrorMsg;
3188       sReport += sSigName;
3189       sReport += " - CLUT must be present.\r\n";
3190       rv = icMaxStatus(rv, icValidateCriticalError);
3191     }
3192   }
3193 
3194   if (m_CLUT) {
3195     rv = icMaxStatus(rv, m_CLUT->Validate(GetType(), sReport, pProfile));
3196   }
3197 
3198   return rv;
3199 }
3200 
3201 /**
3202  ****************************************************************************
3203  * Name: CIccMBB::NewCurvesA
3204  *
3205  * Purpose: Allocates memory for a new set of A-curves
3206  *
3207  * Return: Pointer to the LPIccCurve object
3208  *****************************************************************************
3209  */
NewCurvesA()3210 LPIccCurve* CIccMBB::NewCurvesA()
3211 {
3212   if (m_CurvesA)
3213     return m_CurvesA;
3214 
3215   icUInt8Number nCurves = !IsInputB() ? m_nInput : m_nOutput;
3216 
3217   m_CurvesA = new LPIccCurve[nCurves];
3218   memset(m_CurvesA, 0, nCurves * sizeof(LPIccCurve));
3219 
3220   return m_CurvesA;
3221 }
3222 
3223 
3224 /**
3225  ****************************************************************************
3226  * Name: CIccMBB::NewCurvesM
3227  *
3228  * Purpose: Allocates memory for a new set of M-curves
3229  *
3230  * Return: Pointer to the LPIccCurve object
3231  *****************************************************************************
3232  */
NewCurvesM()3233 LPIccCurve* CIccMBB::NewCurvesM()
3234 {
3235   if (m_CurvesM)
3236     return m_CurvesM;
3237 
3238   icUInt8Number nCurves = IsInputMatrix() ? m_nInput : m_nOutput;
3239 
3240   m_CurvesM = new LPIccCurve[nCurves];
3241   memset(m_CurvesM, 0, nCurves * sizeof(LPIccCurve));
3242 
3243   return m_CurvesM;
3244 }
3245 
3246 /**
3247  ****************************************************************************
3248  * Name: CIccMBB::NewCurvesB
3249  *
3250  * Purpose: Allocates memory for a new set of B-curves
3251  *
3252  * Return: Pointer to the LPIccCurve object
3253  *****************************************************************************
3254  */
NewCurvesB()3255 LPIccCurve* CIccMBB::NewCurvesB()
3256 {
3257   if (m_CurvesB)
3258     return m_CurvesB;
3259 
3260   icUInt8Number nCurves = IsInputB() ? m_nInput : m_nOutput;
3261 
3262   m_CurvesB = new LPIccCurve[nCurves];
3263   memset(m_CurvesB, 0, nCurves * sizeof(LPIccCurve));
3264 
3265   return m_CurvesB;
3266 }
3267 
3268 /**
3269  ****************************************************************************
3270  * Name: CIccMBB::NewMatrix
3271  *
3272  * Purpose: Allocates memory for a new matrix
3273  *
3274  * Return: Pointer to the CIccMatrix object
3275  *****************************************************************************
3276  */
NewMatrix()3277 CIccMatrix* CIccMBB::NewMatrix()
3278 {
3279   if (m_Matrix)
3280     return m_Matrix;
3281 
3282   m_Matrix = new CIccMatrix;
3283 
3284   return m_Matrix;
3285 }
3286 
3287 /**
3288  ****************************************************************************
3289  * Name: CIccMBB::NewCLUT
3290  *
3291  * Purpose: Allocates memory for a new CLUT and initializes it
3292  *
3293  * Args:
3294  *  pGridPoints = number of grid points in the CLUT
3295  *
3296  * Return: Pointer to the CIccCLUT object
3297  *****************************************************************************
3298  */
NewCLUT(icUInt8Number * pGridPoints,icUInt8Number nPrecision)3299 CIccCLUT* CIccMBB::NewCLUT(icUInt8Number *pGridPoints, icUInt8Number nPrecision/*=2*/)
3300 {
3301   if (m_CLUT)
3302     return m_CLUT;
3303 
3304   m_CLUT = new CIccCLUT(m_nInput, m_nOutput, nPrecision);
3305 
3306   m_CLUT->Init(pGridPoints);
3307 
3308   return m_CLUT;
3309 }
3310 
3311 /**
3312 ****************************************************************************
3313 * Name: CIccMBB::SetCLUT
3314 *
3315 * Purpose: Assignes CLUT connection to an initialized new CLUT
3316 *
3317 * Args:
3318 *  clut = pointer to a previously allocated CLUT (Onwership is transfered to
3319 *    CIccMBB object).
3320 *
3321 * Return: Pointer to the CIccCLUT object or NULL if clut is incompatible with
3322 *  CIccMBB object.  If the clut is incompatible it is deleted.
3323 *****************************************************************************
3324 */
SetCLUT(CIccCLUT * clut)3325 CIccCLUT *CIccMBB::SetCLUT(CIccCLUT *clut)
3326 {
3327   if (clut->GetInputDim() != m_nInput || clut->GetOutputChannels() != m_nOutput) {
3328     delete clut;
3329     return NULL;
3330   }
3331 
3332   if (m_CLUT) {
3333     delete m_CLUT;
3334   }
3335 
3336   m_CLUT = clut;
3337   return clut;
3338 }
3339 
3340 /**
3341  ****************************************************************************
3342  * Name: CIccMBB::NewCLUT
3343  *
3344  * Purpose: Allocates memory for a new CLUT and initializes it
3345  *
3346  * Args:
3347  *  nGridPoints = number of grid points in the CLUT
3348  *
3349  * Return: Pointer to the CIccCLUT object
3350  *****************************************************************************
3351  */
NewCLUT(icUInt8Number nGridPoints,icUInt8Number nPrecision)3352 CIccCLUT* CIccMBB::NewCLUT(icUInt8Number nGridPoints, icUInt8Number nPrecision/*=2*/)
3353 {
3354   if (m_CLUT)
3355     return m_CLUT;
3356 
3357   m_CLUT = new CIccCLUT(m_nInput, m_nOutput, nPrecision);
3358 
3359   m_CLUT->Init(nGridPoints);
3360 
3361   return m_CLUT;
3362 }
3363 
3364 
3365 /**
3366  ****************************************************************************
3367  * Name: CIccTagLutAtoB::CIccTagLutAtoB
3368  *
3369  * Purpose: Constructor
3370  *
3371  *****************************************************************************
3372  */
CIccTagLutAtoB()3373 CIccTagLutAtoB::CIccTagLutAtoB()
3374 {
3375   m_bInputMatrix = false;
3376   m_nReservedWord = 0;
3377 }
3378 
3379 
3380 /**
3381  ****************************************************************************
3382  * Name: CIccTagLutAtoB::CIccTagLutAtoB
3383  *
3384  * Purpose: Copy Constructor
3385  *
3386  * Args:
3387  *  ITLA2B = The CIccTagLutAtoB object to be copied
3388  *****************************************************************************
3389  */
CIccTagLutAtoB(const CIccTagLutAtoB & ITLA2B)3390 CIccTagLutAtoB::CIccTagLutAtoB(const CIccTagLutAtoB &ITLA2B) : CIccMBB(ITLA2B)
3391 {
3392   m_nReservedWord = 0;
3393 }
3394 
3395 
3396 /**
3397  ****************************************************************************
3398  * Name: CIccTagLutAtoB::operator=
3399  *
3400  * Purpose: Copy Operator
3401  *
3402  * Args:
3403  *  ITLA2B = The CIccTagLutAtoB object to be copied
3404  *****************************************************************************
3405  */
operator =(const CIccTagLutAtoB & ITLA2B)3406 CIccTagLutAtoB &CIccTagLutAtoB::operator=(const CIccTagLutAtoB &ITLA2B)
3407 {
3408   if (&ITLA2B == this)
3409     return *this;
3410 
3411   CIccMBB::operator=(ITLA2B);
3412 
3413   return *this;
3414 }
3415 
3416 
3417 /**
3418  ****************************************************************************
3419  * Name: CIccTagLutAtoB::~CIccTagLutAtoB
3420  *
3421  * Purpose: Destructor
3422  *
3423  *****************************************************************************
3424  */
~CIccTagLutAtoB()3425 CIccTagLutAtoB::~CIccTagLutAtoB()
3426 {
3427 }
3428 
3429 
3430 /**
3431  ****************************************************************************
3432  * Name: CIccTagLutAtoB::Read
3433  *
3434  * Purpose: Read in the tag contents into a data block
3435  *
3436  * Args:
3437  *  size - # of bytes in tag,
3438  *  pIO - IO object to read tag from
3439  *
3440  * Return:
3441  *  true = successful, false = failure
3442  *****************************************************************************
3443  */
Read(icUInt32Number size,CIccIO * pIO)3444 bool CIccTagLutAtoB::Read(icUInt32Number size, CIccIO *pIO)
3445 {
3446   icTagTypeSignature sig;
3447   icUInt32Number Offset[5], nStart, nEnd, nPos;
3448   icUInt8Number nCurves, i;
3449 
3450   if (size<8*sizeof(icUInt32Number) || !pIO) {
3451     return false;
3452   }
3453 
3454   nStart = pIO->Tell();
3455   nEnd = nStart + size;
3456 
3457   if (!pIO->Read32(&sig) ||
3458       !pIO->Read32(&m_nReserved) ||
3459       !pIO->Read8(&m_nInput) ||
3460       !pIO->Read8(&m_nOutput) ||
3461       !pIO->Read16(&m_nReservedWord) ||
3462       pIO->Read32(Offset, 5)!=5)
3463     return false;
3464 
3465   if (sig!=GetType())
3466     return false;
3467 
3468   //B Curves
3469   if (Offset[0]) {
3470     nCurves = IsInputB() ? m_nInput : m_nOutput;
3471     LPIccCurve *pCurves = NewCurvesB();
3472 
3473     if (pIO->Seek(nStart + Offset[0], icSeekSet)<0)
3474       return false;
3475 
3476     for (i=0; i<nCurves; i++) {
3477       nPos = pIO->Tell();
3478 
3479       if (!pIO->Read32(&sig))
3480         return false;
3481 
3482       if (pIO->Seek(nPos, icSeekSet)<0)
3483         return false;
3484 
3485       if (sig!=icSigCurveType &&
3486           sig!=icSigParametricCurveType)
3487         return false;
3488 
3489       pCurves[i] = (CIccCurve*)CIccTag::Create(sig);
3490 
3491       if (!pCurves[i]->Read(nEnd - pIO->Tell(), pIO))
3492         return false;
3493 
3494       if (!pIO->Sync32(Offset[1]))
3495         return false;
3496     }
3497   }
3498 
3499   //Matrix
3500   if (Offset[1]) {
3501     icS15Fixed16Number tmp;
3502 
3503     if (Offset[1] + 12*sizeof(icS15Fixed16Number) >size)
3504       return false;
3505 
3506     m_Matrix = new CIccMatrix();
3507 
3508     if (pIO->Seek(nStart + Offset[1], icSeekSet)<0)
3509       return false;
3510 
3511     for (i=0; i<12; i++) {
3512        if (pIO->Read32(&tmp, 1)!=1)
3513         return false;
3514       m_Matrix->m_e[i] = icFtoD(tmp);
3515     }
3516   }
3517 
3518 
3519   //M Curves
3520   if (Offset[2]) {
3521     nCurves = IsInputMatrix() ? m_nInput : m_nOutput;
3522     LPIccCurve *pCurves = NewCurvesM();
3523 
3524     if (pIO->Seek(nStart + Offset[2], icSeekSet)<0)
3525       return false;
3526 
3527     for (i=0; i<nCurves; i++) {
3528       nPos = pIO->Tell();
3529 
3530       if (!pIO->Read32(&sig))
3531         return false;
3532 
3533       if (pIO->Seek(nPos, icSeekSet)<0)
3534         return false;
3535 
3536       if (sig!=icSigCurveType &&
3537           sig!=icSigParametricCurveType)
3538         return false;
3539 
3540       pCurves[i] = (CIccCurve*)CIccTag::Create(sig);
3541 
3542       if (!pCurves[i]->Read(nEnd - pIO->Tell(), pIO))
3543         return false;
3544 
3545       if (!pIO->Sync32(Offset[2]))
3546         return false;
3547     }
3548   }
3549 
3550   //CLUT
3551   if (Offset[3]) {
3552     if (pIO->Seek(nStart + Offset[3], icSeekSet)<0)
3553       return false;
3554 
3555     m_CLUT = new CIccCLUT(m_nInput, m_nOutput);
3556 
3557     if (!m_CLUT->Read(nEnd - pIO->Tell(), pIO))
3558       return false;
3559   }
3560 
3561   //A Curves
3562   if (Offset[4]) {
3563     nCurves = !IsInputB() ? m_nInput : m_nOutput;
3564     LPIccCurve *pCurves = NewCurvesA();
3565 
3566     if (pIO->Seek(nStart + Offset[4], icSeekSet)<0)
3567       return false;
3568 
3569     for (i=0; i<nCurves; i++) {
3570       nPos = pIO->Tell();
3571 
3572       if (!pIO->Read32(&sig))
3573         return false;
3574 
3575       if (pIO->Seek(nPos, icSeekSet)<0)
3576         return false;
3577 
3578       if (sig!=icSigCurveType &&
3579           sig!=icSigParametricCurveType)
3580         return false;
3581 
3582       pCurves[i] = (CIccCurve*)CIccTag::Create(sig);
3583 
3584       if (!pCurves[i]->Read(nEnd - pIO->Tell(), pIO))
3585         return false;
3586 
3587       if (!pIO->Sync32(Offset[4]))
3588         return false;
3589     }
3590   }
3591   return true;
3592 }
3593 
3594 
3595 
3596 /**
3597  ****************************************************************************
3598  * Name: CIccTagLutAtoB::Write
3599  *
3600  * Purpose: Write the tag to a file
3601  *
3602  * Args:
3603  *  pIO - The IO object to write tag to.
3604  *
3605  * Return:
3606  *  true = succesful, false = failure
3607  *****************************************************************************
3608  */
Write(CIccIO * pIO)3609 bool CIccTagLutAtoB::Write(CIccIO *pIO)
3610 {
3611   icTagTypeSignature sig = GetType();
3612   icUInt32Number Offset[5], nStart, nEnd, nOffsetPos;
3613   icUInt8Number nCurves, i;
3614 
3615   nStart = pIO->Tell();
3616   memset(&Offset[0], 0, sizeof(Offset));
3617 
3618   if (!pIO->Write32(&sig) ||
3619       !pIO->Write32(&m_nReserved) ||
3620       !pIO->Write8(&m_nInput) ||
3621       !pIO->Write8(&m_nOutput) ||
3622       !pIO->Write16(&m_nReservedWord))
3623     return false;
3624 
3625   nOffsetPos = pIO->Tell();
3626   if (pIO->Write32(Offset, 5)!=5)
3627     return false;
3628 
3629   //B Curves
3630   if (m_CurvesB) {
3631     Offset[0] = pIO->Tell() - nStart;
3632     nCurves = IsInputB() ? m_nInput : m_nOutput;
3633 
3634     for (i=0; i<nCurves; i++) {
3635       if (!m_CurvesB[i])
3636         return false;
3637 
3638       if (!m_CurvesB[i]->Write(pIO))
3639         return false;
3640 
3641       if (!pIO->Align32())
3642         return false;
3643     }
3644   }
3645 
3646   //Matrix
3647   if (m_Matrix) {
3648     icS15Fixed16Number tmp;
3649 
3650     Offset[1] = pIO->Tell() - nStart;
3651 
3652     for (i=0; i<12; i++) {
3653       tmp = icDtoF(m_Matrix->m_e[i]);
3654       if (pIO->Write32(&tmp, 1)!=1)
3655         return false;
3656     }
3657   }
3658 
3659 
3660   //M Curves
3661   if (m_CurvesM) {
3662     Offset[2] = pIO->Tell() - nStart;
3663     nCurves = IsInputMatrix() ? m_nInput : m_nOutput;
3664 
3665     for (i=0; i<nCurves; i++) {
3666       if (!m_CurvesM[i])
3667         return false;
3668 
3669       if (!m_CurvesM[i]->Write(pIO))
3670         return false;
3671 
3672       if (!pIO->Align32())
3673         return false;
3674     }
3675   }
3676 
3677   //CLUT
3678   if (m_CLUT) {
3679     Offset[3] = pIO->Tell() - nStart;
3680 
3681     if (!m_CLUT->Write(pIO))
3682       return false;
3683 
3684     if (!pIO->Align32())
3685       return false;
3686   }
3687 
3688   //A Curves
3689   if (m_CurvesA) {
3690     Offset[4] = pIO->Tell() - nStart;
3691     nCurves = !IsInputB() ? m_nInput : m_nOutput;
3692 
3693     for (i=0; i<nCurves; i++) {
3694       if (!m_CurvesA[i])
3695         return false;
3696 
3697       if (!m_CurvesA[i]->Write(pIO))
3698         return false;
3699 
3700       if (!pIO->Align32())
3701         return false;
3702     }
3703   }
3704 
3705   nEnd = pIO->Tell();
3706 
3707   if (!pIO->Seek(nOffsetPos, icSeekSet))
3708     return false;
3709 
3710   if (pIO->Write32(&Offset[0], 5)!=5)
3711     return false;
3712 
3713   return pIO->Seek(nEnd, icSeekSet)>=0;
3714 }
3715 
3716 
3717 /**
3718 ******************************************************************************
3719 * Name: CIccTagLutAtoB::Validate
3720 *
3721 * Purpose: Check tag data validity.
3722 *
3723 * Args:
3724 *  sig = signature of tag being validated,
3725 *  sReport = String to add report information to
3726 *
3727 * Return:
3728 *  icValidateStatusOK if valid, or other error status.
3729 ******************************************************************************
3730 */
Validate(icTagSignature sig,std::string & sReport,const CIccProfile * pProfile) const3731 icValidateStatus CIccTagLutAtoB::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const
3732 {
3733   icValidateStatus rv = CIccMBB::Validate(sig, sReport, pProfile);
3734 
3735   CIccInfo Info;
3736   std::string sSigName = Info.GetSigName(sig);
3737 
3738   if (!pProfile) {
3739     return rv;
3740   }
3741 
3742   switch(sig) {
3743   case icSigAToB0Tag:
3744   case icSigAToB1Tag:
3745   case icSigAToB2Tag:
3746     {
3747       icUInt32Number nInput = icGetSpaceSamples(pProfile->m_Header.colorSpace);
3748 
3749       icUInt32Number nOutput = icGetSpaceSamples(pProfile->m_Header.pcs);
3750 
3751       icUInt8Number i;
3752       if (m_CurvesB) {
3753         for (i=0; i<nOutput; i++) {
3754           if (m_CurvesB[i]) {
3755             rv = icMaxStatus(rv, m_CurvesB[i]->Validate(sig, sReport, pProfile));
3756           }
3757           else {
3758             sReport += icValidateCriticalErrorMsg;
3759             sReport += sSigName;
3760             sReport += " - Incorrect number of B-curves.\r\n";
3761             rv = icMaxStatus(rv, icValidateCriticalError);
3762           }
3763         }
3764       }
3765 
3766       if (m_CurvesM) {
3767         for (i=0; i<nOutput; i++) {
3768           if (m_CurvesM[i]) {
3769             rv = icMaxStatus(rv, m_CurvesM[i]->Validate(sig, sReport, pProfile));
3770           }
3771           else {
3772             sReport += icValidateCriticalErrorMsg;
3773             sReport += sSigName;
3774             sReport += " - Incorrect number of M-curves.\r\n";
3775             rv = icMaxStatus(rv, icValidateCriticalError);
3776           }
3777         }
3778       }
3779 
3780       if (m_CurvesA) {
3781         if (!m_CLUT) {
3782           sReport += icValidateNonCompliantMsg;
3783           sReport += sSigName;
3784           sReport += " - CLUT must be present if using A-curves.\r\n";
3785 
3786           rv = icMaxStatus(rv, icValidateNonCompliant);
3787         }
3788 
3789         for (i=0; i<nInput; i++) {
3790           if (m_CurvesA[i]) {
3791             rv = icMaxStatus(rv, m_CurvesA[i]->Validate(sig, sReport, pProfile));
3792           }
3793           else {
3794             sReport += icValidateCriticalErrorMsg;
3795             sReport += sSigName;
3796             sReport += " - Incorrect number of A-curves.\r\n";
3797             rv = icMaxStatus(rv, icValidateCriticalError);
3798           }
3799         }
3800 
3801       }
3802 
3803       break;
3804     }
3805   default:
3806     {
3807     }
3808   }
3809 
3810 
3811   return rv;
3812 }
3813 
3814 /**
3815  ****************************************************************************
3816  * Name: CIccTagLutBtoA::CIccTagLutBtoA
3817  *
3818  * Purpose: Constructor
3819  *
3820  *****************************************************************************
3821  */
CIccTagLutBtoA()3822 CIccTagLutBtoA::CIccTagLutBtoA()
3823 {
3824   m_bInputMatrix = true;
3825 }
3826 
3827 
3828 /**
3829  ****************************************************************************
3830  * Name: CIccTagLutBtoA::CIccTagLutBtoA
3831  *
3832  * Purpose: Copy Constructor
3833  *
3834  * Args:
3835  *  ITLB2A = The CIccTagLutBtoA object to be copied
3836  *****************************************************************************
3837  */
CIccTagLutBtoA(const CIccTagLutBtoA & ITLB2A)3838 CIccTagLutBtoA::CIccTagLutBtoA(const CIccTagLutBtoA &ITLB2A) : CIccTagLutAtoB(ITLB2A)
3839 {
3840 }
3841 
3842 
3843 /**
3844  ****************************************************************************
3845  * Name: CIccTagLutBtoA::operator=
3846  *
3847  * Purpose: Copy Operator
3848  *
3849  * Args:
3850  *  ITLB2A = The CIccTagLutBtoA object to be copied
3851  *****************************************************************************
3852  */
operator =(const CIccTagLutBtoA & ITLB2A)3853 CIccTagLutBtoA &CIccTagLutBtoA::operator=(const CIccTagLutBtoA &ITLB2A)
3854 {
3855   if (&ITLB2A == this)
3856     return *this;
3857 
3858   CIccMBB::operator=(ITLB2A);
3859 
3860   return *this;
3861 }
3862 
3863 
3864 /**
3865 ******************************************************************************
3866 * Name: CIccTagLutBtoA::Validate
3867 *
3868 * Purpose: Check tag data validity.
3869 *
3870 * Args:
3871 *  sig = signature of tag being validated,
3872 *  sReport = String to add report information to
3873 *
3874 * Return:
3875 *  icValidateStatusOK if valid, or other error status.
3876 ******************************************************************************
3877 */
Validate(icTagSignature sig,std::string & sReport,const CIccProfile * pProfile) const3878 icValidateStatus CIccTagLutBtoA::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const
3879 {
3880   icValidateStatus rv = CIccMBB::Validate(sig, sReport, pProfile);
3881 
3882   CIccInfo Info;
3883   std::string sSigName = Info.GetSigName(sig);
3884 
3885   if (!pProfile) {
3886     sReport += icValidateWarningMsg;
3887     sReport += sSigName;
3888     sReport += " - Tag validation incomplete: Pointer to profile unavailable.\r\n";
3889     rv = icMaxStatus(rv, icValidateCriticalError);
3890     return rv;
3891   }
3892 
3893   switch(sig) {
3894   case icSigBToA0Tag:
3895   case icSigBToA1Tag:
3896   case icSigBToA2Tag:
3897   case icSigGamutTag:
3898     {
3899       icUInt32Number nInput = icGetSpaceSamples(pProfile->m_Header.pcs);
3900 
3901       icUInt32Number nOutput;
3902       if (sig==icSigGamutTag) {
3903         nOutput = 1;
3904       }
3905       else {
3906         nOutput = icGetSpaceSamples(pProfile->m_Header.colorSpace);
3907       }
3908 
3909       if (m_nOutput!=nOutput) {
3910         sReport += icValidateCriticalErrorMsg;
3911         sReport += sSigName;
3912         sReport += " - Incorrect number of output channels.\r\n";
3913         rv = icMaxStatus(rv, icValidateCriticalError);
3914       }
3915 
3916       icUInt8Number i;
3917       if (m_CurvesB) {
3918         for (i=0; i<nInput; i++) {
3919           if (m_CurvesB[i]) {
3920             rv = icMaxStatus(rv, m_CurvesB[i]->Validate(sig, sReport, pProfile));
3921           }
3922           else {
3923             sReport += icValidateCriticalErrorMsg;
3924             sReport += sSigName;
3925             sReport += " - Incorrect number of B-curves.\r\n";
3926             rv = icMaxStatus(rv, icValidateCriticalError);
3927           }
3928         }
3929       }
3930 
3931       if (m_CurvesM) {
3932         for (i=0; i<nInput; i++) {
3933           if (m_CurvesM[i]) {
3934             rv = icMaxStatus(rv, m_CurvesM[i]->Validate(sig, sReport, pProfile));
3935           }
3936           else {
3937             sReport += icValidateCriticalErrorMsg;
3938             sReport += sSigName;
3939             sReport += " - Incorrect number of M-curves.\r\n";
3940             rv = icMaxStatus(rv, icValidateCriticalError);
3941           }
3942         }
3943       }
3944 
3945       if (m_CurvesA) {
3946         if (!m_CLUT) {
3947           sReport += icValidateNonCompliantMsg;
3948           sReport += sSigName;
3949           sReport += " - CLUT must be present if using A-curves.\r\n";
3950 
3951           rv = icMaxStatus(rv, icValidateNonCompliant);
3952         }
3953 
3954         for (i=0; i<nOutput; i++) {
3955           if (m_CurvesA[i]) {
3956             rv = icMaxStatus(rv, m_CurvesA[i]->Validate(sig, sReport, pProfile));
3957           }
3958           else {
3959             sReport += icValidateCriticalErrorMsg;
3960             sReport += sSigName;
3961             sReport += " - Incorrect number of A-curves.\r\n";
3962             rv = icMaxStatus(rv, icValidateCriticalError);
3963           }
3964         }
3965 
3966       }
3967 
3968       break;
3969     }
3970   default:
3971     {
3972     }
3973   }
3974 
3975 
3976   return rv;
3977 }
3978 
3979 
3980 /**
3981  ****************************************************************************
3982  * Name: CIccTagLut8::CIccTagLut8
3983  *
3984  * Purpose: Constructor
3985  *
3986  *****************************************************************************
3987  */
CIccTagLut8()3988 CIccTagLut8::CIccTagLut8()
3989 {
3990   memset(m_XYZMatrix, 0, sizeof(m_XYZMatrix));
3991   m_XYZMatrix[0] = m_XYZMatrix[4] = m_XYZMatrix[8] = icDtoF(1.0);
3992   m_nReservedByte = 0;
3993 }
3994 
3995 
3996 /**
3997  ****************************************************************************
3998  * Name: CIccTagLut8::CIccTagLut8
3999  *
4000  * Purpose: Copy Constructor
4001  *
4002  * Args:
4003  *  ITL = The CIccTagLut8 object to be copied
4004  *****************************************************************************
4005  */
CIccTagLut8(const CIccTagLut8 & ITL)4006 CIccTagLut8::CIccTagLut8(const CIccTagLut8& ITL) : CIccMBB(ITL)
4007 {
4008   memcpy(&m_XYZMatrix, &ITL.m_XYZMatrix, sizeof(m_XYZMatrix));
4009   m_nReservedByte = 0;
4010 }
4011 
4012 
4013 /**
4014  ****************************************************************************
4015  * Name: CIccTagLut8::operator=
4016  *
4017  * Purpose: Copy Operator
4018  *
4019  * Args:
4020  *  ITL = The CIccTagLut8 object to be copied
4021  *****************************************************************************
4022  */
operator =(const CIccTagLut8 & ITL)4023 CIccTagLut8 &CIccTagLut8::operator=(const CIccTagLut8 &ITL)
4024 {
4025   if (&ITL==this)
4026     return *this;
4027 
4028   CIccMBB::operator=(ITL);
4029   memcpy(&m_XYZMatrix, &ITL.m_XYZMatrix, sizeof(m_XYZMatrix));
4030 
4031   return *this;
4032 }
4033 
4034 
4035 /**
4036  ****************************************************************************
4037  * Name: CIccTagLut8::~CIccTagLut8
4038  *
4039  * Purpose: Destructor
4040  *
4041  *****************************************************************************
4042  */
~CIccTagLut8()4043 CIccTagLut8::~CIccTagLut8()
4044 {
4045 }
4046 
4047 
4048 /**
4049  ****************************************************************************
4050  * Name: CIccTagLut8::Read
4051  *
4052  * Purpose: Read in the tag contents into a data block
4053  *
4054  * Args:
4055  *  size - # of bytes in tag,
4056  *  pIO - IO object to read tag from
4057  *
4058  * Return:
4059  *  true = successful, false = failure
4060  *****************************************************************************
4061  */
Read(icUInt32Number size,CIccIO * pIO)4062 bool CIccTagLut8::Read(icUInt32Number size, CIccIO *pIO)
4063 {
4064   icTagTypeSignature sig;
4065   icUInt32Number nStart, nEnd;
4066   icUInt8Number i, nGrid;
4067   LPIccCurve *pCurves;
4068   CIccTagCurve *pCurve;
4069 
4070   if (size<13*sizeof(icUInt32Number) || !pIO) {
4071     return false;
4072   }
4073 
4074   nStart = pIO->Tell();
4075   nEnd = nStart + size;
4076 
4077   if (!pIO->Read32(&sig) ||
4078       !pIO->Read32(&m_nReserved) ||
4079       !pIO->Read8(&m_nInput) ||
4080       !pIO->Read8(&m_nOutput) ||
4081       !pIO->Read8(&nGrid) ||
4082       !pIO->Read8(&m_nReservedByte) ||
4083       pIO->Read32(m_XYZMatrix, 9) != 9)
4084     return false;
4085 
4086   if (sig!=GetType())
4087     return false;
4088 
4089   //B Curves
4090   pCurves = NewCurvesB();
4091 
4092   for (i=0; i<m_nInput; i++) {
4093     if (256 > nEnd - pIO->Tell())
4094       return false;
4095 
4096     pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType);
4097 
4098     pCurve->SetSize(256);
4099 
4100     if (pIO->Read8Float(&(*pCurve)[0], 256) != 256)
4101       return false;
4102   }
4103 
4104   //CLUT
4105   m_CLUT = new CIccCLUT(m_nInput, m_nOutput);
4106 
4107   m_CLUT->Init(nGrid);
4108 
4109   if (!m_CLUT->ReadData(nEnd - pIO->Tell(), pIO, 1))
4110     return false;
4111 
4112   //A Curves
4113   pCurves = NewCurvesA();
4114 
4115   for (i=0; i<m_nOutput; i++) {
4116     if (256 > nEnd - pIO->Tell())
4117       return false;
4118 
4119     pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType);
4120 
4121     pCurve->SetSize(256);
4122 
4123     if (pIO->Read8Float(&(*pCurve)[0], 256) != 256)
4124       return false;
4125   }
4126   return true;
4127 }
4128 
4129 
4130 /**
4131  ****************************************************************************
4132  * Name: CIccTagLut8::SetColorSpaces
4133  *
4134  * Purpose: Sets the input and output color spaces
4135  *
4136  * Args:
4137  *  csInput = input color space signature,
4138  *  csOutput = output color space signature
4139  *
4140  *****************************************************************************
4141  */
SetColorSpaces(icColorSpaceSignature csInput,icColorSpaceSignature csOutput)4142 void CIccTagLut8::SetColorSpaces(icColorSpaceSignature csInput, icColorSpaceSignature csOutput)
4143 {
4144   if (csInput==icSigXYZData) {
4145     int i;
4146 
4147     if (!m_CurvesM && IsInputMatrix()) { //Transfer ownership of curves
4148       m_CurvesM = m_CurvesB;
4149       m_CurvesB = NULL;
4150 
4151       LPIccCurve *pCurves = NewCurvesB();
4152       CIccTagCurve *pCurve;
4153       for (i=0; i<m_nInput; i++) {
4154         pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType);
4155         pCurve->SetSize(0);
4156       }
4157 
4158       m_bUseMCurvesAsBCurves = true;
4159     }
4160 
4161     if (!m_Matrix) {
4162       CIccMatrix *pMatrix = NewMatrix();
4163       for (i=0; i<9; i++) {
4164         pMatrix->m_e[i] = icFtoD(m_XYZMatrix[i]);
4165       }
4166 
4167       pMatrix->m_bUseConstants=false;
4168     }
4169   }
4170   else {
4171     m_XYZMatrix[0] = m_XYZMatrix[4] = m_XYZMatrix[8] = icDtoF(1.0);
4172     m_XYZMatrix[1] = m_XYZMatrix[2] = m_XYZMatrix[3] =
4173     m_XYZMatrix[5] = m_XYZMatrix[6] = m_XYZMatrix[7] = 0;
4174   }
4175 
4176   CIccMBB::SetColorSpaces(csInput, csOutput);
4177 }
4178 
4179 
4180 /**
4181  ****************************************************************************
4182  * Name: CIccTagLut8::Write
4183  *
4184  * Purpose: Write the tag to a file
4185  *
4186  * Args:
4187  *  pIO - The IO object to write tag to.
4188  *
4189  * Return:
4190  *  true = succesful, false = failure
4191  *****************************************************************************
4192  */
Write(CIccIO * pIO)4193 bool CIccTagLut8::Write(CIccIO *pIO)
4194 {
4195   icTagTypeSignature sig = GetType();
4196   icUInt8Number i, nGrid;
4197   icS15Fixed16Number XYZMatrix[9];
4198   icUInt16Number nInputEntries, nOutputEntries;
4199   LPIccCurve *pCurves;
4200   CIccTagCurve *pCurve;
4201   icFloat32Number v;
4202 
4203   if (m_Matrix) {
4204     for (i=0; i<9; i++)
4205       XYZMatrix[i] = icDtoF(m_Matrix->m_e[i]);
4206   }
4207   else {
4208     memset(XYZMatrix, 0, 9*sizeof(icS15Fixed16Number));
4209     XYZMatrix[0] = XYZMatrix[4] = XYZMatrix[8] = icDtoF(1.0);
4210   }
4211 
4212   if (m_bUseMCurvesAsBCurves) {
4213     pCurves = m_CurvesM;
4214   }
4215   else {
4216     pCurves = m_CurvesB;
4217   }
4218 
4219   if (!pCurves || !m_CurvesA || !m_CLUT)
4220     return false;
4221 
4222   nGrid = m_CLUT->GridPoints();
4223 
4224   nInputEntries = (icUInt16Number)(((CIccTagCurve*)pCurves[0])->GetSize());
4225   nOutputEntries = (icUInt16Number)(((CIccTagCurve*)m_CurvesA[0])->GetSize());
4226 
4227   if (!pIO->Write32(&sig) ||
4228       !pIO->Write32(&m_nReserved) ||
4229       !pIO->Write8(&m_nInput) ||
4230       !pIO->Write8(&m_nOutput) ||
4231       !pIO->Write8(&nGrid) ||
4232       !pIO->Write8(&m_nReservedByte) ||
4233       pIO->Write32(XYZMatrix, 9) != 9)
4234     return false;
4235 
4236   //B Curves
4237   for (i=0; i<m_nInput; i++) {
4238     if (pCurves[i]->GetType()!=icSigCurveType)
4239       return false;
4240 
4241     pCurve = (CIccTagCurve*)pCurves[i];
4242     if (!pCurve)
4243       return false;
4244 
4245     if (pCurve->GetSize()!=256) {
4246       icUInt32Number j;
4247 
4248       for (j=0; j<256; j++) {
4249         v = pCurve->Apply((icFloat32Number)j / 255.0F);
4250         if (!pIO->Write8Float(&v, 1))
4251           return false;
4252       }
4253     }
4254     else {
4255       if (pIO->Write8Float(&(*pCurve)[0], 256)!=256)
4256         return false;
4257     }
4258   }
4259 
4260   //CLUT
4261   if (!m_CLUT->WriteData(pIO, 1))
4262     return false;
4263 
4264   //A Curves
4265   pCurves = m_CurvesA;
4266 
4267   for (i=0; i<m_nOutput; i++) {
4268     if (pCurves[i]->GetType()!=icSigCurveType)
4269       return false;
4270 
4271     pCurve = (CIccTagCurve*)pCurves[i];
4272 
4273     if (!pCurve)
4274       return false;
4275 
4276     if (pCurve->GetSize()!=256) {
4277       icUInt32Number j;
4278 
4279       for (j=0; j<256; j++) {
4280         v = pCurve->Apply((icFloat32Number)j / 255.0F);
4281         if (!pIO->Write8Float(&v, 1))
4282           return false;
4283       }
4284     }
4285     else {
4286       if (pIO->Write8Float(&(*pCurve)[0], 256)!=256)
4287         return false;
4288     }
4289   }
4290   return true;
4291 }
4292 
4293 
4294 /**
4295 ******************************************************************************
4296 * Name: CIccTagLut8::Validate
4297 *
4298 * Purpose: Check tag data validity.
4299 *
4300 * Args:
4301 *  sig = signature of tag being validated,
4302 *  sReport = String to add report information to
4303 *
4304 * Return:
4305 *  icValidateStatusOK if valid, or other error status.
4306 ******************************************************************************
4307 */
Validate(icTagSignature sig,std::string & sReport,const CIccProfile * pProfile) const4308 icValidateStatus CIccTagLut8::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const
4309 {
4310   icValidateStatus rv = CIccMBB::Validate(sig, sReport, pProfile);
4311 
4312   CIccInfo Info;
4313   std::string sSigName = Info.GetSigName(sig);
4314 
4315   if (!pProfile) {
4316     return rv;
4317   }
4318 
4319   switch(sig) {
4320   case icSigAToB0Tag:
4321   case icSigAToB1Tag:
4322   case icSigAToB2Tag:
4323   case icSigBToA0Tag:
4324   case icSigBToA1Tag:
4325   case icSigBToA2Tag:
4326   case icSigGamutTag:
4327     {
4328       icUInt32Number nInput, nOutput;
4329       if (sig==icSigAToB0Tag || sig==icSigAToB1Tag || sig==icSigAToB2Tag || sig==icSigGamutTag) {
4330         nInput = icGetSpaceSamples(pProfile->m_Header.pcs);
4331         nOutput = icGetSpaceSamples(pProfile->m_Header.colorSpace);
4332       }
4333       else {
4334         nInput = icGetSpaceSamples(pProfile->m_Header.colorSpace);
4335         nOutput = icGetSpaceSamples(pProfile->m_Header.pcs);
4336       }
4337 
4338       if (sig==icSigGamutTag) {
4339         nOutput = 1;
4340       }
4341 
4342       icUInt8Number i;
4343       if (m_CurvesB) {
4344         for (i=0; i<nInput; i++) {
4345           if (m_CurvesB[i]) {
4346             rv = icMaxStatus(rv, m_CurvesB[i]->Validate(sig, sReport, pProfile));
4347             if (m_CurvesB[i]->GetType()==icSigCurveType) {
4348               CIccTagCurve *pTagCurve = (CIccTagCurve*)m_CurvesB[i];
4349               if (pTagCurve->GetSize()==1) {
4350                 sReport += icValidateCriticalErrorMsg;
4351                 sReport += sSigName;
4352                 sReport += " - lut8Tags do not support single entry gamma curves.\r\n";
4353                 rv = icMaxStatus(rv, icValidateCriticalError);
4354               }
4355             }
4356           }
4357           else {
4358             sReport += icValidateCriticalErrorMsg;
4359             sReport += sSigName;
4360             sReport += " - Incorrect number of B-curves.\r\n";
4361             rv = icMaxStatus(rv, icValidateCriticalError);
4362           }
4363         }
4364       }
4365 
4366       if (m_Matrix) {
4367         rv = icMaxStatus(rv, m_Matrix->Validate(GetType(), sReport, pProfile));
4368       }
4369       else {
4370         int sum=0;
4371         for (int i=0; i<9; i++) {
4372           sum += m_XYZMatrix[i];
4373         }
4374         if (m_XYZMatrix[0]!=1.0 || m_XYZMatrix[4]!=1.0 || m_XYZMatrix[8]!=1.0 || sum!=3.0) {
4375           sReport += icValidateWarningMsg;
4376           sReport += sSigName;
4377           sReport += " - Matrix must be identity.\r\n";
4378           rv = icMaxStatus(rv, icValidateWarning);
4379         }
4380       }
4381 
4382       if (m_CurvesA) {
4383 
4384         for (i=0; i<nOutput; i++) {
4385           if (m_CurvesA[i]) {
4386             rv = icMaxStatus(rv, m_CurvesA[i]->Validate(sig, sReport, pProfile));
4387             if (m_CurvesA[i]->GetType()==icSigCurveType) {
4388               CIccTagCurve *pTagCurve = (CIccTagCurve*)m_CurvesA[i];
4389               if (pTagCurve->GetSize()==1) {
4390                 sReport += icValidateCriticalErrorMsg;
4391                 sReport += sSigName;
4392                 sReport += " - lut8Tags do not support single entry gamma curves.\r\n";
4393                 rv = icMaxStatus(rv, icValidateCriticalError);
4394               }
4395             }
4396           }
4397           else {
4398             sReport += icValidateCriticalErrorMsg;
4399             sReport += sSigName;
4400             sReport += " - Incorrect number of A-curves.\r\n";
4401             rv = icMaxStatus(rv, icValidateCriticalError);
4402           }
4403         }
4404 
4405       }
4406 
4407       break;
4408     }
4409   default:
4410     {
4411     }
4412   }
4413 
4414 
4415   return rv;
4416 }
4417 
4418 
4419 /**
4420  ****************************************************************************
4421  * Name: CIccTagLut16::CIccTagLut16
4422  *
4423  * Purpose: Constructor
4424  *
4425  *****************************************************************************
4426  */
CIccTagLut16()4427 CIccTagLut16::CIccTagLut16()
4428 {
4429   memset(m_XYZMatrix, 0, sizeof(m_XYZMatrix));
4430   m_XYZMatrix[0] = m_XYZMatrix[4] = m_XYZMatrix[8] = icDtoF(1.0);
4431   m_nReservedByte = 0;
4432 }
4433 
4434 
4435 /**
4436  ****************************************************************************
4437  * Name: CIccTagLut16::CIccTagLut16
4438  *
4439  * Purpose: Copy Constructor
4440  *
4441  * Args:
4442  *  ITL = The CIccTagUnknown object to be copied
4443  *****************************************************************************
4444  */
CIccTagLut16(const CIccTagLut16 & ITL)4445 CIccTagLut16::CIccTagLut16(const CIccTagLut16& ITL) : CIccMBB(ITL)
4446 {
4447   memcpy(&m_XYZMatrix, &ITL.m_XYZMatrix, sizeof(m_XYZMatrix));
4448   m_nReservedByte = 0;
4449 }
4450 
4451 
4452 /**
4453  ****************************************************************************
4454  * Name: CIccTagLut16::operator=
4455  *
4456  * Purpose: Copy Operator
4457  *
4458  * Args:
4459  *  ITL = The CIccTagLut16 object to be copied
4460  *****************************************************************************
4461  */
operator =(const CIccTagLut16 & ITL)4462 CIccTagLut16 &CIccTagLut16::operator=(const CIccTagLut16 &ITL)
4463 {
4464   if (&ITL==this)
4465     return *this;
4466 
4467   CIccMBB::operator=(ITL);
4468   memcpy(&m_XYZMatrix, &ITL.m_XYZMatrix, sizeof(m_XYZMatrix));
4469 
4470   return *this;
4471 }
4472 
4473 
4474 /**
4475  ****************************************************************************
4476  * Name: CIccTagLut16::~CIccTagLut16
4477  *
4478  * Purpose: Destructor
4479  *
4480  *****************************************************************************
4481  */
~CIccTagLut16()4482 CIccTagLut16::~CIccTagLut16()
4483 {
4484 }
4485 
4486 
4487 /**
4488  ****************************************************************************
4489  * Name: CIccTagLut16::Read
4490  *
4491  * Purpose: Read in the tag contents into a data block
4492  *
4493  * Args:
4494  *  size - # of bytes in tag,
4495  *  pIO - IO object to read tag from
4496  *
4497  * Return:
4498  *  true = successful, false = failure
4499  *****************************************************************************
4500  */
Read(icUInt32Number size,CIccIO * pIO)4501 bool CIccTagLut16::Read(icUInt32Number size, CIccIO *pIO)
4502 {
4503   icTagTypeSignature sig;
4504   icUInt32Number nStart, nEnd;
4505   icUInt8Number i, nGrid;
4506   icUInt16Number nInputEntries, nOutputEntries;
4507   LPIccCurve *pCurves;
4508   CIccTagCurve *pCurve;
4509 
4510   if (size<13*sizeof(icUInt32Number) || !pIO) {
4511     return false;
4512   }
4513 
4514   nStart = pIO->Tell();
4515   nEnd = nStart + size;
4516 
4517   if (!pIO->Read32(&sig) ||
4518       !pIO->Read32(&m_nReserved) ||
4519       !pIO->Read8(&m_nInput) ||
4520       !pIO->Read8(&m_nOutput) ||
4521       !pIO->Read8(&nGrid) ||
4522       !pIO->Read8(&m_nReservedByte) ||
4523       pIO->Read32(m_XYZMatrix, 9) != 9 ||
4524       !pIO->Read16(&nInputEntries) ||
4525       !pIO->Read16(&nOutputEntries))
4526     return false;
4527 
4528   if (sig!=GetType())
4529     return false;
4530 
4531 
4532   //B Curves
4533   pCurves = NewCurvesB();
4534 
4535   for (i=0; i<m_nInput; i++) {
4536     if (nInputEntries*sizeof(icUInt16Number) > nEnd - pIO->Tell())
4537       return false;
4538 
4539     pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType);
4540 
4541     pCurve->SetSize(nInputEntries);
4542 
4543     if (pIO->Read16Float(&(*pCurve)[0], nInputEntries) != nInputEntries)
4544       return false;
4545   }
4546 
4547   //CLUT
4548   m_CLUT = new CIccCLUT(m_nInput, m_nOutput);
4549 
4550   m_CLUT->Init(nGrid);
4551 
4552   if (!m_CLUT->ReadData(nEnd - pIO->Tell(), pIO, 2))
4553     return false;
4554 
4555   //A Curves
4556   pCurves = NewCurvesA();
4557 
4558   for (i=0; i<m_nOutput; i++) {
4559     if (nOutputEntries*sizeof(icUInt16Number) > nEnd - pIO->Tell())
4560       return false;
4561 
4562     pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType);
4563 
4564     pCurve->SetSize(nOutputEntries);
4565 
4566     if (pIO->Read16Float(&(*pCurve)[0], nOutputEntries) != nOutputEntries)
4567       return false;
4568   }
4569   return true;
4570 }
4571 
4572 
4573 /**
4574  ****************************************************************************
4575  * Name: CIccTagLut16::SetColorSpaces
4576  *
4577  * Purpose: Sets the input and output color spaces
4578  *
4579  * Args:
4580  *  csInput = input color space signature,
4581  *  csOutput = output color space signature
4582  *
4583  *****************************************************************************
4584  */
SetColorSpaces(icColorSpaceSignature csInput,icColorSpaceSignature csOutput)4585 void CIccTagLut16::SetColorSpaces(icColorSpaceSignature csInput, icColorSpaceSignature csOutput)
4586 {
4587   if (csInput==icSigXYZData) {
4588     int i;
4589 
4590     if (!m_CurvesM && IsInputMatrix()) { //Transfer ownership of curves
4591       m_CurvesM = m_CurvesB;
4592       m_CurvesB = NULL;
4593 
4594       LPIccCurve *pCurves = NewCurvesB();
4595       CIccTagCurve *pCurve;
4596       for (i=0; i<m_nInput; i++) {
4597         pCurves[i] = pCurve = (CIccTagCurve*)CIccTag::Create(icSigCurveType);
4598         pCurve->SetSize(0);
4599       }
4600 
4601       m_bUseMCurvesAsBCurves = true;
4602     }
4603 
4604     if (!m_Matrix) {
4605       CIccMatrix *pMatrix = NewMatrix();
4606       for (i=0; i<9; i++) {
4607         pMatrix->m_e[i] = icFtoD(m_XYZMatrix[i]);
4608       }
4609 
4610       pMatrix->m_bUseConstants=false;
4611     }
4612   }
4613   else {
4614     m_XYZMatrix[0] = m_XYZMatrix[4] = m_XYZMatrix[8] = icDtoF(1.0);
4615     m_XYZMatrix[1] = m_XYZMatrix[2] = m_XYZMatrix[3] =
4616     m_XYZMatrix[5] = m_XYZMatrix[6] = m_XYZMatrix[7] = 0;
4617   }
4618 
4619   CIccMBB::SetColorSpaces(csInput, csOutput);
4620 }
4621 
4622 
4623 /**
4624  ****************************************************************************
4625  * Name: CIccTagLut16::Write
4626  *
4627  * Purpose: Write the tag to a file
4628  *
4629  * Args:
4630  *  pIO - The IO object to write tag to.
4631  *
4632  * Return:
4633  *  true = succesful, false = failure
4634  *****************************************************************************
4635  */
Write(CIccIO * pIO)4636 bool CIccTagLut16::Write(CIccIO *pIO)
4637 {
4638   icTagTypeSignature sig = GetType();
4639   icUInt8Number i, nGrid;
4640   icS15Fixed16Number XYZMatrix[9];
4641   icUInt16Number nInputEntries, nOutputEntries;
4642   LPIccCurve *pCurves;
4643   CIccTagCurve *pCurve;
4644 
4645   if (m_Matrix) {
4646     for (i=0; i<9; i++) {
4647       XYZMatrix[i] = icDtoF(m_Matrix->m_e[i]);
4648     }
4649   }
4650   else {
4651     memset(XYZMatrix, 0, 9*sizeof(icS15Fixed16Number));
4652     XYZMatrix[0] = XYZMatrix[4] = XYZMatrix[8] = icDtoF(1.0);
4653   }
4654 
4655   if (m_bUseMCurvesAsBCurves) {
4656     pCurves = m_CurvesM;
4657   }
4658   else {
4659     pCurves = m_CurvesB;
4660   }
4661 
4662   if (!pCurves || !m_CurvesA || !m_CLUT)
4663     return false;
4664 
4665   nGrid = m_CLUT->GridPoints();
4666 
4667   nInputEntries = (icUInt16Number)(((CIccTagCurve*)pCurves[0])->GetSize());
4668   nOutputEntries = (icUInt16Number)(((CIccTagCurve*)m_CurvesA[0])->GetSize());
4669 
4670   if (!pIO->Write32(&sig) ||
4671       !pIO->Write32(&m_nReserved) ||
4672       !pIO->Write8(&m_nInput) ||
4673       !pIO->Write8(&m_nOutput) ||
4674       !pIO->Write8(&nGrid) ||
4675       !pIO->Write8(&m_nReservedByte) ||
4676       pIO->Write32(XYZMatrix, 9) != 9 ||
4677       !pIO->Write16(&nInputEntries) ||
4678       !pIO->Write16(&nOutputEntries))
4679     return false;
4680 
4681   //B Curves
4682   for (i=0; i<m_nInput; i++) {
4683     if (pCurves[i]->GetType()!=icSigCurveType)
4684       return false;
4685 
4686     pCurve = (CIccTagCurve*)pCurves[i];
4687     if (!pCurve)
4688       return false;
4689 
4690     if (pIO->Write16Float(&(*pCurve)[0], nInputEntries) != nInputEntries)
4691       return false;
4692   }
4693 
4694   //CLUT
4695   if (!m_CLUT->WriteData(pIO, 2))
4696     return false;
4697 
4698   //A Curves
4699   pCurves = m_CurvesA;
4700 
4701   for (i=0; i<m_nOutput; i++) {
4702     if (pCurves[i]->GetType()!=icSigCurveType)
4703       return false;
4704 
4705     pCurve = (CIccTagCurve*)pCurves[i];
4706 
4707     if (pIO->Write16Float(&(*pCurve)[0], nOutputEntries) != nOutputEntries)
4708       return false;
4709   }
4710   return true;
4711 }
4712 
4713 
4714 /**
4715 ******************************************************************************
4716 * Name: CIccTagLut16::Validate
4717 *
4718 * Purpose: Check tag data validity.
4719 *
4720 * Args:
4721 *  sig = signature of tag being validated,
4722 *  sReport = String to add report information to
4723 *
4724 * Return:
4725 *  icValidateStatusOK if valid, or other error status.
4726 ******************************************************************************
4727 */
Validate(icTagSignature sig,std::string & sReport,const CIccProfile * pProfile) const4728 icValidateStatus CIccTagLut16::Validate(icTagSignature sig, std::string &sReport, const CIccProfile* pProfile/*=NULL*/) const
4729 {
4730   icValidateStatus rv = CIccMBB::Validate(sig, sReport, pProfile);
4731 
4732   CIccInfo Info;
4733   std::string sSigName = Info.GetSigName(sig);
4734 
4735   if (!pProfile) {
4736     rv = icMaxStatus(rv, icValidateWarning);
4737     return rv;
4738   }
4739 
4740   switch(sig) {
4741   case icSigAToB0Tag:
4742   case icSigAToB1Tag:
4743   case icSigAToB2Tag:
4744   case icSigBToA0Tag:
4745   case icSigBToA1Tag:
4746   case icSigBToA2Tag:
4747   case icSigGamutTag:
4748     {
4749       icUInt32Number nInput, nOutput;
4750       if (sig==icSigAToB0Tag || sig==icSigAToB1Tag || sig==icSigAToB2Tag || sig==icSigGamutTag) {
4751         nInput = icGetSpaceSamples(pProfile->m_Header.pcs);
4752         nOutput = icGetSpaceSamples(pProfile->m_Header.colorSpace);
4753       }
4754       else {
4755         nInput = icGetSpaceSamples(pProfile->m_Header.colorSpace);
4756         nOutput = icGetSpaceSamples(pProfile->m_Header.pcs);
4757       }
4758 
4759       if (sig==icSigGamutTag) {
4760         nOutput = 1;
4761       }
4762 
4763       icUInt8Number i;
4764       if (m_CurvesB) {
4765         for (i=0; i<nInput; i++) {
4766           if (m_CurvesB[i]) {
4767             rv = icMaxStatus(rv, m_CurvesB[i]->Validate(sig, sReport, pProfile));
4768             if (m_CurvesB[i]->GetType()==icSigCurveType) {
4769               CIccTagCurve *pTagCurve = (CIccTagCurve*)m_CurvesB[i];
4770               if (pTagCurve->GetSize()==1) {
4771                 sReport += icValidateCriticalErrorMsg;
4772                 sReport += sSigName;
4773                 sReport += " - lut16Tags do not support single entry gamma curves.\r\n";
4774                 rv = icMaxStatus(rv, icValidateCriticalError);
4775               }
4776             }
4777           }
4778           else {
4779             sReport += icValidateCriticalErrorMsg;
4780             sReport += sSigName;
4781             sReport += " - Incorrect number of B-curves.\r\n";
4782             rv = icMaxStatus(rv, icValidateCriticalError);
4783           }
4784         }
4785       }
4786 
4787       if (m_Matrix) {
4788         rv = icMaxStatus(rv, m_Matrix->Validate(GetType(), sReport, pProfile));
4789       }
4790       else {
4791         int sum=0;
4792         for (int i=0; i<9; i++) {
4793           sum += m_XYZMatrix[i];
4794         }
4795         if (m_XYZMatrix[0]!=1.0 || m_XYZMatrix[4]!=1.0 || m_XYZMatrix[8]!=1.0 || sum!=3.0) {
4796           sReport += icValidateWarningMsg;
4797           sReport += sSigName;
4798           sReport += " - Matrix must be identity.\r\n";
4799           rv = icMaxStatus(rv, icValidateWarning);
4800         }
4801       }
4802 
4803       if (m_CurvesA) {
4804 
4805         for (i=0; i<nOutput; i++) {
4806           if (m_CurvesA[i]) {
4807             rv = icMaxStatus(rv, m_CurvesA[i]->Validate(sig, sReport, pProfile));
4808             if (m_CurvesA[i]->GetType()==icSigCurveType) {
4809               CIccTagCurve *pTagCurve = (CIccTagCurve*)m_CurvesA[i];
4810               if (pTagCurve->GetSize()==1) {
4811                 sReport += icValidateCriticalErrorMsg;
4812                 sReport += sSigName;
4813                 sReport += " - lut16Tags do not support single entry gamma curves.\r\n";
4814                 rv = icMaxStatus(rv, icValidateCriticalError);
4815               }
4816             }
4817           }
4818           else {
4819             sReport += icValidateCriticalErrorMsg;
4820             sReport += sSigName;
4821             sReport += " - Incorrect number of A-curves.\r\n";
4822             rv = icMaxStatus(rv, icValidateCriticalError);
4823           }
4824         }
4825 
4826       }
4827 
4828       break;
4829     }
4830   default:
4831     {
4832     }
4833   }
4834 
4835 
4836   return rv;
4837 }
4838 
4839 
4840 #ifdef USESAMPLEICCNAMESPACE
4841 } //namespace sampleICC
4842 #endif
4843