Hoyt's FORK of DemoIccMAX 2.1.17.hoyt
Documentation for Hoyt's FORK of DemoIccMAX
Loading...
Searching...
No Matches
IccProfile.cpp
Go to the documentation of this file.
1/** @file
2 File: IccProfile.cpp
3
4 Contains: Implementation of the CIccProfile class.
5
6 Version: V1
7
8 Copyright: � see ICC Software License
9*/
10
11/*
12 * The ICC Software License, Version 0.2
13 *
14 *
15 * Copyright (c) 2003-2012 The International Color Consortium. All rights
16 * reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 *
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 *
25 * 2. Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in
27 * the documentation and/or other materials provided with the
28 * distribution.
29 *
30 * 3. In the absence of prior written permission, the names "ICC" and "The
31 * International Color Consortium" must not be used to imply that the
32 * ICC organization endorses or promotes products derived from this
33 * software.
34 *
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
40 * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the The International Color Consortium.
52 *
53 *
54 * Membership in the ICC is encouraged when this software is used for
55 * commercial purposes.
56 *
57 *
58 * For more information on The International Color Consortium, please
59 * see <http://www.color.org/>.
60 *
61 *
62 */
63
64//////////////////////////////////////////////////////////////////////
65// HISTORY:
66//
67// -Initial implementation by Max Derhak 5-15-2003
68//
69//////////////////////////////////////////////////////////////////////
70
71#ifdef WIN32
72 #pragma warning( disable: 4786) //disable warning in <list.h>
73#endif
74#include <ctime>
75#include <cstring>
76#include <cmath>
77#include "IccProfile.h"
78#include "IccTag.h"
79#include "IccArrayBasic.h"
80#include "IccIO.h"
81#include "IccUtil.h"
82#include "IccMatrixMath.h"
83#include "IccMD5.h"
84
85
86#ifdef USEREFICCMAXNAMESPACE
87namespace refIccMAX {
88#endif
89
90//////////////////////////////////////////////////////////////////////
91// Construction/Destruction
92//////////////////////////////////////////////////////////////////////
93
94/**
95 **************************************************************************
96 * Name: CIccProfile::CIccProfile
97 *
98 * Purpose:
99 * Constructor
100 **************************************************************************
101 */
102CIccProfile::CIccProfile()
103{
104 m_pAttachIO = NULL;
105 memset(&m_Header, 0, sizeof(m_Header));
106 m_Tags = new(TagEntryList);
107 m_TagVals = new(TagPtrList);
108}
109
110/**
111 **************************************************************************
112 * Name: CIccProfile::CIccProfile
113 *
114 * Purpose:
115 * Copy Constructor. The copy constructor makes the copy of the
116 * CIccProfile object in it's present state. It DOES NOT make a
117 * copy of the m_pAttachIO member variable. Any operation with the
118 * IO object should be done before making a copy.
119 *
120 * Args:
121 * Profile = CIccProfile object which is to be copied.
122 **************************************************************************
123 */
124CIccProfile::CIccProfile(const CIccProfile &Profile)
125{
126 m_pAttachIO = NULL;
127 memset(&m_Header, 0, sizeof(m_Header));
128 m_Tags = new(TagEntryList);
129 m_TagVals = new(TagPtrList);
130 memcpy(&m_Header, &Profile.m_Header, sizeof(m_Header));
131
132 if (!Profile.m_TagVals->empty()) {
133 TagPtrList::const_iterator i;
134 IccTagPtr tagptr = {0};
135 for (i=Profile.m_TagVals->begin(); i!=Profile.m_TagVals->end(); i++) {
136 tagptr.ptr = i->ptr->NewCopy();
137 m_TagVals->push_back(tagptr);
138 }
139 }
140
141 if (!Profile.m_Tags->empty()) {
142 TagEntryList::const_iterator i;
143 IccTagEntry entry = {};
144 for (i=Profile.m_Tags->begin(); i!=Profile.m_Tags->end(); i++) {
145 TagPtrList::const_iterator j, k;
146
147 //Make sure that tag entry values point to shared tags in m_TagVals
148 for (j=Profile.m_TagVals->begin(), k=m_TagVals->begin(); j!=Profile.m_TagVals->end() && k!=m_TagVals->end(); j++, k++) {
149 if (i->pTag == j->ptr) {
150 //k should point to the the corresponding copied tag
151 entry.pTag = k->ptr;
152 break;
153 }
154 }
155
156 if (j==Profile.m_TagVals->end()) { //Did we not find the tag?
157 entry.pTag = NULL;
158 }
159
160 memcpy(&entry.TagInfo, &i->TagInfo, sizeof(icTag));
161 m_Tags->push_back(entry);
162 }
163 }
164
165 m_pAttachIO = NULL;
166}
167
168/**
169 **************************************************************************
170 * Name: CIccProfile::operator=
171 *
172 * Purpose:
173 * Copy Operator. The copy operator makes the copy of the
174 * CIccProfile object in it's present state. It DOES NOT make a
175 * copy of the m_pAttachIO member variable. Any operation with the
176 * IO object should be done before making a copy.
177 *
178 * Args:
179 * Profile = CIccProfile object which is to be copied.
180 **************************************************************************
181 */
182CIccProfile &CIccProfile::operator=(const CIccProfile &Profile)
183{
184 if (&Profile == this)
185 return *this;
186
187 Cleanup();
188
189 memcpy(&m_Header, &Profile.m_Header, sizeof(m_Header));
190
191 if (!Profile.m_TagVals->empty()) {
192 TagPtrList::const_iterator i;
193 IccTagPtr tagptr = {0};
194 for (i=Profile.m_TagVals->begin(); i!=Profile.m_TagVals->end(); i++) {
195 tagptr.ptr = i->ptr->NewCopy();
196 m_TagVals->push_back(tagptr);
197 }
198 }
199
200 if (!Profile.m_Tags->empty()) {
201 TagEntryList::const_iterator i;
202 IccTagEntry entry = {};
203 for (i=Profile.m_Tags->begin(); i!=Profile.m_Tags->end(); i++) {
204 TagPtrList::const_iterator j, k;
205
206 //Make sure that tag entry values point to shared tags in m_TagVals
207 for (j=Profile.m_TagVals->begin(), k=m_TagVals->begin(); j!=Profile.m_TagVals->end() && k!=m_TagVals->end(); j++, k++) {
208 if (i->pTag == j->ptr) {
209 //k should point to the the corresponding copied tag
210 entry.pTag = k->ptr;
211 break;
212 }
213 }
214
215 if (j==Profile.m_TagVals->end()) { //Did we not find the tag?
216 entry.pTag = NULL;
217 }
218
219 memcpy(&entry.TagInfo, &i->TagInfo, sizeof(icTag));
220 m_Tags->push_back(entry);
221 }
222 }
223
224 m_pAttachIO = NULL;
225
226 return *this;
227}
228
229/**
230 **************************************************************************
231 * Name: CIccProfile::CIccProfile
232 *
233 * Purpose:
234 * Destructor
235 **************************************************************************
236 */
237CIccProfile::~CIccProfile()
238{
239 Cleanup();
240
241 delete m_Tags;
242 delete m_TagVals;
243}
244
245/**
246 ***************************************************************************
247 * Name: CIccProfile::Cleanup
248 *
249 * Purpose: Detach from a pending IO object
250 ***************************************************************************
251 */
252void CIccProfile::Cleanup()
253{
254 if (m_pAttachIO) {
255 delete m_pAttachIO;
256 m_pAttachIO = NULL;
257 }
258
259 TagPtrList::iterator i;
260
261 for (i=m_TagVals->begin(); i!=m_TagVals->end(); i++) {
262 if (NULL != i->ptr)
263 delete i->ptr;
264 }
265 m_Tags->clear();
266 m_TagVals->clear();
267 memset(&m_Header, 0, sizeof(m_Header));
268}
269
270/**
271 ****************************************************************************
272 * Name: CIccProfile::GetTag
273 *
274 * Purpose: Get a tag entry with a given signature
275 *
276 * Args:
277 * sig - signature id to find in tag directory
278 *
279 * Return:
280 * Pointer to desired tag directory entry, or NULL if not found.
281 *****************************************************************************
282 */
283IccTagEntry* CIccProfile::GetTag(icSignature sig) const
284{
285 TagEntryList::const_iterator i;
286
287 for (i=m_Tags->begin(); i!=m_Tags->end(); i++) {
288 if (i->TagInfo.sig==(icTagSignature)sig)
289 return (IccTagEntry*)&(i->TagInfo);
290 }
291
292 return NULL;
293}
294
295
296/**
297 ******************************************************************************
298 * Name: CIccProfile::AreTagsUnique
299 *
300 * Purpose: For each tag it checks to see if any other tags have the same
301 * signature.
302 *
303 *
304 * Return:
305 * true if all tags have unique signatures, or false if there are duplicate
306 * tag signatures.
307 *******************************************************************************
308 */
309bool CIccProfile::AreTagsUnique() const
310{
311 TagEntryList::const_iterator i, j;
312
313 for (i=m_Tags->begin(); i!=m_Tags->end(); i++) {
314 j=i;
315 for (j++; j!= m_Tags->end(); j++) {
316 if (i->TagInfo.sig == j->TagInfo.sig)
317 return false;
318 }
319 }
320
321 return true;
322}
323
324
325/**
326******************************************************************************
327* Name: CIccProfile::GetTag
328*
329* Purpose: Finds the first tag entry that points to the indicated tag object
330*
331* Args:
332* pTag - pointer to tag object desired to be found
333*
334* Return:
335* pointer to first tag directory entry that points to the desired tag object,
336* or NULL if tag object is not pointed to by any tag directory entries.
337*******************************************************************************
338*/
339IccTagEntry* CIccProfile::GetTag(CIccTag *pTag) const
340{
341 TagEntryList::const_iterator i;
342
343 for (i=m_Tags->begin(); i!=m_Tags->end(); i++) {
344 if (i->pTag==pTag)
345 return (IccTagEntry*)&(i->TagInfo);
346 }
347
348 return NULL;
349}
350
351
352/**
353 ******************************************************************************
354 * Name: CIccProfile::FindTag
355 *
356 * Purpose: Finds the tag object associated with the directory entry with the
357 * given signature. If the profile object is attached to an IO object then
358 * the tag may need to be loaded first.
359 *
360 * Args:
361 * sig - tag signature to find in profile
362 *
363 * Return:
364 * The desired tag object, or NULL if unable to find in the directory or load
365 * tag object.
366 *******************************************************************************
367 */
368CIccTag* CIccProfile::FindTag(icSignature sig)
369{
370 IccTagEntry *pEntry = GetTag(sig);
371
372 if (pEntry) {
373 if (!pEntry->pTag && m_pAttachIO)
374 LoadTag(pEntry, m_pAttachIO);
375 return pEntry->pTag;
376 }
377
378 return NULL;
379}
380
381
382/**
383 ******************************************************************************
384 * Name: CIccProfile::FindTagConst
385 *
386 * Purpose: Finds the loaded tag object associated with the directory entry
387 * with the given signature.
388 *
389 * Args:
390 * sig - tag signature to find in profile
391 *
392 * Return:
393 * The desired tag object, or NULL if unable to find the loaded tag.
394 *******************************************************************************
395 */
396const CIccTag* CIccProfile::FindTagConst (icSignature sig) const
397{
398 IccTagEntry* pEntry = GetTag(sig);
399
400 if (pEntry) {
401 return pEntry->pTag;
402 }
403
404 return NULL;
405}
406
407
408/**
409 ******************************************************************************
410 * Name: CIccProfile::FindTagOfType
411 *
412 * Purpose: Finds the tag object associated with the directory entry with the
413 * given signature that has a given tag type signature..
414 * If the profile object is attached to an IO object then the tag may need to
415 * be loaded first.
416 *
417 * Args:
418 * tagSig - tag signature to find in profile
419 * typeSig - tag signature to find in profile
420 *
421 * Return:
422 * The desired tag object that has the desired tag type signature, or NULL if
423 * unable to find in the directory, load tag object, or the tag has the
424 * wrong tag type signature.
425 *******************************************************************************
426 */
427CIccTag* CIccProfile::FindTagOfType(icSignature tagSig, icTagTypeSignature typeSig)
428{
429 CIccTag *pTag = FindTag(tagSig);
430
431 if (pTag && pTag->GetType()==typeSig)
432 return pTag;
433
434 return NULL;
435}
436
437
438
439/**
440******************************************************************************
441* Name: CIccProfile::GetTagIO
442*
443* Purpose: Finds the tag directory entry with the given signature and returns
444* a CIccIO object that can be used to read the tag data stored in the profile.
445* This only works if the profile is still connected to the file IO object.
446*
447* Args:
448* sig - tag signature to find in profile
449*
450* Return:
451* A CIccIO object that can be used to read the tag data from the file.
452* Note: the caller is responsible for deleting the returned CIccIO object.
453*******************************************************************************
454*/
455CIccMemIO* CIccProfile::GetTagIO(icSignature sig)
456{
457 IccTagEntry *pEntry = GetTag(sig);
458
459 if (pEntry && m_pAttachIO) {
460 CIccMemIO *pIO = new CIccMemIO;
461
462 if (!pIO)
463 return NULL;
464
465 if (!pIO->Alloc(pEntry->TagInfo.size)) {
466 delete pIO;
467 return NULL;
468 }
469
470 m_pAttachIO->Seek(pEntry->TagInfo.offset, icSeekSet);
471 m_pAttachIO->Read8(pIO->GetData(), pIO->GetLength());
472 return pIO;
473 }
474
475 return NULL;
476}
477
478
479/**
480 ******************************************************************************
481 * Name: CIccProfile::AttachTag
482 *
483 * Purpose: Assign a tag object to a directory entry in the profile. This
484 * will assume ownership of the tag object.
485 *
486 * Args:
487 * sig - signature of tag 'name' to use to assign tag object with,
488 * pTag - pointer to tag object to attach to profile.
489 *
490 * Return:
491 * true = tag assigned to profile,
492 * false - tag not assigned to profile (tag already exists).
493 *******************************************************************************
494 */
495bool CIccProfile::AttachTag(icSignature sig, CIccTag *pTag)
496{
497 IccTagEntry *pEntry = GetTag(sig);
498
499 if (pEntry) {
500 if (pEntry->pTag == pTag)
501 return true;
502
503 return false;
504 }
505
506 IccTagEntry Entry = {};
507 Entry.TagInfo.sig = (icTagSignature)sig;
508 Entry.TagInfo.offset = 0;
509 Entry.TagInfo.size = 0;
510 Entry.pTag = pTag;
511
512 m_Tags->push_back(Entry);
513
514 TagPtrList::iterator i;
515
516 for (i=m_TagVals->begin(); i!=m_TagVals->end(); i++)
517 if (i->ptr == pTag)
518 break;
519
520 if (i==m_TagVals->end()) {
521 IccTagPtr TagPtr = {};
522 TagPtr.ptr = pTag;
523 m_TagVals->push_back(TagPtr);
524 }
525
526 return true;
527}
528
529
530/**
531 ******************************************************************************
532 * Name: CIccProfile::DeleteTag
533 *
534 * Purpose: Delete tag directory entry with given signature. If no other tag
535 * directory entries use the tag object, the tag object will also be deleted.
536 *
537 * Args:
538 * sig - signature of tag directory entry to remove
539 *
540 * Return:
541 * true - desired tag directory entry was found and deleted,
542 * false - desired tag directory entry was not found
543 *******************************************************************************
544 */
545bool CIccProfile::DeleteTag(icSignature sig)
546{
547 TagEntryList::iterator i;
548
549 for (i=m_Tags->begin(); i!=m_Tags->end(); i++) {
550 if (i->TagInfo.sig==(icTagSignature)sig)
551 break;
552 }
553 if (i!=m_Tags->end()) {
554 CIccTag *pTag = i->pTag;
555 m_Tags->erase(i);
556
557 if (!GetTag(pTag)) {
558 DetachTag(pTag);
559 delete pTag;
560 }
561 return true;
562 }
563
564 return false;
565}
566
567
568/**
569******************************************************************************
570* Name: CIccProfile::ConnectSubProfile
571*
572* Purpose: This checks for a embedded profile tag and creates a CIccIO object
573* for purposes of reading embedded profile in tag
574*
575* Args:
576* pIO - pointer to IO object to use to
577* bOwnIO - flag to indicate whether returned IO object should own pIO (pIO closed when returned object closed).
578*
579* Return:
580* the IO object (file) if there is an embedded profile.
581* NULL if there is no embedded profile.
582*******************************************************************************
583*/
584CIccIO* CIccProfile::ConnectSubProfile(CIccIO *pIO, bool bOwnIO) const
585{
586 TagEntryList::iterator i;
587
588 for (i = m_Tags->begin(); i != m_Tags->end(); i++) {
589 if (i->TagInfo.sig == icSigEmbeddedV5ProfileTag && i->TagInfo.size>2*sizeof(icUInt32Number)) {
590 pIO->Seek(i->TagInfo.offset, icSeekSet);
592
593 if (pIO->Read32(&sig) && pIO->Read32(&extra) && sig == icSigEmbeddedProfileType) {
594 CIccEmbedIO *pEmbedIO = new CIccEmbedIO();
595
596 if (pEmbedIO->Attach(pIO, i->TagInfo.size - 2 * sizeof(icUInt32Number), bOwnIO))
597 return pEmbedIO;
598 }
599 }
600 }
601
602 return NULL;
603}
604
605
606/**
607 ******************************************************************************
608 * Name: CIccProfile::Attach
609 *
610 * Purpose: This allows for deferred IO with a profile. The profile header and
611 * tag directory will be read, but tag data will not be read. The IO object
612 * will remain attached to the profile for the purpose of reading data in as
613 * needed.
614 *
615 * Args:
616 * pIO - pointer to IO object to begin reading profile file with.
617 *
618 * Return:
619 * true - the IO object (file) is an ICC profile, and the CIccProfile object
620 * is now attached to the object,
621 * false - the IO object (file) is not an ICC profile.
622 *******************************************************************************
623 */
624bool CIccProfile::Attach(CIccIO *pIO, bool bUseSubProfile/*=false*/)
625{
626 if (m_Tags->size())
627 Cleanup();
628
629 if (!ReadBasic(pIO)) {
630 Cleanup();
631 return false;
632 }
633
634 if (bUseSubProfile) {
635 CIccIO *pSubIO = ConnectSubProfile(pIO, true);
636
637 if (pSubIO) {
638 Cleanup();
639 if (!ReadBasic(pSubIO)) {
640 Cleanup();
641 return false;
642 }
643 pIO = pSubIO;
644 }
645 }
646
647 m_pAttachIO = pIO;
648
649 return true;
650}
651
652/**
653******************************************************************************
654* Name: CIccProfile::Detach
655*
656* Purpose: Discontinues the use of defferred IO with a profile. This can be done
657* once all the information needed for performing a transform has been extracted
658* from the profile.
659*
660* Args:
661* true - If an IO object was attached to the profile
662* false - if no IO object was attached to the profile
663*******************************************************************************
664*/
665bool CIccProfile::Detach()
666{
667 if (m_pAttachIO) {
668 TagEntryList::iterator i;
669
670 for (i = m_Tags->begin(); i != m_Tags->end(); i++) {
671 if (i->pTag)
672 i->pTag->DetachIO();
673 }
674
675 delete m_pAttachIO;
676
677 m_pAttachIO = NULL;
678 return true;
679 }
680
681 return false;
682}
683
684/**
685******************************************************************************
686* Name: CIccProfile::ReadTags
687*
688* Purpose: This will read the all the tags from the IO object into the
689* CIccProfile object. The IO object must have been attached before
690* calling this function.
691*
692* Return:
693* true - CIccProfile object now contains all tag data,
694* false - No IO object attached or tags cannot be read.
695*******************************************************************************
696*/
697bool CIccProfile::ReadTags(CIccProfile* pProfile)
698{
699 CIccIO *pIO = m_pAttachIO;
700
701 if (pProfile && pProfile->m_pAttachIO) {
702 pIO = pProfile->m_pAttachIO;
703 }
704
705 TagEntryList::iterator i;
706 //If there is no IO handle then ReadTags is successful if they have all been
707 //loaded in
708 if (!pIO) {
709 for (i = m_Tags->begin(); i != m_Tags->end(); i++) {
710 if (!i->pTag) {
711 return false;
712 }
713 }
714 return true;
715 }
716
717 icUInt32Number pos = pIO->Tell();
718
719 for (i=m_Tags->begin(); i!=m_Tags->end(); i++) {
720 if (!LoadTag((IccTagEntry*)&(i->TagInfo), pIO, true)) {
721 pIO->Seek(pos, icSeekSet);
722 return false;
723 }
724 }
725
726 pIO->Seek(pos, icSeekSet);
727
728 return true;
729}
730
731/**
732 ******************************************************************************
733 * Name: CIccProfile::Read
734 *
735 * Purpose: This will read the entire ICC profile from the IO object into the
736 * CIccProfile object
737 *
738 * Args:
739 * pIO - pointer to IO object to read ICC profile from
740 * bUseSubProfile - will attempt to open a sub-profile if present
741 *
742 * Return:
743 * true - the IO object (file) is an ICC profile, and the CIccProfile object
744 * now contains all its data,
745 * false - the IO object (file) is not an ICC profile.
746 *******************************************************************************
747 */
748bool CIccProfile::Read(CIccIO *pIO, bool bUseSubProfile/*=false*/)
749{
750 if (m_Tags->size())
751 Cleanup();
752
753 if (!ReadBasic(pIO)) {
754 Cleanup();
755 return false;
756 }
757
758 if (bUseSubProfile) {
759 CIccIO *pSubIO = ConnectSubProfile(pIO, false);
760
761 if (pSubIO) {
762 Cleanup();
763 if (!ReadBasic(pSubIO)) {
764 Cleanup();
765 return false;
766 }
767 pIO = pSubIO;
768 }
769 }
770
771 TagEntryList::iterator i;
772
773 for (i=m_Tags->begin(); i!=m_Tags->end(); i++) {
774 if (!LoadTag((IccTagEntry*)&(i->TagInfo), pIO)) {
775 Cleanup();
776 return false;
777 }
778 }
779
780 return true;
781}
782
783/**
784******************************************************************************
785* Name: CIccProfile::ReadValidate
786*
787* Purpose: This will read the entire ICC profile from the IO object into the
788* CIccProfile object
789*
790* Args:
791* pIO - pointer to IO object to read ICC profile from
792* sReport - string to put validation report info into. String should be initialized
793* before calling
794*
795* Return:
796* icValidateOK if file can be read, bad status otherwise.
797*******************************************************************************
798*/
799icValidateStatus CIccProfile::ReadValidate(CIccIO *pIO, std::string &sReport)
800{
802
803 if (m_Tags->size())
804 Cleanup();
805
806 if (!ReadBasic(pIO)) {
808 sReport += " - Unable to read profile!**\n\tProfile has invalid structure!\n";
809 Cleanup();
810
812 }
813
814 // Check profile header
815 if (!CheckFileSize(pIO)) {
816 sReport += icMsgValidateNonCompliant;
817 sReport += "Bad Header File Size\n";
819 }
820
821 CIccInfo Info;
822 icProfileID profileID;
823 // check if bytes 84..89 are zero, if not we assume a profile id
824 if (Info.IsProfileIDCalculated(&m_Header.profileID)) {
825 CalcProfileID(pIO, &profileID);
826 // if the provided and the calculated profileid missmatch
827 if (memcmp((char *) profileID.ID8, (char *) m_Header.profileID.ID8, 16) != 0) {
828 if (m_Header.version >= icVersionNumberV4) { // error with bad profile ID on v4.x.y profiles (or higher)
829 sReport += icMsgValidateNonCompliant;
830 sReport += "Bad Profile ID\n";
832 } else { // on older profiles the reserved bytes are (mis-)interpreted as profile id
833 sReport += icMsgValidateWarning;
834 sReport += "Version 2 profile has non-zero reserved data that doesn't match calculated Profile ID\n";
836 }
837 } else { // the provided and the calculated profileid match
838 if (m_Header.version < icVersionNumberV4) { // the profileid should only be used in v4.x.y profiles (or higher)
839 sReport += icMsgValidateWarning;
840 sReport += "Version 2 profile has non-zero reserved data that matches calculated Profile ID\n";
842 }
843 }
844 }
845
846 TagEntryList::iterator i;
847
848 for (i=m_Tags->begin(); i!=m_Tags->end(); i++) {
849 if ((i->TagInfo.offset % 4) != 0) {
850 sReport += icMsgValidateNonCompliant;
851 sReport += Info.GetTagSigName(i->TagInfo.sig);
852 sReport += " - Offset is not aligned on 4-byte boundary!\n";
853
855 }
856 if (!LoadTag((IccTagEntry*)&(i->TagInfo), pIO)) {
858 sReport += " - ";
859 sReport += Info.GetTagSigName(i->TagInfo.sig);
860 sReport += " - Tag has invalid structure!\n";
861
863 }
864 }
865
867 Cleanup();
868
869 return rv;
870}
871
872
873/**
874 ******************************************************************************
875 * Name: CIccProfile::Write
876 *
877 * Purpose: Write the data associated with the CIccProfile object to an IO
878 * IO object.
879 *
880 * Args:
881 * pIO - pointer to IO object to write data to
882 *
883 * Return:
884 * true - success, false - failure
885 *******************************************************************************
886 */
887bool CIccProfile::Write(CIccIO *pIO, icProfileIDSaveMethod nWriteId)
888{
889 //Write Header
890 pIO->Seek(0, icSeekSet);
891
892 pIO->Write32(&m_Header.size);
893 pIO->Write32(&m_Header.cmmId);
894 pIO->Write32(&m_Header.version);
895 pIO->Write32(&m_Header.deviceClass);
896 pIO->Write32(&m_Header.colorSpace);
897 pIO->Write32(&m_Header.pcs);
898 pIO->Write16(&m_Header.date.year);
899 pIO->Write16(&m_Header.date.month);
900 pIO->Write16(&m_Header.date.day);
901 pIO->Write16(&m_Header.date.hours);
902 pIO->Write16(&m_Header.date.minutes);
903 pIO->Write16(&m_Header.date.seconds);
904 pIO->Write32(&m_Header.magic);
905 pIO->Write32(&m_Header.platform);
906 pIO->Write32(&m_Header.flags);
907 pIO->Write32(&m_Header.manufacturer);
908 pIO->Write32(&m_Header.model);
909 pIO->Write64(&m_Header.attributes);
910 pIO->Write32(&m_Header.renderingIntent);
911 pIO->Write32(&m_Header.illuminant.X);
912 pIO->Write32(&m_Header.illuminant.Y);
913 pIO->Write32(&m_Header.illuminant.Z);
914 pIO->Write32(&m_Header.creator);
915 pIO->Write8(&m_Header.profileID, sizeof(m_Header.profileID));
916 pIO->Write32(&m_Header.spectralPCS);
917 pIO->Write16(&m_Header.spectralRange.start);
918 pIO->Write16(&m_Header.spectralRange.end);
919 pIO->Write16(&m_Header.spectralRange.steps);
920 pIO->Write16(&m_Header.biSpectralRange.start);
921 pIO->Write16(&m_Header.biSpectralRange.end);
922 pIO->Write16(&m_Header.biSpectralRange.steps);
923 pIO->Write32(&m_Header.mcs);
924 pIO->Write32(&m_Header.deviceSubClass);
925 pIO->Write8(&m_Header.reserved[0], sizeof(m_Header.reserved));
926
927 TagEntryList::iterator i, j;
928 icUInt32Number count;
929
930 for (count=0, i=m_Tags->begin(); i!= m_Tags->end(); i++) {
931 if (i->pTag)
932 count++;
933 }
934
935 pIO->Write32(&count);
936
937 icUInt32Number dirpos = pIO->GetLength();
938
939 //Write Unintialized TagDir
940 for (i=m_Tags->begin(); i!= m_Tags->end(); i++) {
941 if (i->pTag) {
942 i->TagInfo.offset = 0;
943 i->TagInfo.size = 0;
944
945 pIO->Write32(&i->TagInfo.sig);
946 pIO->Write32(&i->TagInfo.offset);
947 pIO->Write32(&i->TagInfo.size);
948 }
949 }
950
951 //Write Tags
952 for (i=m_Tags->begin(); i!= m_Tags->end(); i++) {
953 if (i->pTag) {
954 for (j=m_Tags->begin(); j!=i; j++) {
955 if (i->pTag == j->pTag)
956 break;
957 }
958
959 if (i==j) {
960 i->TagInfo.offset = pIO->GetLength();
961 i->pTag->Write(pIO);
962 i->TagInfo.size = pIO->GetLength() - i->TagInfo.offset;
963
964 pIO->Align32();
965 }
966 else {
967 i->TagInfo.offset = j->TagInfo.offset;
968 i->TagInfo.size = j->TagInfo.size;
969 }
970 }
971 }
972
973 pIO->Seek(dirpos, icSeekSet);
974
975 //Write TagDir with offsets and sizes
976 for (i=m_Tags->begin(); i!= m_Tags->end(); i++) {
977 if (i->pTag) {
978 pIO->Write32(&i->TagInfo.sig);
979 pIO->Write32(&i->TagInfo.offset);
980 pIO->Write32(&i->TagInfo.size);
981 }
982 }
983
984 //Update header with size
985 m_Header.size = pIO->GetLength();
986 pIO->Seek(0, icSeekSet);
987 pIO->Write32(&m_Header.size);
988
989 bool bWriteId;
990
991 switch (nWriteId) {
992 case icVersionBasedID:
993 default:
994 bWriteId = (m_Header.version>=icVersionNumberV4);
995 break;
996 case icAlwaysWriteID:
997 bWriteId = true;
998 break;
999 case icNeverWriteID:
1000 bWriteId = false;
1001 }
1002 if (m_Header.deviceClass==icSigColorEncodingClass) {
1003 bWriteId = false;
1004 }
1005
1006 //Write the profile ID if version 4 profile
1007 if(bWriteId) {
1008 CalcProfileID(pIO, &m_Header.profileID);
1009 pIO->Seek(84, icSeekSet);
1010 pIO->Write8(&m_Header.profileID, sizeof(m_Header.profileID));
1011 }
1012
1013 return true;
1014}
1015
1016bool CIccProfile::ReadProfileID(icProfileID &profileID)
1017{
1018 if (!m_pAttachIO) {
1019 memset(&profileID, 0, sizeof(profileID));
1020 return false;
1021 }
1022
1023 CalcProfileID(m_pAttachIO, &profileID);
1024
1025 return true;
1026}
1027
1028/**
1029 ******************************************************************************
1030 * Name: CIccProfile::InitHeader
1031 *
1032 * Purpose: Initializes the data to be written in the profile header.
1033 *
1034 *******************************************************************************
1035 */
1036void CIccProfile::InitHeader()
1037{
1038 m_Header.size = 0;
1039 m_Header.cmmId = icSigDemoIccMAX;
1040 m_Header.version=icVersionNumberV4;
1041 m_Header.deviceClass = (icProfileClassSignature)0;
1042 m_Header.colorSpace = (icColorSpaceSignature)0;
1043 m_Header.pcs = icSigLabData;
1044
1045 struct tm *newtime;
1046 time_t long_time;
1047
1048 time( &long_time ); /* Get time as long integer. */
1049 newtime = gmtime( &long_time );
1050
1051 m_Header.date.year = newtime->tm_year+1900;
1052 m_Header.date.month = newtime->tm_mon+1;
1053 m_Header.date.day = newtime->tm_mday;
1054 m_Header.date.hours = newtime->tm_hour;
1055 m_Header.date.minutes = newtime->tm_min;
1056 m_Header.date.seconds = newtime->tm_sec;
1057
1058 m_Header.magic = icMagicNumber;
1059 m_Header.platform = (icPlatformSignature)0;
1060 m_Header.flags = 0;
1061 m_Header.manufacturer=0;
1062 m_Header.model=0;
1063 m_Header.attributes=0;
1064 m_Header.renderingIntent=icPerceptual;
1065 m_Header.illuminant.X = icDtoF((icFloatNumber)0.9642);
1066 m_Header.illuminant.Y = icDtoF((icFloatNumber)1.0000);
1067 m_Header.illuminant.Z = icDtoF((icFloatNumber)0.8249);
1068 m_Header.creator = icSigDemoIccMAX;
1069 m_Header.spectralPCS = icSigNoSpectralData;
1070 m_Header.spectralRange.start = 0;
1071 m_Header.spectralRange.end = 0;
1072 m_Header.spectralRange.steps = 0;
1073 m_Header.biSpectralRange.start = 0;
1074 m_Header.biSpectralRange.end = 0;
1075 m_Header.biSpectralRange.steps = 0;
1076
1077 memset(&m_Header.profileID, 0, sizeof(m_Header.profileID));
1078 memset(&m_Header.reserved[0], 0, sizeof(m_Header.reserved));
1079}
1080
1081
1082/**
1083 *****************************************************************************
1084 * Name: CIccProfile::ReadBasic
1085 *
1086 * Purpose: Read in ICC header and tag directory entries.
1087 *
1088 * Args:
1089 * pIO - pointer to IO object to read data with
1090 *
1091 * Return:
1092 * true - valid ICC header and tag directory, false - failure
1093 ******************************************************************************
1094 */
1095bool CIccProfile::ReadBasic(CIccIO *pIO)
1096{
1097 //Read Header
1098 if (pIO->Seek(0, icSeekSet)<0 ||
1099 !pIO->Read32(&m_Header.size) ||
1100 !pIO->Read32(&m_Header.cmmId) ||
1101 !pIO->Read32(&m_Header.version) ||
1102 !pIO->Read32(&m_Header.deviceClass) ||
1103 !pIO->Read32(&m_Header.colorSpace) ||
1104 !pIO->Read32(&m_Header.pcs) ||
1105 !pIO->Read16(&m_Header.date.year) ||
1106 !pIO->Read16(&m_Header.date.month) ||
1107 !pIO->Read16(&m_Header.date.day) ||
1108 !pIO->Read16(&m_Header.date.hours) ||
1109 !pIO->Read16(&m_Header.date.minutes) ||
1110 !pIO->Read16(&m_Header.date.seconds) ||
1111 !pIO->Read32(&m_Header.magic) ||
1112 !pIO->Read32(&m_Header.platform) ||
1113 !pIO->Read32(&m_Header.flags) ||
1114 !pIO->Read32(&m_Header.manufacturer) ||
1115 !pIO->Read32(&m_Header.model) ||
1116 !pIO->Read64(&m_Header.attributes) ||
1117 !pIO->Read32(&m_Header.renderingIntent) ||
1118 !pIO->Read32(&m_Header.illuminant.X) ||
1119 !pIO->Read32(&m_Header.illuminant.Y) ||
1120 !pIO->Read32(&m_Header.illuminant.Z) ||
1121 !pIO->Read32(&m_Header.creator) ||
1122 pIO->Read8(&m_Header.profileID, sizeof(m_Header.profileID))!=sizeof(m_Header.profileID) ||
1123 !pIO->Read32(&m_Header.spectralPCS) ||
1124 !pIO->Read16(&m_Header.spectralRange.start) ||
1125 !pIO->Read16(&m_Header.spectralRange.end) ||
1126 !pIO->Read16(&m_Header.spectralRange.steps) ||
1127 !pIO->Read16(&m_Header.biSpectralRange.start) ||
1128 !pIO->Read16(&m_Header.biSpectralRange.end) ||
1129 !pIO->Read16(&m_Header.biSpectralRange.steps) ||
1130 !pIO->Read32(&m_Header.mcs) ||
1131 !pIO->Read32(&m_Header.deviceSubClass) ||
1132 pIO->Read8(&m_Header.reserved[0], sizeof(m_Header.reserved))!=sizeof(m_Header.reserved)) {
1133 return false;
1134 }
1135
1136 if (m_Header.magic != icMagicNumber)
1137 return false;
1138
1139 icUInt32Number count, i;
1140 IccTagEntry TagEntry = {};
1141
1142 TagEntry.pTag = NULL;
1143
1144 if (!pIO->Read32(&count))
1145 return false;
1146
1147 //Read TagDir
1148 for (i=0; i<count; i++) {
1149 if (!pIO->Read32(&TagEntry.TagInfo.sig) ||
1150 !pIO->Read32(&TagEntry.TagInfo.offset) ||
1151 !pIO->Read32(&TagEntry.TagInfo.size)) {
1152 return false;
1153 }
1154 m_Tags->push_back(TagEntry);
1155 }
1156
1157
1158 return true;
1159}
1160
1161
1162/**
1163 ******************************************************************************
1164 * Name: CIccProfile::LoadTag
1165 *
1166 * Purpose: This will load from the indicated IO object and associate a tag
1167 * object to a tag directory entry. Nothing happens if tag directory entry
1168 * is associated with a tag object.
1169 *
1170 * Args:
1171 * pTagEntry - pointer to tag directory entry,
1172 * pIO - pointer to IO object to read tag object data from
1173 *
1174 * Return:
1175 * true - tag directory object associated with tag directory entry,
1176 * false - failure
1177 *******************************************************************************
1178 */
1179bool CIccProfile::LoadTag(IccTagEntry *pTagEntry, CIccIO *pIO, bool bReadAll/*=false*/)
1180{
1181 if (!pTagEntry)
1182 return false;
1183
1184 if (pTagEntry->pTag)
1185 return pTagEntry->pTag->ReadAll();
1186
1187 if (pTagEntry->TagInfo.offset<sizeof(m_Header) ||
1188 !pTagEntry->TagInfo.size) {
1189 return false;
1190 }
1191
1192 icTagTypeSignature sigType;
1193
1194 //First we need to get the tag type to create the right kind of tag
1195 if (pIO->Seek(pTagEntry->TagInfo.offset, icSeekSet)!=(icInt32Number)pTagEntry->TagInfo.offset)
1196 return false;
1197
1198 if (!pIO->Read32(&sigType))
1199 return false;
1200
1201 CIccTag *pTag = CIccTag::Create(sigType);
1202
1203 if (!pTag)
1204 return false;
1205
1206 //Now seek back to where the tag starts so the created tag object can read
1207 //in its data.
1208 //First we need to get the tag type to create the right kind of tag
1209 if (pIO->Seek(pTagEntry->TagInfo.offset, icSeekSet)!=(icInt32Number)pTagEntry->TagInfo.offset) {
1210 delete pTag;
1211 return false;
1212 }
1213
1214 if (!pTag->Read(pTagEntry->TagInfo.size, pIO, this)) {
1215 delete pTag;
1216 return false;
1217 }
1218
1219 if (bReadAll) {
1220 if (!pTag->ReadAll()) {
1221 delete pTag;
1222 return false;
1223 }
1224 }
1225
1226 switch(pTagEntry->TagInfo.sig) {
1227 case icSigAToB0Tag:
1228 case icSigAToB1Tag:
1229 case icSigAToB2Tag:
1230 if (pTag->IsMBBType())
1231 ((CIccMBB*)pTag)->SetColorSpaces(m_Header.colorSpace, m_Header.pcs);
1232 break;
1233
1234 case icSigBToA0Tag:
1235 case icSigBToA1Tag:
1236 case icSigBToA2Tag:
1237 if (pTag->IsMBBType())
1238 ((CIccMBB*)pTag)->SetColorSpaces(m_Header.pcs, m_Header.colorSpace);
1239 break;
1240
1241 case icSigGamutTag:
1242 if (pTag->IsMBBType())
1243 ((CIccMBB*)pTag)->SetColorSpaces(m_Header.pcs, icSigGamutData);
1244 break;
1245
1249 if (pNamed)
1250 pNamed->SetColorSpaces(m_Header.pcs, m_Header.colorSpace,
1251 m_Header.spectralPCS,
1252 &m_Header.spectralRange,
1253 &m_Header.biSpectralRange);
1254 }
1255 else if (pTag->GetType()==icSigNamedColor2Type) {
1256 ((CIccTagNamedColor2*)pTag)->SetColorSpaces(m_Header.pcs, m_Header.colorSpace);
1257 }
1258
1259 default:
1260 break;
1261 }
1262
1263 pTagEntry->pTag = pTag;
1264
1265 IccTagPtr TagPtr = {};
1266
1267 TagPtr.ptr = pTag;
1268
1269 m_TagVals->push_back(TagPtr);
1270
1271 TagEntryList::iterator i;
1272
1273 for (i=m_Tags->begin(); i!= m_Tags->end(); i++) {
1274 if (i->TagInfo.offset == pTagEntry->TagInfo.offset &&
1275 i->pTag != pTag)
1276 i->pTag = pTag;
1277 }
1278
1279 return true;
1280}
1281
1282
1283/**
1284 ******************************************************************************
1285 * Name: CIccProfile::DetachTag
1286 *
1287 * Purpose: Remove association of a tag object from all tag directory entries.
1288 * Associated tag directory entries will be removed from the tag directory.
1289 * The tag object is NOT deleted from memory, but is considered to be
1290 * no longer associated with the CIccProfile object. The caller assumes
1291 * ownership of the tag object.
1292 *
1293 * Args:
1294 * pTag - pointer to tag object unassociate with the profile object
1295 *
1296 * Return:
1297 * true - tag object found and unassociated with profile object,
1298 * false - tag object not found
1299 *******************************************************************************
1300 */
1301bool CIccProfile::DetachTag(CIccTag *pTag)
1302{
1303 if (!pTag)
1304 return false;
1305
1306 TagPtrList::iterator i;
1307
1308 for (i=m_TagVals->begin(); i!=m_TagVals->end(); i++) {
1309 if (i->ptr == pTag)
1310 break;
1311 }
1312
1313 if (i==m_TagVals->end())
1314 return false;
1315
1316 m_TagVals->erase(i);
1317
1318 TagEntryList::iterator j;
1319 for (j=m_Tags->begin(); j!=m_Tags->end();) {
1320 if (j->pTag == pTag) {
1321 j=m_Tags->erase(j);
1322 }
1323 else
1324 j++;
1325 }
1326 return true;
1327}
1328
1329static inline bool compare_float(float x, float y, float eps=0.01f) {
1330 return (fabsf(x-y)<eps);
1331}
1332
1333static inline bool compare_float(double x, double y, double eps=0.0000001f) {
1334 return (fabs(x-y)<eps);
1335}
1336
1337
1338/**
1339****************************************************************************
1340* Name: CIccProfile::CheckHeader
1341*
1342* Purpose: Validates profile header.
1343*
1344* Return:
1345* icValidateOK if valid, or other error status.
1346*****************************************************************************
1347*/
1348icValidateStatus CIccProfile::CheckHeader(std::string &sReport) const
1349{
1351
1352 icChar buf[128];
1353 CIccInfo Info;
1354
1355 switch(m_Header.deviceClass) {
1356 case icSigInputClass:
1357 case icSigDisplayClass:
1358 case icSigOutputClass:
1359 case icSigLinkClass:
1361 case icSigAbstractClass:
1363 break;
1364
1369 if (m_Header.version<icVersionNumberV5) {
1370 CIccInfo classInfo;
1371 sReport += icMsgValidateCriticalError;
1372 sprintf(buf, " - %s not supported in Version %s profiles!\n", classInfo.GetProfileClassSigName(m_Header.deviceClass),
1373 Info.GetVersionName(m_Header.version));
1374 sReport += buf;
1376 }
1377 break;
1378
1379 default:
1380 sReport += icMsgValidateCriticalError;
1381 sprintf(buf, " - %s: Unknown profile class!\n", Info.GetProfileClassSigName(m_Header.deviceClass));
1382 sReport += buf;
1384 }
1385
1386
1387 if (m_Header.deviceClass==icSigMaterialIdentificationClass ||
1388 m_Header.deviceClass==icSigMaterialLinkClass ||
1389 m_Header.deviceClass==icSigMaterialVisualizationClass) {
1390 if (icGetColorSpaceType(m_Header.mcs)!=icSigSrcMCSChannelData) {
1391 sReport += icMsgValidateCriticalError;
1392 sReport += " - Invalid MCS designator\n";
1394 }
1395 }
1396 else if (m_Header.mcs != icSigNoMCSData && m_Header.deviceClass != icSigInputClass) {
1397 sReport += icMsgValidateNonCompliant;
1398 sReport += " - Invalid MCS designator for device class\n";
1400 }
1401
1402 if (m_Header.colorSpace!=icSigNoColorData ||
1403 m_Header.version<icVersionNumberV5 ||
1404 (m_Header.deviceClass!=icSigNamedColorClass &&
1405 m_Header.deviceClass!=icSigMaterialIdentificationClass &&
1406 m_Header.deviceClass!=icSigMaterialVisualizationClass)) {
1407 if (!Info.IsValidSpace(m_Header.colorSpace)) {
1408 if (!(m_Header.version>=icVersionNumberV5 && m_Header.deviceClass==icSigAbstractClass && Info.IsValidSpectralSpace(m_Header.colorSpace) && IsTagPresent(icSigDToB0Tag))) {
1409 sReport += icMsgValidateCriticalError;
1410 sprintf(buf, " - %s: Unknown color space!\n", Info.GetColorSpaceSigName(m_Header.colorSpace));
1411 sReport += buf;
1413 }
1414 }
1415 }
1416
1417 if (m_Header.deviceClass==icSigMaterialIdentificationClass ||
1418 m_Header.deviceClass==icSigMaterialLinkClass) {
1419 if (m_Header.pcs!=icSigNoColorData) {
1420 sReport += icMsgValidateNonCompliant;
1421 sprintf(buf, "Invalid PCS designator for %s\n", Info.GetProfileClassSigName(m_Header.deviceClass));
1422 sReport += buf;
1424 }
1425 }
1426 else if (m_Header.deviceClass==icSigColorEncodingClass) {
1427 if (m_Header.cmmId ||
1428 m_Header.pcs ||
1429 m_Header.date.day || m_Header.date.month || m_Header.date.year ||
1430 m_Header.date.hours || m_Header.date.minutes || m_Header.date.seconds ||
1431 m_Header.platform ||
1432 m_Header.flags ||
1433 m_Header.manufacturer ||
1434 m_Header.model ||
1435 m_Header.attributes ||
1436 m_Header.renderingIntent ||
1437 m_Header.illuminant.X || m_Header.illuminant.Y || m_Header.illuminant.Z ||
1438 m_Header.creator ||
1439 m_Header.profileID.ID32[0] || m_Header.profileID.ID32[1] ||
1440 m_Header.profileID.ID32[2] || m_Header.profileID.ID32[3] ||
1441 m_Header.spectralPCS ||
1442 m_Header.spectralRange.start || m_Header.spectralRange.end || m_Header.spectralRange.steps ||
1443 m_Header.biSpectralRange.start || m_Header.biSpectralRange.end || m_Header.biSpectralRange.steps
1444 ) {
1445 sReport += icMsgValidateNonCompliant;
1446 sprintf(buf, " - Encoding Class has non-zero Header data were zeros are required!\n");
1447 sReport += buf;
1449 }
1450 }
1451 else {
1452 if (m_Header.deviceClass==icSigLinkClass) {
1453 if (!Info.IsValidSpace(m_Header.pcs)) {
1454 sReport += icMsgValidateCriticalError;
1455 sprintf(buf, " - %s: Unknown pcs color space!\n", Info.GetColorSpaceSigName(m_Header.pcs));
1456 sReport += buf;
1458 }
1459 }
1460 else {
1461 switch(m_Header.pcs) {
1462 case icSigNoColorData:
1463 case icSigXYZData:
1464 case icSigLabData:
1465 break;
1466
1467 default:
1468 sReport += icMsgValidateCriticalError;
1469 sprintf(buf, " - %s: Invalid pcs color space!\n", Info.GetColorSpaceSigName(m_Header.pcs));
1470 sReport += buf;
1472 break;
1473 }
1474
1475 if (m_Header.spectralPCS && m_Header.version<icVersionNumberV5) {
1476 sReport += icMsgValidateNonCompliant;
1477 sprintf(buf, " - Spectral PCS usage in version %s ICC profile!\n", Info.GetVersionName(m_Header.version));
1478 sReport += buf;
1480 }
1481
1482 switch(icGetColorSpaceType(m_Header.spectralPCS)) {
1484 if (m_Header.spectralRange.start ||
1485 m_Header.spectralRange.end ||
1486 m_Header.spectralRange.steps ||
1487 m_Header.biSpectralRange.start ||
1488 m_Header.biSpectralRange.end ||
1489 m_Header.biSpectralRange.steps) {
1490 sReport += icMsgValidateWarning;
1491 sprintf(buf, "%s - Spectral PCS wavelengths defined with no spectral PCS!\n", Info.GetColorSpaceSigName(m_Header.pcs));
1492 sReport += buf;
1494 }
1495 break;
1496
1499 if (icGetColorSpaceType(m_Header.spectralPCS)==icSigBiSpectralReflectanceData) {
1500 if (icNumColorSpaceChannels(m_Header.spectralPCS)!=m_Header.biSpectralRange.steps * m_Header.spectralRange.steps) {
1501 sReport += icMsgValidateCriticalError;
1502 sReport += "Number of channels defined for spectral PCS do not match spectral range definitions.\n";
1504 }
1505 }
1506
1507 if (icF16toF(m_Header.biSpectralRange.end)<=icF16toF(m_Header.biSpectralRange.start)) {
1508 sReport += icMsgValidateCriticalError;
1509 sprintf(buf, "end BiDir Spectral PCS wavelength must be larger than start BiDir Spectral PCS wavelength!\n");
1510 sReport += buf;
1512 }
1513
1514 if (m_Header.biSpectralRange.steps<2) {
1515 sReport += icMsgValidateCriticalError;
1516 sprintf(buf, "%d: Must have more 2 or more BiDir spectral wavelength steps!\n", m_Header.biSpectralRange.steps);
1517 sReport += buf;
1519 }
1520 if (icF16toF(m_Header.spectralRange.end)<=icF16toF(m_Header.spectralRange.start)) {
1521 sReport += icMsgValidateCriticalError;
1522 sprintf(buf, "end Spectral PCS wavelength must be larger than start Spectral PCS wavelength!\n");
1523 sReport += buf;
1525 }
1526 if (m_Header.spectralRange.steps<2) {
1527 sReport += icMsgValidateCriticalError;
1528 sprintf(buf, "%d: Must have more 2 or more spectral wavelength steps!\n", m_Header.spectralRange.steps);
1529 sReport += buf;
1531 }
1532 break;
1533
1537 if (icNumColorSpaceChannels(m_Header.spectralPCS)!=m_Header.spectralRange.steps) {
1538 sReport += icMsgValidateCriticalError;
1539 sReport += "Number of channels defined for spectral PCS do not match spectral range definition.\n";
1541 }
1542 if (icF16toF(m_Header.spectralRange.end)<=icF16toF(m_Header.spectralRange.start)) {
1543 sReport += icMsgValidateCriticalError;
1544 sprintf(buf, "end Spectral PCS wavelength must be larger than start Spectral PCS wavelength!\n");
1545 sReport += buf;
1547 }
1548
1549 if (m_Header.spectralRange.steps<2) {
1550 sReport += icMsgValidateCriticalError;
1551 sprintf(buf, "%d: Must have more 2 or more spectral wavelength steps!\n", m_Header.spectralRange.steps);
1552 sReport += buf;
1554 }
1555 if (m_Header.biSpectralRange.start ||
1556 m_Header.biSpectralRange.end ||
1557 m_Header.biSpectralRange.steps) {
1558 sReport += icMsgValidateCriticalError;
1559 sprintf(buf, "%s - Spectral PCS wavelengths defined with no spectral PCS!\n", Info.GetColorSpaceSigName(m_Header.pcs));
1560 sReport += buf;
1562 }
1563 break;
1564
1565 default:
1566 sReport += icMsgValidateCriticalError;
1567 sprintf(buf, "%s: Invalid spectral PCS color space!\n", Info.GetColorSpaceSigName((icColorSpaceSignature)m_Header.spectralPCS));
1568 sReport += buf;
1570 break;
1571 }
1572
1573 if (m_Header.pcs==icSigNoColorData && m_Header.spectralPCS==icSigNoSpectralData) {
1574 sReport += icMsgValidateCriticalError;
1575 sprintf(buf, "Both Colorimetric PCS or Spectral PCS are not defined!\n");
1576 sReport += buf;
1578 }
1579
1580 }
1581
1582 rv = icMaxStatus(rv, Info.CheckData(sReport, m_Header.date, "Header date"));
1583
1584 switch(m_Header.platform) {
1585 case icSigMacintosh:
1586 case icSigMicrosoft:
1587 case icSigSolaris:
1588 case icSigSGI:
1589 case icSigTaligent:
1591 break;
1592
1593 default:
1594 sReport += icMsgValidateWarning;
1595 sprintf(buf, "%s: Unknown platform signature.\n", Info.GetPlatformSigName(m_Header.platform));
1596 sReport += buf;
1598 }
1599
1600 // Report on various bits of profile flags as per Table 21 in v4.3.0
1601 if(m_Header.version<icVersionNumberV5 && m_Header.flags & 0x0000FFFC) {
1602 sReport += icMsgValidateNonCompliant;
1603 sReport += "Reserved profile flags (bits 2-15) are non-zero.\n";
1605 }
1606 else if (m_Header.version == icVersionNumberV5 && m_Header.flags & 0x0000FFF8) {
1607 sReport += icMsgValidateNonCompliant;
1608 sReport += "Reserved profile flags (bits 3-15) are non-zero.\n";
1610 }
1611 else if (m_Header.flags & 0x0000FFF0) {
1612 sReport += icMsgValidateNonCompliant;
1613 sReport += "Reserved profile flags (bits 4-15) are non-zero.\n";
1615 }
1616
1617 if(m_Header.flags & 0xFFFF0000) {
1618 sReport += icMsgValidateWarning;
1619 sReport += "Vendor-specific profile flags (bits 16-32) are non-zero.\n";
1621 }
1622
1623 // Report on various bits of device attributes as per Table 22 in v4.3.0
1624 if(m_Header.attributes & 0x0000FFF0) {
1625 sReport += icMsgValidateNonCompliant;
1626 sReport += "Reserved device attributes (bits 4-31) are non-zero.\n";
1628 }
1629 if(m_Header.attributes & 0xFFFF0000) {
1630 sReport += icMsgValidateWarning;
1631 sReport += "Vendor-specific device attributes (bits 32-63) are non-zero.\n";
1633 }
1634
1635 icUInt8Number bcdpair = (icUInt8Number)(m_Header.version >> 24);
1636 // Report on unusual version (stored as BCD)
1637 if (bcdpair<0x05 && (m_Header.version & 0x0000FFFF)) {
1638 sReport += icMsgValidateWarning;
1639 sReport += "Version number bytes 10 and 11 are reserved but non-zero.\n";
1641 }
1642 switch (bcdpair) {
1643 case 0x02:
1644 bcdpair = (icUInt8Number)((m_Header.version & 0x00FF0000) >> 16);
1645 if ((bcdpair > 0x40) || (bcdpair & 0x0F)) {
1646 sReport += icMsgValidateWarning;
1647 sReport += "Version 2 minor number is unexpected.\n";
1649 }
1650 break;
1651 case 0x04:
1652 bcdpair = (icUInt8Number)((m_Header.version & 0x00FF0000) >> 16);
1653 if ((bcdpair > 0x40) || (bcdpair & 0x0F)) {
1654 sReport += icMsgValidateWarning;
1655 sReport += "Version 4 minor number is unexpected.\n";
1657 }
1658 break;
1659 case 0x05:
1660 bcdpair = (icUInt8Number)((m_Header.version & 0x00FF0000) >> 16);
1661 if ((bcdpair > 0x10) || (bcdpair & 0x0F)) {
1662 sReport += icMsgValidateWarning;
1663 sReport += "Version 5 minor number is unexpected.\n";
1665 }
1666 break;
1667 default:
1668 sReport += icMsgValidateWarning;
1669 sprintf(buf, "Major version number (%d) is unexpected.\n", ((bcdpair >> 4) * 10 + (bcdpair & 0x0F)));
1670 sReport += buf;
1672 }
1673
1674 switch((icCmmSignature)m_Header.cmmId) {
1675 //Account for registered CMM's as well:
1676 case icSigUnknownCmm:
1677 case icSigAdobe:
1678 case icSigAgfa:
1679 case icSigApple:
1680 case icSigColorGear:
1681 case icSigColorGearLite:
1682 case icSigColorGearC:
1683 case icSigEFI:
1684 case icSigExactScan:
1685 case icSigFujiFilm:
1686 case icSigHarlequinRIP:
1687 case icSigArgyllCMS:
1688 case icSigLogoSync:
1689 case icSigHeidelberg:
1690 case icSigLittleCMS:
1691 case icSigKodak:
1692 case icSigKonicaMinolta:
1693 case icSigWindowsCMS:
1694 case icSigMutoh:
1695 case icSigRefIccMAX:
1696 case icSigDemoIccMAX:
1697 case icSigRolfGierling:
1698 case icSigSampleICC:
1699 case icSigToshiba:
1701 case icSigVivo:
1702 case icSigWareToGo:
1703 case icSigZoran:
1704 case icSigOnyxGraphics:
1705 break;
1706
1707 default:
1708 sReport += icMsgValidateWarning;
1709 sprintf(buf, "%s: Unregistered CMM signature.\n", Info.GetCmmSigName((icCmmSignature)m_Header.cmmId));
1710 sReport += buf;
1712 }
1713
1714 switch(m_Header.renderingIntent) {
1715 case icPerceptual:
1717 case icSaturation:
1719 break;
1720
1721 default:
1722 sReport += icMsgValidateCriticalError;
1723 sprintf(buf, "%s: Unknown rendering intent!\n", Info.GetRenderingIntentName((icRenderingIntent)m_Header.renderingIntent));
1724 sReport += buf;
1726 }
1727
1728 rv = icMaxStatus(rv, Info.CheckData(sReport, m_Header.illuminant, "Header Illuminant"));
1729 icFloatNumber X = icFtoD(m_Header.illuminant.X);
1730 icFloatNumber Y = icFtoD(m_Header.illuminant.Y);
1731 icFloatNumber Z = icFtoD(m_Header.illuminant.Z);
1732 if (m_Header.version<icVersionNumberV5
1733 && (
1734 (!compare_float(X, 0.9642f, 0.0004f))
1735 || (!compare_float(Y, 1.0f, 0.0004f))
1736 || (!compare_float(Z, 0.8249f, 0.0004f))
1737 )
1738 ){
1739 sReport += icMsgValidateNonCompliant;
1740 sReport += "Non D50 Illuminant XYZ values";
1741 sReport +="\r\n";
1743 }
1744 }
1745
1746 int sum=0, num = sizeof(m_Header.reserved) / sizeof(m_Header.reserved[0]);
1747 for (int i=0; i<num; i++) {
1748 sum += m_Header.reserved[i];
1749 }
1750 if (sum) {
1751 sReport += icMsgValidateNonCompliant;
1752 sReport += "Reserved value must be zero.\n";
1754 }
1755
1756 return rv;
1757}
1758
1759
1760/**
1761****************************************************************************
1762* Name: CIccProfile::CheckTagExclusion
1763*
1764* Purpose: Some tags does not have a defined interpretation for a profile
1765* of a specific class. This function does these tests.
1766*
1767* Return:
1768* true if test successful, else false.
1769*****************************************************************************
1770*/
1771bool CIccProfile::CheckTagExclusion(std::string &sReport) const
1772{
1773 bool rv = true;
1774
1775 CIccInfo Info;
1776 icChar buf[128];
1777 sprintf(buf, "%s", Info.GetSigName(m_Header.deviceClass));
1778 if (m_Header.deviceClass!=icSigInputClass && m_Header.deviceClass!=icSigDisplayClass &&
1779 m_Header.deviceClass != icSigColorEncodingClass) {
1780 if (GetTag(icSigGrayTRCTag) || GetTag(icSigRedTRCTag) || GetTag(icSigGreenTRCTag) ||
1781 GetTag(icSigBlueTRCTag) || GetTag(icSigRedColorantTag) || GetTag(icSigGreenColorantTag) ||
1782 GetTag(icSigBlueColorantTag) || GetTag(icSigCicpTag))
1783 {
1784 sReport += icMsgValidateWarning;
1785 sReport += buf;
1786 sReport += "Tag exclusion test failed.\n";
1787 rv = false;
1788 }
1789 }
1790
1791 switch(m_Header.deviceClass) {
1793 {
1794 if (GetTag(icSigAToB0Tag) || GetTag(icSigAToB1Tag) || GetTag(icSigAToB2Tag) ||
1795 GetTag(icSigBToA0Tag) || GetTag(icSigBToA1Tag) || GetTag(icSigBToA2Tag) ||
1796 GetTag(icSigProfileSequenceDescTag) || GetTag(icSigGamutTag))
1797 {
1798 sReport += icMsgValidateWarning;
1799 sReport += buf;
1800 sReport += "Tag exclusion test failed.\n";
1801 rv = false;
1802 }
1803 break;
1804 }
1805
1809 {
1810 if (GetTag(icSigAToB0Tag) || GetTag(icSigAToB1Tag) || GetTag(icSigAToB2Tag) ||
1811 GetTag(icSigBToA0Tag) || GetTag(icSigBToA1Tag) || GetTag(icSigBToA2Tag) ||
1813 {
1814 sReport += icMsgValidateWarning;
1815 sReport += buf;
1816 sReport += "Tag exclusion test failed.\n";
1817 rv = false;
1818 }
1819 break;
1820 }
1821 case icSigAbstractClass:
1822 {
1823 if (GetTag(icSigNamedColor2Tag) ||
1824 GetTag(icSigAToB1Tag) || GetTag(icSigAToB2Tag) ||
1825 GetTag(icSigBToA1Tag) || GetTag(icSigBToA2Tag) || GetTag(icSigGamutTag))
1826 {
1827 sReport += icMsgValidateWarning;
1828 sReport += buf;
1829 sReport += "Tag exclusion test failed.\n";
1830 rv = false;
1831 }
1832 break;
1833 }
1834
1835 case icSigLinkClass:
1836 {
1837 if (GetTag(icSigMediaWhitePointTag) || GetTag(icSigNamedColor2Tag) ||
1838 GetTag(icSigAToB1Tag) || GetTag(icSigAToB2Tag) ||
1839 GetTag(icSigBToA1Tag) || GetTag(icSigBToA2Tag) || GetTag(icSigGamutTag))
1840 {
1841 sReport += icMsgValidateWarning;
1842 sReport += buf;
1843 sReport += "Tag exclusion test failed.\n";
1844 rv = false;
1845 }
1846 break;
1847 }
1848
1849 default:
1850 {
1851 }
1852 }
1853
1854 return rv;
1855}
1856
1857
1858/**
1859****************************************************************************
1860* Name: CIccProfile::CheckTagTypes
1861*
1862* Purpose: Check if tags have allowed tag types.
1863*
1864* Return:
1865* icValidateOK if valid, or other error status.
1866*****************************************************************************
1867*/
1868icValidateStatus CIccProfile::CheckTagTypes(std::string &sReport) const
1869{
1871
1872 icChar buf[128];
1873 CIccInfo Info;
1874
1875 icTagSignature tagsig;
1876 icTagTypeSignature typesig;
1877 icStructSignature structSig;
1878 icArraySignature arraySig;
1879 TagEntryList::const_iterator i;
1880 for (i=m_Tags->begin(); i!=m_Tags->end(); i++) {
1881 tagsig = i->TagInfo.sig;
1882 typesig = i->pTag->GetType();
1883 structSig = i->pTag->GetTagStructType();
1884 arraySig = i->pTag->GetTagArrayType();
1885 sprintf(buf, "%s", Info.GetSigName(tagsig));
1886 if (!IsTypeValid(tagsig, typesig, structSig, arraySig)) {
1887 sReport += icMsgValidateNonCompliant;
1888 sReport += buf;
1889 sprintf(buf," %s: Invalid tag type (Might be critical!).\n", Info.GetTagTypeSigName(typesig));
1890 sReport += buf;
1892 }
1893 }
1894
1895 return rv;
1896}
1897
1898
1899/**
1900****************************************************************************
1901* Name: CIccProfile::IsTypeValid
1902*
1903* Purpose: Check if tags have allowed tag types.
1904*
1905* Return:
1906* true if valid, else false.
1907*****************************************************************************
1908*/
1909bool CIccProfile::IsTypeValid(icTagSignature tagSig, icTagTypeSignature typeSig,
1910 icStructSignature structSig/*=icSigUnknownStruct*/,
1911 icArraySignature arraySig/*=icSigUnknownStruct*/) const
1912{
1913 switch(tagSig) {
1914 // A to B tags
1915 case icSigAToB0Tag:
1916 case icSigAToB1Tag:
1917 case icSigAToB2Tag:
1918 {
1919 switch(typeSig) {
1920 case icSigLut8Type:
1921 case icSigLut16Type:
1922 return true;
1923
1924 case icSigLutAtoBType:
1925 if (m_Header.version >= icVersionNumberV4)
1926 return true;
1927 else
1928 return false;
1929
1931 if (m_Header.version >= icVersionNumberV5)
1932 return true;
1933 else
1934 return false;
1935
1936 case icSigTagStructType:
1937 if (m_Header.version >= icVersionNumberV5 &&
1938 structSig==icSigBRDFStruct)
1939 return true;
1940 else
1941 return false;
1942
1943 default:
1944 return false;
1945 }
1946 }
1947
1948 case icSigAToB3Tag:
1949 {
1950 if (m_Header.version < icVersionNumberV5)
1951 return false;
1952
1953 switch(typeSig) {
1954 case icSigLut8Type:
1955 case icSigLut16Type:
1956 return true;
1957
1958 case icSigLutAtoBType:
1959 if (m_Header.version >= icVersionNumberV4)
1960 return true;
1961 else
1962 return false;
1963
1965 if (m_Header.version >= icVersionNumberV5)
1966 return true;
1967 else
1968 return false;
1969
1970 case icSigTagStructType:
1971 if (m_Header.version >= icVersionNumberV5 &&
1972 structSig==icSigBRDFStruct)
1973 return true;
1974 else
1975 return false;
1976
1977 default:
1978 return false;
1979 }
1980 }
1981
1982 // B to A tags
1983 case icSigBToA0Tag:
1984 case icSigBToA1Tag:
1985 case icSigBToA2Tag:
1986 case icSigGamutTag:
1987 case icSigPreview0Tag:
1988 case icSigPreview1Tag:
1989 case icSigPreview2Tag:
1990 {
1991 switch(typeSig) {
1992 case icSigLut8Type:
1993 case icSigLut16Type:
1994 return true;
1995
1996 case icSigLutBtoAType:
1997 if (m_Header.version >= icVersionNumberV4)
1998 return true;
1999 else
2000 return false;
2001
2003 if (m_Header.version >= icVersionNumberV5)
2004 return true;
2005 else
2006 return false;
2007
2008// case icSigTagStructType:
2009// if (m_Header.version >= icVersionNumberV5 &&
2010// structSig==icSigBRDFStruct)
2011// return true;
2012// else
2013// return false;
2014
2015 default:
2016 return false;
2017 }
2018 }
2019
2020 case icSigBToA3Tag:
2021 {
2022 if (m_Header.version < icVersionNumberV5)
2023 return false;
2024
2025 switch(typeSig) {
2026 case icSigLut8Type:
2027 case icSigLut16Type:
2028 return true;
2029
2030 case icSigLutBtoAType:
2031 if (m_Header.version >= icVersionNumberV4)
2032 return true;
2033 else
2034 return false;
2035
2037 if (m_Header.version >= icVersionNumberV5)
2038 return true;
2039 else
2040 return false;
2041
2042 // case icSigTagStructType:
2043 // if (m_Header.version >= icVersionNumberV5 &&
2044 // structSig==icSigBRDFStruct)
2045 // return true;
2046 // else
2047 // return false;
2048
2049 default:
2050 return false;
2051 }
2052 }
2053
2054 case icSigDToB0Tag:
2055 case icSigDToB1Tag:
2056 case icSigDToB2Tag:
2057 case icSigBToD0Tag:
2058 case icSigBToD1Tag:
2059 case icSigBToD2Tag:
2060 {
2061 if (m_Header.version < icVersionNumberV4_2)
2062 return false;
2063
2064 if (typeSig!=icSigMultiProcessElementType)
2065 return false;
2066 return true;
2067 }
2068
2069 case icSigDToB3Tag:
2070 case icSigBToD3Tag:
2071 case icSigAToM0Tag:
2072 case icSigMToA0Tag:
2073 case icSigMToB0Tag:
2074 case icSigMToB1Tag:
2075 case icSigMToB2Tag:
2076 case icSigMToB3Tag:
2077 case icSigMToS0Tag:
2078 case icSigMToS1Tag:
2079 case icSigMToS2Tag:
2080 case icSigMToS3Tag:
2081 case icSigBRDFAToB0Tag:
2082 case icSigBRDFAToB1Tag:
2083 case icSigBRDFAToB2Tag:
2084 case icSigBRDFAToB3Tag:
2085 case icSigBRDFDToB0Tag:
2086 case icSigBRDFDToB1Tag:
2087 case icSigBRDFDToB2Tag:
2088 case icSigBRDFDToB3Tag:
2089 {
2090 if (m_Header.version < icVersionNumberV5)
2091 return false;
2092
2093 if (typeSig!=icSigMultiProcessElementType)
2094 return false;
2095 return true;
2096 }
2097
2098
2103 {
2104 if (typeSig!=icSigGamutBoundaryDescType)
2105 return false;
2106 return true;
2107 }
2108
2117 {
2118 if (structSig==icSigBRDFStruct)
2119 return true;
2120 else
2121 return false;
2122 }
2123
2124 // Matrix column tags - XYZ types
2128 case icSigLuminanceTag:
2131 {
2132 if (typeSig!=icSigXYZType) {
2133 return false;
2134 }
2135 else return true;
2136 }
2137
2138 // TRC tags
2139 case icSigBlueTRCTag:
2140 case icSigGreenTRCTag:
2141 case icSigRedTRCTag:
2142 case icSigGrayTRCTag:
2143 {
2144 switch(typeSig) {
2145 case icSigCurveType:
2147 return true;
2148
2149 default:
2150 return false;
2151 }
2152 }
2153
2155 {
2156 if (typeSig!=icSigDateTimeType)
2157 return false;
2158 else return true;
2159 }
2160
2161 case icSigCharTargetTag:
2162 {
2163 if (typeSig!=icSigTextType)
2164 return false;
2165 else
2166 return true;
2167 }
2168
2170 {
2171 if (typeSig!=icSigS15Fixed16ArrayType)
2172 return false;
2173 else return true;
2174 }
2175
2177 {
2178 if (typeSig!=icSigChromaticityType)
2179 return false;
2180 else return true;
2181 }
2182
2183 case icSigCicpType:
2184 {
2185 if (typeSig != icSigCicpType)
2186 return false;
2187 else if (m_Header.version < icVersionNumberV4_4 || m_Header.version==icVersionNumberV5)
2188 return false;
2189
2190 return true;
2191 }
2192
2195 {
2196 //if (arraySig == icSigColorantInfoArray)
2197 // return true;
2198 //else return true;
2199 return true;
2200 }
2201
2204 {
2205 if (typeSig!=icSigColorantOrderType)
2206 return false;
2207 else return true;
2208 }
2209
2212 {
2213 if (typeSig!=icSigColorantTableType)
2214 return false;
2215 else return true;
2216 }
2217
2218 // Multi-localized Unicode type tags
2219 case icSigCopyrightTag:
2220 {
2221 if (m_Header.version>=icVersionNumberV4) {
2222 if (typeSig!=icSigMultiLocalizedUnicodeType)
2223 return false;
2224 else return true;
2225 }
2226 else {
2227 if (typeSig!=icSigTextType)
2228 return false;
2229 else return true;
2230 }
2231 }
2232
2233 case icSigCxFTag:
2234 {
2235 if (m_Header.version >= icVersionNumberV5) {
2236 if (typeSig != icSigUtf8TextType &&
2237 typeSig != icSigZipUtf8TextType)
2238 return false;
2239 return true;
2240 }
2241 else {
2242 if (typeSig != icSigUtf8TextType &&
2243 typeSig != icSigZipUtf8TextType &&
2244#if defined(XRITE_ADDITIONS)
2245 typeSig != icSigZipXmlType_XRITE &&
2246#endif
2247 typeSig != icSigZipXmlType)
2248 return false;
2249 return true;
2250 }
2251 }
2252
2254 {
2255 if (typeSig!=icSigUtf8TextType)
2256 return false;
2257 return true;
2258 }
2259
2261 {
2262 if (typeSig!=icSigUtf8TextType)
2263 return false;
2264 return true;
2265 }
2266
2268 {
2269 if (m_Header.version >= icVersionNumberV5 &&
2271 return true;
2272
2273 return false;
2274 }
2275
2280 {
2281 if (m_Header.version>=icVersionNumberV4) {
2282 if (typeSig!=icSigMultiLocalizedUnicodeType)
2283 return false;
2284 else return true;
2285 }
2286 else {
2287 if (typeSig!=icSigTextDescriptionType)
2288 return false;
2289 else return true;
2290 }
2291 }
2292
2294 {
2295 if (typeSig!=icSigMeasurementType)
2296 return false;
2297 else return true;
2298 }
2299
2301 {
2302 if (typeSig==icSigNamedColor2Type)
2303 return true;
2304 if (m_Header.version >= icVersionNumberV5 &&
2305 arraySig==icSigNamedColorArray)
2306 return true;
2307
2308 return false;
2309 }
2310
2312 {
2313 if (typeSig!=icSigResponseCurveSet16Type)
2314 return false;
2315 else return true;
2316 }
2317
2319 {
2320 if (typeSig!=icSigProfileSequenceDescType)
2321 return false;
2322 else return true;
2323 }
2324
2325 case icSigTechnologyTag:
2328 {
2329 if (typeSig!=icSigSignatureType)
2330 return false;
2331 else return true;
2332 }
2333
2335 {
2336 if (typeSig!=icSigViewingConditionsType)
2337 return false;
2338 else return true;
2339 }
2340
2342 {
2343 if (typeSig!=icSigTagArrayType ||
2344 arraySig!=icSigUtf8TextTypeArray)
2345 return false;
2346 else
2347 return true;
2348 }
2349
2351 {
2352 if (typeSig!=icSigUInt8ArrayType &&
2353 typeSig!=icSigUInt16ArrayType &&
2354 typeSig!=icSigFloat16ArrayType &&
2355 typeSig!=icSigFloat32ArrayType)
2356 return false;
2357 else
2358 return true;
2359 }
2360
2361 case icSigSurfaceMapTag:
2362 {
2364 return false;
2365 else return true;
2366 }
2367
2368 //The Private Tag case
2369 default:
2370 {
2371 return true;
2372 }
2373 }
2374}
2375
2376
2377/**
2378 ****************************************************************************
2379 * Name: CIccProfile::CheckRequiredTags
2380 *
2381 * Purpose: Check if the Profile has the required tags
2382 * for the specified Profile/Device class.
2383 *
2384 * Return:
2385 * icValidateOK if valid, or other error status.
2386 *****************************************************************************
2387 */
2388icValidateStatus CIccProfile::CheckRequiredTags(std::string &sReport) const
2389{
2390 if (m_Tags->size() <= 0) {
2391 sReport += icMsgValidateCriticalError;
2392 sReport += "No tags present.\n";
2394 }
2395
2397
2398 icProfileClassSignature sig = m_Header.deviceClass;
2399
2400 if (m_Header.deviceClass==icSigColorEncodingClass) {
2401 if (!GetTag(icSigReferenceNameTag)) {
2402 sReport += icMsgValidateNonCompliant;
2403 sReport += "Required tags missing.\n";
2405 }
2406 return rv;
2407 }
2408 else {
2409 if (!GetTag(icSigProfileDescriptionTag) ||
2410 !GetTag(icSigCopyrightTag)) {
2411 sReport += icMsgValidateNonCompliant;
2412 sReport += "Required tags missing.\n";
2414 }
2415
2417 if ((m_Header.version<icVersionNumberV5 || m_Header.pcs != 0) && !GetTag(icSigMediaWhitePointTag)) {
2418 sReport += icMsgValidateCriticalError;
2419 sReport += "Media white point tag missing.\n";
2421 }
2422 }
2423 }
2424
2425 if (m_Header.version<icVersionNumberV5) {
2426 switch(sig) {
2427 case icSigInputClass:
2428 if (m_Header.colorSpace == icSigGrayData) {
2429 if (!GetTag(icSigGrayTRCTag)) {
2430 sReport += icMsgValidateCriticalError;
2431 sReport += "Gray TRC tag missing.\n";
2433 }
2434 }
2435 else {
2436 if (!GetTag(icSigAToB0Tag)) {
2437 if (!GetTag(icSigRedMatrixColumnTag) || !GetTag(icSigGreenMatrixColumnTag) ||
2438 !GetTag(icSigBlueMatrixColumnTag) || !GetTag(icSigRedTRCTag) ||
2439 !GetTag(icSigGreenTRCTag) || !GetTag(icSigBlueTRCTag)) {
2440 sReport += icMsgValidateCriticalError;
2441 sReport += "Critical tag(s) missing.\n";
2443 }
2444 }
2445 }
2446 break;
2447
2448 case icSigDisplayClass:
2449 if (m_Header.colorSpace == icSigGrayData) {
2450 if (!GetTag(icSigGrayTRCTag)) {
2451 sReport += icMsgValidateCriticalError;
2452 sReport += "Gray TRC tag missing.\n";
2454 }
2455 }
2456 else {
2457 if (!GetTag(icSigAToB0Tag) || !GetTag(icSigBToA0Tag)) {
2458 if (!GetTag(icSigRedMatrixColumnTag) || !GetTag(icSigGreenMatrixColumnTag) ||
2459 !GetTag(icSigBlueMatrixColumnTag) || !GetTag(icSigRedTRCTag) ||
2460 !GetTag(icSigGreenTRCTag) || !GetTag(icSigBlueTRCTag)) {
2461 sReport += icMsgValidateCriticalError;
2462 sReport += "Critical tag(s) missing.\n";
2464 }
2465 }
2466 }
2467 break;
2468
2469 case icSigOutputClass:
2470 if (m_Header.colorSpace == icSigGrayData) {
2471 if (!GetTag(icSigGrayTRCTag)) {
2472 sReport += icMsgValidateCriticalError;
2473 sReport += "Gray TRC tag missing.\n";
2475 }
2476 }
2477 else {
2478 if (!GetTag(icSigAToB0Tag) || !GetTag(icSigBToA0Tag) ||
2479 !GetTag(icSigAToB1Tag) || !GetTag(icSigBToA1Tag) ||
2480 !GetTag(icSigAToB2Tag) || !GetTag(icSigBToA2Tag)) {
2481 sReport += icMsgValidateCriticalError;
2482 sReport += "Critical tag(s) missing.\n";
2484 }
2485
2486 if (!GetTag(icSigGamutTag) && m_Header.version < icVersionNumberV5) {
2487 sReport += icMsgValidateNonCompliant;
2488 sReport += "Gamut tag missing.\n";
2490 }
2491
2492 if (m_Header.version >= icVersionNumberV4) {
2493 switch (m_Header.colorSpace) {
2494 case icSig2colorData:
2495 case icSig3colorData:
2496 case icSig4colorData:
2497 case icSig5colorData:
2498 case icSig6colorData:
2499 case icSig7colorData:
2500 case icSig8colorData:
2501 case icSig9colorData:
2502 case icSig10colorData:
2503 case icSig11colorData:
2504 case icSig12colorData:
2505 case icSig13colorData:
2506 case icSig14colorData:
2507 case icSig15colorData:
2508 if (!GetTag(icSigColorantTableTag)) {
2509 sReport += icMsgValidateNonCompliant;
2510 sReport += "xCLR output profile is missing colorantTableTag\n";
2512 }
2513
2514 default:
2515 break;
2516 }
2517 }
2518 }
2519 break;
2520
2521 case icSigLinkClass:
2522 if (!GetTag(icSigAToB0Tag) || !GetTag(icSigProfileSequenceDescTag)) {
2523 sReport += icMsgValidateCriticalError;
2524 sReport += "Critical tag(s) missing.\n";
2526 }
2527
2528 if (icIsSpaceCLR(m_Header.colorSpace)) {
2529 if (!GetTag(icSigColorantTableTag)) {
2530 sReport += icMsgValidateNonCompliant;
2531 sReport += "Required tag(s) missing.\n";
2533 }
2534 }
2535
2536 if (icIsSpaceCLR(m_Header.pcs)) {
2537 if (!GetTag(icSigColorantTableOutTag)) {
2538 sReport += icMsgValidateNonCompliant;
2539 sReport += "Required tag(s) missing.\n";
2541 }
2542 }
2543 break;
2544
2546 if (!GetTag(icSigAToB0Tag) || !GetTag(icSigBToA0Tag)) {
2547 sReport += icMsgValidateCriticalError;
2548 sReport += "Critical tag(s) missing.\n";
2550 }
2551 break;
2552
2553 case icSigAbstractClass:
2554 if (!GetTag(icSigAToB0Tag)) {
2555 sReport += icMsgValidateCriticalError;
2556 sReport += "Critical tag(s) missing.\n";
2558 }
2559 break;
2560
2562 if (!GetTag(icSigNamedColor2Tag)) {
2563 sReport += icMsgValidateCriticalError;
2564 sReport += "Critical tag(s) missing.\n";
2566 }
2567
2568 break;
2569
2570 default:
2571 sReport += icMsgValidateCriticalError;
2572 sReport += "Unknown Profile Class.\n";
2574 break;
2575 }
2576 }
2577 else {
2578 switch(sig) {
2579 case icSigInputClass:
2580 if (m_Header.spectralPCS) {
2581 //????
2582 }
2583 if (m_Header.pcs) {
2584 if (m_Header.colorSpace == icSigGrayData) {
2585 if (!GetTag(icSigAToB0Tag) && !GetTag(icSigAToB1Tag) && !GetTag(icSigAToB3Tag) && !GetTag(icSigGrayTRCTag)) {
2586 sReport += icMsgValidateCriticalError;
2587 sReport += "Critical tag(s) missing.\n";
2589 }
2590 }
2591 else {
2592 if (!GetTag(icSigAToB0Tag) && !GetTag(icSigAToB1Tag) && !GetTag(icSigAToB3Tag)) {
2593 if (!GetTag(icSigRedMatrixColumnTag) || !GetTag(icSigGreenMatrixColumnTag) ||
2594 !GetTag(icSigBlueMatrixColumnTag) || !GetTag(icSigRedTRCTag) ||
2595 !GetTag(icSigGreenTRCTag) || !GetTag(icSigBlueTRCTag)) {
2596 sReport += icMsgValidateCriticalError;
2597 sReport += "Critical tag(s) missing.\n";
2599 }
2600 }
2601 }
2602 }
2603 break;
2604
2605 case icSigDisplayClass:
2606 if (m_Header.spectralPCS) {
2607 //????
2608 }
2609 if (m_Header.pcs) {
2610 if (m_Header.colorSpace == icSigGrayData) {
2611 if (!GetTag(icSigAToB0Tag) && !GetTag(icSigAToB1Tag) && !GetTag(icSigAToB3Tag) && !GetTag(icSigGrayTRCTag)) {
2612 sReport += icMsgValidateCriticalError;
2613 sReport += "Critical tag(s) missing.\n";
2615 }
2616 }
2617 else {
2618 if ((!GetTag(icSigAToB0Tag) && !GetTag(icSigAToB1Tag) && !GetTag(icSigAToB3Tag)) /*||
2619 (!GetTag(icSigBToA0Tag) && !GetTag(icSigBToA1Tag) && !GetTag(icSigBToA3Tag))*/) {
2620 if (!GetTag(icSigRedMatrixColumnTag) || !GetTag(icSigGreenMatrixColumnTag) ||
2621 !GetTag(icSigBlueMatrixColumnTag) || !GetTag(icSigRedTRCTag) ||
2622 !GetTag(icSigGreenTRCTag) || !GetTag(icSigBlueTRCTag)) {
2623 sReport += icMsgValidateCriticalError;
2624 sReport += "Critical tag(s) missing.\n";
2626 }
2627 }
2628 }
2629 }
2630 break;
2631
2632 case icSigOutputClass:
2633 if (m_Header.spectralPCS) {
2634 //????
2635 }
2636 if (m_Header.pcs) {
2637 if (m_Header.colorSpace == icSigGrayData) {
2638 if (!GetTag(icSigAToB0Tag) && !GetTag(icSigBToA0Tag) &&
2639 !GetTag(icSigAToB1Tag) && !GetTag(icSigBToA1Tag) &&
2640 !GetTag(icSigAToB3Tag) && !GetTag(icSigBToA3Tag) && !GetTag(icSigGrayTRCTag)) {
2641 sReport += icMsgValidateCriticalError;
2642 sReport += "Critical tag(s) missing.\n";
2644 }
2645 }
2646 else {
2647 if (!GetTag(icSigAToB0Tag) && !GetTag(icSigBToA0Tag) &&
2648 !GetTag(icSigAToB1Tag) && !GetTag(icSigBToA1Tag) &&
2649 !GetTag(icSigAToB3Tag) && !GetTag(icSigBToA3Tag)) {
2650 sReport += icMsgValidateCriticalError;
2651 sReport += "Critical tag(s) missing.\n";
2653 }
2654
2655 if (!GetTag(icSigGamutTag) && m_Header.version < icVersionNumberV5) {
2656 sReport += icMsgValidateNonCompliant;
2657 sReport += "Gamut tag missing.\n";
2659 }
2660
2661 if (m_Header.version >= 0x04000000L) {
2662 switch (m_Header.colorSpace) {
2663 case icSig2colorData:
2664 case icSig3colorData:
2665 case icSig4colorData:
2666 case icSig5colorData:
2667 case icSig6colorData:
2668 case icSig7colorData:
2669 case icSig8colorData:
2670 case icSig9colorData:
2671 case icSig10colorData:
2672 case icSig11colorData:
2673 case icSig12colorData:
2674 case icSig13colorData:
2675 case icSig14colorData:
2676 case icSig15colorData:
2677 if (!GetTag(icSigColorantTableTag)) {
2678 sReport += icMsgValidateNonCompliant;
2679 sReport += "xCLR output profile is missing colorantTableTag\n";
2681 }
2682
2683 default:
2684 break;
2685 }
2686 }
2687 }
2688 }
2689 break;
2690
2691 case icSigLinkClass:
2692 if (!GetTag(icSigAToB0Tag)){
2693 sReport += icMsgValidateCriticalError;
2694 sReport += "Critical tag(s) missing.\n";
2696 }
2697
2698 if (icIsSpaceCLR(m_Header.colorSpace)) {
2699 if (!GetTag(icSigColorantTableTag)) {
2700 sReport += icMsgValidateNonCompliant;
2701 sReport += "Required tag(s) missing.\n";
2703 }
2704 }
2705
2706 if (icIsSpaceCLR(m_Header.pcs)) {
2707 if (!GetTag(icSigColorantTableOutTag)) {
2708 sReport += icMsgValidateNonCompliant;
2709 sReport += "Required tag(s) missing.\n";
2711 }
2712 }
2713 break;
2714
2716 if (m_Header.spectralPCS) {
2717 //????
2718 }
2719 if (m_Header.pcs) {
2720 if ((!GetTag(icSigAToB0Tag) && !GetTag(icSigAToB1Tag) && !GetTag(icSigAToB3Tag)) ||
2721 (!GetTag(icSigBToA0Tag) && !GetTag(icSigBToA1Tag) && !GetTag(icSigBToA3Tag))) {
2722 sReport += icMsgValidateCriticalError;
2723 sReport += "Critical tag(s) missing.\n";
2725 }
2726 }
2727 break;
2728
2729 case icSigAbstractClass:
2730 if (m_Header.spectralPCS) {
2731 //????
2732 }
2733 if (m_Header.pcs) {
2734 if (!GetTag(icSigAToB0Tag) && !GetTag(icSigAToB3Tag)) {
2735 sReport += icMsgValidateCriticalError;
2736 sReport += "Critical tag(s) missing.\n";
2738 }
2739 }
2740 break;
2741
2743 if (!GetTag(icSigNamedColor2Tag)) {
2744 sReport += icMsgValidateCriticalError;
2745 sReport += "Critical tag(s) missing.\n";
2747 }
2748 break;
2749
2751 if (!GetTag(icSigAToM0Tag) && !GetTag(icSigMaterialTypeArrayTag)) {
2752 sReport += icMsgValidateCriticalError;
2753 sReport += "Critical tag missing.\n";
2755 }
2756 break;
2757
2759 if (!GetTag(icSigMToB0Tag) && !GetTag(icSigMToS0Tag)&& !GetTag(icSigMaterialTypeArrayTag)) {
2760 sReport += icMsgValidateCriticalError;
2761 sReport += "Critical tag(s) missing.\n";
2763 }
2764 break;
2765
2767 if (!GetTag(icSigMToA0Tag)&& !GetTag(icSigMaterialTypeArrayTag)) {
2768 sReport += icMsgValidateCriticalError;
2769 sReport += "Critical tag(s) missing.\n";
2771 }
2772 break;
2773
2774 default:
2775 sReport += icMsgValidateCriticalError;
2776 sReport += "Unknown Profile Class.\n";
2778 break;
2779 }
2780
2781 }
2782
2783 if (!CheckTagExclusion(sReport)) {
2785 }
2786
2787 return rv;
2788}
2789
2790/**
2791 *****************************************************************************
2792 * Name: CIccProfile::CheckFileSize()
2793 *
2794 * Purpose: Check if the Profile file size matches with the size mentioned
2795 * in the header and is evenly divisible by four.
2796 *
2797 * Args:
2798 *
2799 * Return:
2800 * true - size matches,
2801 * false - size mismatches
2802 ******************************************************************************
2803 */
2804bool CIccProfile::CheckFileSize(CIccIO *pIO) const
2805{
2806 icUInt32Number FileSize;
2807 icUInt32Number curPos = pIO->Tell();
2808
2809 if (!pIO->Seek(0, icSeekEnd))
2810 return false;
2811
2812 FileSize = pIO->Tell();
2813
2814 if (!FileSize)
2815 return false;
2816
2817 if (!pIO->Seek(curPos, icSeekSet))
2818 return false;
2819
2820 if (FileSize != m_Header.size)
2821 return false;
2822
2823 if ((m_Header.version>=icVersionNumberV4_2) && ((FileSize%4 != 0) || (m_Header.size%4 != 0)))
2824 return false;
2825
2826
2827 return true;
2828}
2829
2830
2831/**
2832 ****************************************************************************
2833 * Name: CIccProfile::Validate
2834 *
2835 * Purpose: Check the data integrity of the profile, and conformance to
2836 * the ICC specification
2837 *
2838 * Args:
2839 * sReport = String to put report into
2840 *
2841 * Return:
2842 * icValidateOK if profile is valid, warning/error level otherwise
2843 *****************************************************************************
2844 */
2845icValidateStatus CIccProfile::Validate(std::string &sReport, std::string sSigPath/*=""*/) const
2846{
2848
2849 //Check header
2850 rv = icMaxStatus(rv, CheckHeader(sReport));
2851
2852 // Check for duplicate tags
2853 if (!AreTagsUnique()) {
2854 sReport += icMsgValidateWarning;
2855 sReport += " - There are duplicate tags.\n";
2857 }
2858
2859 // Check Required Tags which includes exclusion tests
2860 rv = icMaxStatus(rv, CheckRequiredTags(sReport));
2861
2862 // Per Tag tests
2863 rv = icMaxStatus(rv, CheckTagTypes(sReport));
2864 TagEntryList::iterator i;
2865 for (i=m_Tags->begin(); i!=m_Tags->end(); i++) {
2866 rv = icMaxStatus(rv, i->pTag->Validate(sSigPath + icGetSigPath(i->TagInfo.sig), sReport, this));
2867 }
2868
2869 return rv;
2870}
2871
2872/**
2873 ****************************************************************************
2874 * Name: CIccProfile::GetSpaceSamples
2875 *
2876 * Purpose: Get the number of device channels from the color space
2877 * of data.
2878 *
2879 * Return: Number of device channels.
2880 *
2881 *****************************************************************************
2882 */
2883icUInt16Number CIccProfile::GetSpaceSamples() const
2884{
2885 return (icUInt16Number)icGetSpaceSamples(m_Header.colorSpace);
2886}
2887
2888
2889/**
2890 ****************************************************************************
2891 * Name: CIccProfile::getPccIlluminant
2892 *
2893 * Purpose: Get the Illuminant associated with profile connection.
2894 *
2895 * Return: The illuminant type associated with profile connection.
2896 *
2897 *****************************************************************************
2898 */
2899icIlluminant CIccProfile::getPccIlluminant()
2900{
2901 if (m_Header.version<icVersionNumberV5)
2902 return icIlluminantD50;
2903
2904 const CIccTagSpectralViewingConditions *pCond = getPccViewingConditions();
2905
2906 if (!pCond) {
2907 if (icIsIllumD50(m_Header.illuminant))
2908 return icIlluminantD50;
2909 else
2910 return icIlluminantUnknown;
2911 }
2912
2913 return pCond->getStdIllumiant();
2914}
2915
2916
2917
2918/**
2919 ****************************************************************************
2920 * Name: CIccProfile::getPccCCT
2921 *
2922 * Purpose: Get the Correlated Color Temperature associated with profile connection.
2923 *
2924 * Return: The Correlated Color Temperature associated with profile connection.
2925 *
2926 *****************************************************************************
2927 */
2928icFloatNumber CIccProfile::getPccCCT()
2929{
2930 if (m_Header.version<icVersionNumberV5)
2931 return 5000.f;
2932
2933 const CIccTagSpectralViewingConditions *pCond = getPccViewingConditions();
2934
2935 if (!pCond) {
2936 if (icIsIllumD50(m_Header.illuminant))
2937 return 5000.0f;
2938 else
2939 return 0.0;
2940 }
2941
2942 return pCond->getIlluminantCCT();
2943}
2944
2945
2946/**
2947 ****************************************************************************
2948 * Name: CIccProfile::getPccObserver
2949 *
2950 * Purpose: Get the observer type associated with profile connection.
2951 *
2952 * Return: The observer type associated with profile connection.
2953 *
2954 *****************************************************************************
2955 */
2956icStandardObserver CIccProfile::getPccObserver()
2957{
2958 if (m_Header.version<icVersionNumberV5)
2960
2961 const CIccTagSpectralViewingConditions *pCond = getPccViewingConditions();
2962 if (!pCond) {
2963 if (icIsIllumD50(m_Header.illuminant))
2965 else
2966 return icStdObsUnknown;
2967 }
2968
2969 return pCond->getStdObserver();
2970}
2971
2972/**
2973 ****************************************************************************
2974 * Name: CIccProfile::getNormIlluminantXYZ
2975 *
2976 * Purpose: Get the Normalized XYZ coordinates for the illuminant and observer
2977 * associated with profile connection.
2978 *
2979 *****************************************************************************
2980 */
2981void CIccProfile::getNormIlluminantXYZ(icFloatNumber *pXYZ)
2982{
2983 const CIccTagSpectralViewingConditions *pCond = getPccViewingConditions();
2984 if (!pCond) {
2985 pXYZ[0] = icFtoD(m_Header.illuminant.X);
2986 pXYZ[1] = icFtoD(m_Header.illuminant.Y);
2987 pXYZ[2] = icFtoD(m_Header.illuminant.Z);
2988 }
2989 else {
2990 pXYZ[0] = pCond->m_illuminantXYZ.X / pCond->m_illuminantXYZ.Y;
2991 pXYZ[1] = 1.0f;
2992 pXYZ[2] = pCond->m_illuminantXYZ.Z / pCond->m_illuminantXYZ.Y;
2993 }
2994}
2995
2996/**
2997****************************************************************************
2998* Name: CIccProfile::getLumIlluminantXYZ
2999*
3000* Purpose: Get the XYZ Luminance coordinates (in cd/m^2 units) for the
3001* illuminant and observer associated with profile connection.
3002*
3003*****************************************************************************
3004*/
3005void CIccProfile::getLumIlluminantXYZ(icFloatNumber *pXYZ)
3006{
3007 const CIccTagSpectralViewingConditions *pCond = getPccViewingConditions();
3008 if (!pCond) {
3009 const CIccTagXYZ *pXYZTag = (CIccTagXYZ*) FindTagOfType(icSigLuminanceTag, icSigXYZType);
3010 if (pXYZTag) {
3011 icFloatNumber Y = icFtoD((*pXYZTag)[0].Y);
3012
3013 pXYZ[0] = icFtoD(m_Header.illuminant.X) * Y;
3014 pXYZ[1] = icFtoD(m_Header.illuminant.Y) * Y;
3015 pXYZ[2] = icFtoD(m_Header.illuminant.Z) * Y;
3016 }
3017 else { // No Luminance Tag so just use default luminance
3018 pXYZ[0] = icFtoD(m_Header.illuminant.X) * icDefaultLuminance;
3019 pXYZ[1] = icFtoD(m_Header.illuminant.Y) * icDefaultLuminance;
3020 pXYZ[2] = icFtoD(m_Header.illuminant.Z) * icDefaultLuminance;
3021 }
3022 }
3023 else {
3024 pXYZ[0] = pCond->m_illuminantXYZ.X;
3025 pXYZ[1] = pCond->m_illuminantXYZ.Y;
3026 pXYZ[2] = pCond->m_illuminantXYZ.Z;
3027 }
3028}
3029
3030/**
3031 ****************************************************************************
3032 * Name: CIccProfile::getMediaWhiteXYZ
3033 *
3034 * Purpose: Get the Media White point XYZ coordinates for the illuminant and observer
3035 * associated with observing profile connection conditions.
3036 *
3037 *****************************************************************************
3038 */
3039bool CIccProfile::getMediaWhiteXYZ(icFloatNumber *pXYZ)
3040{
3041 CIccTag *pTag = FindTag(icSigMediaWhitePointTag);
3042 if (pTag && pTag->GetType()==icSigXYZType) {
3043 CIccTagXYZ *pXYZTag = (CIccTagXYZ*)pTag;
3044 icXYZNumber *pMediaXYZ = pXYZTag->GetXYZ(0);
3045 pXYZ[0] = icFtoD(pMediaXYZ->X);
3046 pXYZ[1] = icFtoD(pMediaXYZ->Y);
3047 pXYZ[2] = icFtoD(pMediaXYZ->Z);
3048
3049 return true;
3050 }
3051 else { //No media white point so use illuminant
3052 pXYZ[0] = icFtoD(m_Header.illuminant.X);
3053 pXYZ[1] = icFtoD(m_Header.illuminant.Y);
3054 pXYZ[2] = icFtoD(m_Header.illuminant.Z);
3055
3056 return false;
3057 }
3058}
3059
3060/**
3061 ****************************************************************************
3062 * Name: CIccProfile::calcNormIlluminantXYZ
3063 *
3064 * Purpose: Get the XYZ Luminance coordinates (in cd/m^2 units) for the
3065 * illuminant and observer associated with profile connection.
3066 *
3067 * This assumes that the illuminant is not normalized and values for each
3068 * wavelength are expressed in terms of (cd/m^2)
3069 *
3070 *****************************************************************************
3071 */
3072bool CIccProfile::calcLumIlluminantXYZ(icFloatNumber *pXYZ, IIccProfileConnectionConditions *pObservingPCC)
3073{
3074 const CIccTagSpectralViewingConditions *pCond = getPccViewingConditions();
3075
3076 if (pCond) {
3077 icSpectralRange illuminantRange;
3078 const icFloatNumber *illuminant = pCond->getIlluminant(illuminantRange);
3079
3080 CIccMatrixMath *obs = pCond->getObserverMatrix(illuminantRange);
3081
3082 if (!obs) {
3083 pXYZ[0] = icFtoD(m_Header.illuminant.X) * icDefaultLuminance;
3084 pXYZ[1] = icFtoD(m_Header.illuminant.Y) * icDefaultLuminance;
3085 pXYZ[2] = icFtoD(m_Header.illuminant.Z) * icDefaultLuminance;
3086
3087 return false;
3088 }
3089
3090 obs->VectorScale(illuminant);
3091
3092 pXYZ[0] = 683.0f * obs->RowSum(0);
3093 pXYZ[1] = 683.0f * obs->RowSum(1);
3094 pXYZ[2] = 683.0f * obs->RowSum(2);
3095
3096 delete obs;
3097
3098 return true;
3099 }
3100 else {
3101 pXYZ[0] = icFtoD(m_Header.illuminant.X) * icDefaultLuminance;
3102 pXYZ[1] = icFtoD(m_Header.illuminant.Y) * icDefaultLuminance;
3103 pXYZ[2] = icFtoD(m_Header.illuminant.Z) * icDefaultLuminance;
3104
3105 return false;
3106 }
3107}
3108
3109/**
3110****************************************************************************
3111* Name: CIccProfile::calcLumIlluminantXYZ
3112*
3113* Purpose: Get the Normalized XYZ coordinates for the illuminant and observer
3114* associated with profile connection.
3115*
3116*****************************************************************************
3117*/
3118bool CIccProfile::calcNormIlluminantXYZ(icFloatNumber *pXYZ, IIccProfileConnectionConditions *pObservingPCC)
3119{
3120 const CIccTagSpectralViewingConditions *pCond = getPccViewingConditions();
3121
3122 if (pCond) {
3123 icSpectralRange illuminantRange;
3124 const icFloatNumber *illuminant = pCond->getIlluminant(illuminantRange);
3125
3126 CIccMatrixMath *obs = pCond->getObserverMatrix(illuminantRange);
3127
3128 if (!obs) {
3129 pXYZ[0] = icFtoD(m_Header.illuminant.X);
3130 pXYZ[1] = icFtoD(m_Header.illuminant.Y);
3131 pXYZ[2] = icFtoD(m_Header.illuminant.Z);
3132
3133 return false;
3134 }
3135
3136 obs->VectorScale(illuminant);
3137 obs->Scale(obs->RowSum(1));
3138
3139 pXYZ[0] = obs->RowSum(0);
3140 pXYZ[1] = obs->RowSum(1);
3141 pXYZ[2] = obs->RowSum(2);
3142
3143 delete obs;
3144
3145 return true;
3146 }
3147 else {
3148 pXYZ[0] = icFtoD(m_Header.illuminant.X);
3149 pXYZ[1] = icFtoD(m_Header.illuminant.Y);
3150 pXYZ[2] = icFtoD(m_Header.illuminant.Z);
3151
3152 return false;
3153 }
3154}
3155
3156/**
3157 ****************************************************************************
3158 * Name: CIccProfile::calcMediaWhiteXYZ
3159 *
3160 * Purpose: Get the Media White point XYZ coordinates for the illuminant and observer
3161 * associated with observing profile connection conditions.
3162 *
3163 *****************************************************************************
3164 */
3165bool CIccProfile::calcMediaWhiteXYZ(icFloatNumber *pXYZ, IIccProfileConnectionConditions *pObservingPCC)
3166{
3167 const CIccTagSpectralViewingConditions *pView = pObservingPCC->getPccViewingConditions();
3168 CIccTag *pTag;
3169 bool rv = true;
3170
3171 pTag = FindTag(icSigSpectralWhitePointTag);
3172
3173 if (!pView || !pTag) { //Use profile's definition of Media White Point
3174getmediaXYZ:
3175 pTag = FindTag(icSigMediaWhitePointTag);
3176 if (pTag && pTag->GetType()==icSigXYZType) {
3177 CIccTagXYZ *pXYZTag = (CIccTagXYZ*)pTag;
3178 icXYZNumber *pMediaXYZ = pXYZTag->GetXYZ(0);
3179 pXYZ[0] = icFtoD(pMediaXYZ->X);
3180 pXYZ[1] = icFtoD(pMediaXYZ->Y);
3181 pXYZ[2] = icFtoD(pMediaXYZ->Z);
3182 return rv;
3183 }
3184 else { //No media white point so use illuminant
3185 pXYZ[0] = icFtoD(m_Header.illuminant.X);
3186 pXYZ[1] = icFtoD(m_Header.illuminant.Y);
3187 pXYZ[2] = icFtoD(m_Header.illuminant.Z);
3188 return false;
3189 }
3190 }
3191 else if (pTag->IsNumArrayType()) { //pView contains observer and illuminant && spectral white point is available
3192 CIccTagNumArray *pNumTag = (CIccTagNumArray*)pTag;
3193 icSignature sig =m_Header.spectralPCS;
3194 icSpectralRange range = m_Header.spectralRange;
3195 icSpectralRange birange = m_Header.biSpectralRange;
3196
3197 rv = false;
3198
3199 if (!sig) {
3200 pTag = FindTag(icSigSpectralDataInfoTag);
3201 if (pTag && pTag->GetType()==icSigSpectralDataInfoType) {
3203 sig = pInfo->m_nSig;
3204 range = pInfo->m_spectralRange;
3205 birange = pInfo->m_biSpectralRange;
3206 }
3207 }
3208
3210 icFloatNumber *pWhite;
3211
3212 if (samples && pNumTag->GetNumValues()>=samples) {
3213 pWhite=new icFloatNumber[samples];
3214 if (pWhite) {
3215 pNumTag->GetValues(pWhite);
3216 }
3217 else {
3218 goto getmediaXYZ;
3219 }
3220 }
3221 else {
3222 goto getmediaXYZ;
3223 }
3224
3226 CIccMatrixMath *pMtx = pObservingPCC->getReflectanceObserver(range);
3227
3228 pMtx->VectorMult(pXYZ, pWhite);
3229 delete pMtx;
3230 delete [] pWhite;
3231
3232 return true;
3233 }
3235 CIccMatrixMath obs(3,range.steps);
3236 pObservingPCC->getEmissiveObserver(range, pWhite, obs.entry(0));
3237
3238 obs.VectorMult(pXYZ, pWhite);
3239 delete [] pWhite;
3240
3241 return true;
3242 }
3243 else {
3244 delete [] pWhite;
3245 goto getmediaXYZ;
3246
3247 }
3248 }
3249 else {
3250 goto getmediaXYZ;
3251 }
3252}
3253
3254
3255//////////////////////////////////////////////////////////////////////
3256// Function Definitions
3257//////////////////////////////////////////////////////////////////////
3258
3259/**
3260 *****************************************************************************
3261 * Name: ReadIccProfile
3262 *
3263 * Purpose: Read an ICC profile file.
3264 *
3265 * Args:
3266 * szFilename - zero terminated string with filename of ICC profile to read
3267 * bUseSubProfile - will attempt to open a subprofile if present
3268 *
3269 * Return:
3270 * Pointer to ICC profile object, or NULL on failure
3271 ******************************************************************************
3272 */
3273CIccProfile* ReadIccProfile(const icChar *szFilename, bool bUseSubProfile/*=false*/)
3274{
3275 CIccFileIO *pFileIO = new CIccFileIO;
3276
3277 if (!pFileIO->Open(szFilename, "rb")) {
3278 delete pFileIO;
3279 return NULL;
3280 }
3281
3282 CIccProfile *pIcc = new CIccProfile;
3283
3284 if (!pIcc->Read(pFileIO, bUseSubProfile)) {
3285 delete pIcc;
3286 delete pFileIO;
3287 return NULL;
3288 }
3289 delete pFileIO;
3290
3291 return pIcc;
3292}
3293
3294
3295#ifdef WIN32
3296/**
3297*****************************************************************************
3298* Name: ReadIccProfile
3299*
3300* Purpose: Read an ICC profile file.
3301*
3302* Args:
3303* szFilename - zero terminated string with filename of ICC profile to read
3304* bUseSubProfile - will attempt to open a subprofile if present
3305*
3306* Return:
3307* Pointer to icc profile object, or NULL on failure
3308******************************************************************************
3309*/
3310CIccProfile* ReadIccProfile(const icWChar *szFilename, bool bUseSubProfile/*=false*/)
3311{
3312 CIccFileIO *pFileIO = new CIccFileIO;
3313
3314 if (!pFileIO->Open(szFilename, L"rb")) {
3315 delete pFileIO;
3316 return NULL;
3317 }
3318
3319 CIccProfile *pIcc = new CIccProfile;
3320
3321 if (!pIcc->Read(pFileIO)) {
3322 delete pIcc;
3323 delete pFileIO;
3324 return NULL;
3325 }
3326 delete pFileIO;
3327
3328 return pIcc;
3329}
3330
3331#endif
3332
3333/**
3334*****************************************************************************
3335* Name: ReadIccProfile
3336*
3337* Purpose: Read an ICC profile file.
3338*
3339* Args:
3340* pMem = pointer to memory containing profile data
3341* nSize = size of memory related to profile
3342* bUseSubProfile - will attempt to open a subprofile if present
3343*
3344* Return:
3345* Pointer to icc profile object, or NULL on failure
3346******************************************************************************
3347*/
3348CIccProfile* ReadIccProfile(const icUInt8Number *pMem, icUInt32Number nSize, bool bUseSubProfile/*=false*/)
3349{
3350 CIccMemIO *pMemIO = new CIccMemIO();
3351
3352 if (!pMemIO->Attach((icUInt8Number*)pMem, nSize)) {
3353 delete pMemIO;
3354 return NULL;
3355 }
3356
3357 CIccProfile *pIcc = new CIccProfile;
3358
3359 if (!pIcc->Read(pMemIO)) {
3360 delete pIcc;
3361 delete pMemIO;
3362 return NULL;
3363 }
3364 delete pMemIO;
3365
3366 return pIcc;
3367}
3368
3369
3370/**
3371 ******************************************************************************
3372 * Name: OpenIccProfile
3373 *
3374 * Purpose: Open an ICC profile file. This will only read the profile header
3375 * and tag directory. Loading of actual tags will be deferred until the
3376 * tags are actually referenced by FindTag().
3377 *
3378 * Args:
3379 * szFilename - zero terminated string with filename of ICC profile to read
3380 * bUseSubProfile - will attempt to open a subprofile if present
3381 *
3382 * Return:
3383 * Pointer to icc profile object, or NULL on failure
3384 *******************************************************************************
3385 */
3386CIccProfile* OpenIccProfile(const icChar *szFilename, bool bUseSubProfile/*=false*/)
3387{
3388 CIccFileIO *pFileIO = new CIccFileIO;
3389
3390 if (!pFileIO->Open(szFilename, "rb")) {
3391 delete pFileIO;
3392 return NULL;
3393 }
3394
3395 CIccProfile *pIcc = new CIccProfile;
3396
3397 if (!pIcc->Attach(pFileIO, bUseSubProfile)) {
3398 delete pIcc;
3399 delete pFileIO;
3400 return NULL;
3401 }
3402
3403 return pIcc;
3404}
3405
3406#ifdef WIN32
3407/**
3408******************************************************************************
3409* Name: OpenIccProfile
3410*
3411* Purpose: Open an ICC profile file. This will only read the profile header
3412* and tag directory. Loading of actual tags will be deferred until the
3413* tags are actually referenced by FindTag().
3414*
3415* Args:
3416* szFilename - zero terminated string with filename of ICC profile to read
3417* bUseSubProfile - will attempt to open a subprofile if present
3418*
3419* Return:
3420* Pointer to icc profile object, or NULL on failure
3421*******************************************************************************
3422*/
3423CIccProfile* OpenIccProfile(const icWChar *szFilename, bool bUseSubProfile/*=false*/)
3424{
3425 CIccFileIO *pFileIO = new CIccFileIO;
3426
3427 if (!pFileIO->Open(szFilename, L"rb")) {
3428 delete pFileIO;
3429 return NULL;
3430 }
3431
3432 CIccProfile *pIcc = new CIccProfile;
3433
3434 if (!pIcc->Attach(pFileIO, bUseSubProfile)) {
3435 delete pIcc;
3436 delete pFileIO;
3437 return NULL;
3438 }
3439
3440 return pIcc;
3441}
3442#endif
3443
3444/**
3445******************************************************************************
3446* Name: OpenIccProfile
3447*
3448* Purpose: Open an ICC profile file. This will only read the profile header
3449* and tag directory. Loading of actual tags will be deferred until the
3450* tags are actually referenced by FindTag().
3451*
3452* Args:
3453* pMem = pointer to memory containing profile data
3454* nSize = size of memory related to profile
3455*
3456* Return:
3457* Pointer to icc profile object, or NULL on failure
3458*******************************************************************************
3459*/
3460CIccProfile* OpenIccProfile(const icUInt8Number *pMem, icUInt32Number nSize, bool bUseSubProfile/*=false*/)
3461{
3462 CIccMemIO *pMemIO = new CIccMemIO;
3463
3464 if (!pMemIO->Attach((icUInt8Number*)pMem, nSize)) {
3465 delete pMemIO;
3466 return NULL;
3467 }
3468
3469 CIccProfile *pIcc = new CIccProfile;
3470
3471 if (!pIcc->Attach(pMemIO, bUseSubProfile)) {
3472 delete pIcc;
3473 delete pMemIO;
3474 return NULL;
3475 }
3476
3477 return pIcc;
3478}
3479
3480/**
3481******************************************************************************
3482* Name: ValidateIccProfile
3483*
3484* Purpose: Open an ICC profile file. This will only read the profile header
3485* and tag directory. Loading of actual tags will be deferred until the
3486* tags are actually referenced by FindTag().
3487*
3488* Args:
3489* pIO - Handle to IO access object (Not ValidateIccProfile assumes ownership of this object)
3490* sReport - std::string to put report into
3491* nStatus - return status value
3492*
3493* Return:
3494* Pointer to icc profile object, or NULL on failure
3495*******************************************************************************
3496*/
3497CIccProfile* ValidateIccProfile(CIccIO *pIO, std::string &sReport, icValidateStatus &nStatus)
3498{
3499 if (!pIO) {
3501 sReport += " - ";
3502 sReport += "- Invalid I/O Handle\n";
3503 delete pIO;
3504 return NULL;
3505 }
3506
3507 CIccProfile *pIcc = new CIccProfile;
3508
3509 if (!pIcc) {
3510 delete pIO;
3511 return NULL;
3512 }
3513
3514 nStatus = pIcc->ReadValidate(pIO, sReport);
3515
3516 if (nStatus>=icValidateCriticalError) {
3517 delete pIcc;
3518 delete pIO;
3519 return NULL;
3520 }
3521
3522 delete pIO;
3523
3524 nStatus = pIcc->Validate(sReport);
3525
3526 return pIcc;
3527}
3528
3529#ifdef WIN32
3530/**
3531******************************************************************************
3532* Name: ValidateIccProfile
3533*
3534* Purpose: Open an ICC profile file. This will only read the profile header
3535* and tag directory. Loading of actual tags will be deferred until the
3536* tags are actually referenced by FindTag().
3537*
3538* Args:
3539* szFilename - zero terminated string with filename of ICC profile to read
3540* sReport - std::string to put report into
3541* nStatus - return status value
3542*
3543* Return:
3544* Pointer to icc profile object, or NULL on failure
3545*******************************************************************************
3546*/
3547CIccProfile* ValidateIccProfile(const icWChar *szFilename, std::string &sReport, icValidateStatus &nStatus)
3548{
3549 CIccFileIO *pFileIO = new CIccFileIO;
3550
3551 if (!pFileIO->Open(szFilename, L"rb")) {
3552 delete pFileIO;
3553 return NULL;
3554 }
3555
3556 return ValidateIccProfile(pFileIO, sReport, nStatus);
3557}
3558#endif
3559
3560
3561/**
3562******************************************************************************
3563* Name: ValidateIccProfile
3564*
3565* Purpose: Open an ICC profile file. This will only read the profile header
3566* and tag directory. Loading of actual tags will be deferred until the
3567* tags are actually referenced by FindTag().
3568*
3569* Args:
3570* szFilename - zero terminated string with filename of ICC profile to read
3571* sReport - std::string to put report into
3572* nStatus - return status value
3573*
3574* Return:
3575* Pointer to icc profile object, or NULL on failure
3576*******************************************************************************
3577*/
3578CIccProfile* ValidateIccProfile(const icChar *szFilename, std::string &sReport, icValidateStatus &nStatus)
3579{
3580 CIccFileIO *pFileIO = new CIccFileIO;
3581
3582 if (!pFileIO->Open(szFilename, "rb")) {
3584 sReport += " - ";
3585 sReport += szFilename;
3586 sReport += "- Invalid Filename\n";
3587 delete pFileIO;
3588 return NULL;
3589 }
3590
3591 CIccProfile *pIcc = new CIccProfile;
3592
3593 if (!pIcc) {
3594 delete pFileIO;
3595 return NULL;
3596 }
3597
3598 nStatus = pIcc->ReadValidate(pFileIO, sReport);
3599
3600 if (nStatus>=icValidateCriticalError) {
3601 delete pIcc;
3602 delete pFileIO;
3603 return NULL;
3604 }
3605
3606 delete pFileIO;
3607
3608 nStatus = icMaxStatus(nStatus, pIcc->Validate(sReport));
3609
3610 return pIcc;
3611}
3612
3613
3614
3615/**
3616 ******************************************************************************
3617 * Name: SaveIccProfile
3618 *
3619 * Purpose: Save an ICC profile file.
3620 *
3621 * Args:
3622 * szFilename - zero terminated string with filename of ICC profile to create
3623 *
3624 * Return:
3625 * true = success, false = failure
3626 *******************************************************************************
3627 */
3628bool SaveIccProfile(const icChar *szFilename, CIccProfile *pIcc, icProfileIDSaveMethod nWriteId)
3629{
3630 CIccFileIO FileIO;
3631
3632 if (!pIcc)
3633 return false;
3634
3635 if (!FileIO.Open(szFilename, "w+b")) {
3636 return false;
3637 }
3638
3639 if (!pIcc->Write(&FileIO, nWriteId)) {
3640 return false;
3641 }
3642
3643 return true;
3644}
3645
3646/**
3647******************************************************************************
3648* Name: SaveIccProfile
3649*
3650* Purpose: Save an ICC profile file.
3651*
3652* Args:
3653* f - handle to file io stream (closed outside of this function)
3654*
3655* Return:
3656* true = success, false = failure
3657*******************************************************************************
3658*/
3659bool SaveIccProfile(FILE *f, CIccProfile *pIcc, icProfileIDSaveMethod nWriteId)
3660{
3661 CIccFileIO FileIO;
3662
3663 if (!pIcc)
3664 return false;
3665
3666 if (!FileIO.Attach(f)) {
3667 return false;
3668 }
3669
3670 if (!pIcc->Write(&FileIO, nWriteId)) {
3671 return false;
3672 }
3673
3674 FileIO.Detach();
3675
3676 return true;
3677}
3678
3679#ifdef WIN32
3680/**
3681******************************************************************************
3682* Name: SaveIccProfile
3683*
3684* Purpose: Save an ICC profile file.
3685*
3686* Args:
3687* szFilename - zero terminated string with filename of ICC profile to create
3688*
3689* Return:
3690* true = success, false = failure
3691*******************************************************************************
3692*/
3693bool SaveIccProfile(const icWChar *szFilename, CIccProfile *pIcc, icProfileIDSaveMethod nWriteId)
3694{
3695 CIccFileIO FileIO;
3696
3697 if (!pIcc)
3698 return false;
3699
3700 if (!FileIO.Open(szFilename, L"w+b")) {
3701 return false;
3702 }
3703
3704 if (!pIcc->Write(&FileIO, nWriteId)) {
3705 return false;
3706 }
3707
3708 return true;
3709}
3710#endif
3711
3712/**
3713 ****************************************************************************
3714 * Name: CalcProfileID
3715 *
3716 * Purpose: Calculate the Profile ID using MD5 Fingerprinting method.
3717 *
3718 * Args:
3719 * pIO = The CIccIO object,
3720 * pProfileID = array where the profileID will be stored
3721 *
3722 ****************************************************************************
3723 */
3724void CalcProfileID(CIccIO *pIO, icProfileID *pProfileID)
3725{
3726 icUInt32Number len, num, nBlock, pos;
3728 icUInt8Number buffer[1024] = {0};
3729
3730 //remember where we are
3731 pos = pIO->Tell();
3732
3733 //Get length and set up to read entire file
3734 len = pIO->GetLength();
3735 pIO->Seek(0, icSeekSet);
3736
3737 //read file updating checksum as we go
3739 nBlock = 0;
3740 while(len) {
3741 num = pIO->Read8(&buffer[0],1024);
3742 if (!nBlock) { // Zero out 3 header contents in Profile ID calculation
3743 memset(buffer+44, 0, 4); //Profile flags
3744 memset(buffer+64, 0, 4); //Rendering Intent
3745 memset(buffer+84, 0, 16); //Profile Id
3746 }
3747 icMD5Update(&context,buffer,num);
3748 nBlock++;
3749 len -=num;
3750 }
3751 icMD5Final(&pProfileID->ID8[0],&context);
3752
3753 //go back where we were
3754 pIO->Seek(pos, icSeekSet);
3755}
3756
3757/**
3758 ****************************************************************************
3759 * Name: CalcProfileID
3760 *
3761 * Purpose: Calculate the Profile ID using MD5 Fingerprinting method.
3762 *
3763 * Args:
3764 * szFileName = name of the file whose profile ID has to be calculated,
3765 * pProfileID = array where the profileID will be stored
3766 *****************************************************************************
3767 */
3768bool CalcProfileID(const icChar *szFilename, icProfileID *pProfileID)
3769{
3770 CIccFileIO FileIO;
3771
3772 if (!FileIO.Open(szFilename, "rb")) {
3773 memset(pProfileID, 0, sizeof(icProfileID));
3774 return false;
3775 }
3776
3777 CalcProfileID(&FileIO, pProfileID);
3778 return true;
3779}
3780
3781#ifdef WIN32
3782/**
3783****************************************************************************
3784* Name: CalcProfileID
3785*
3786* Purpose: Calculate the Profile ID using MD5 Fingerprinting method.
3787*
3788* Args:
3789* szFileName = name of the file whose profile ID has to be calculated,
3790* pProfileID = array where the profileID will be stored
3791*****************************************************************************
3792*/
3793bool CalcProfileID(const icWChar *szFilename, icProfileID *pProfileID)
3794{
3795 CIccFileIO FileIO;
3796
3797 if (!FileIO.Open(szFilename, L"rb")) {
3798 memset(pProfileID, 0, sizeof(icProfileID));
3799 return false;
3800 }
3801
3802 CalcProfileID(&FileIO, pProfileID);
3803 return true;
3804}
3805#endif
3806
3807
3808#ifdef USEREFICCMAXNAMESPACE
3809} //namespace refIccMAX
3810#endif
File: IccArrayBasic.h.
icArraySignature sig
float icFloatNumber
All floating point operations/variables in IccProfLib use the icFloatNumber data type.
Definition IccDefs.h:100
char icChar
Definition IccDefs.h:109
icValidateStatus
Definition IccDefs.h:118
@ icValidateOK
Definition IccDefs.h:119
@ icValidateWarning
Definition IccDefs.h:120
@ icValidateCriticalError
Definition IccDefs.h:122
@ icValidateNonCompliant
Definition IccDefs.h:121
File: IccIO.h.
@ icSeekEnd
Definition IccIO.h:85
@ icSeekSet
Definition IccIO.h:83
void icMD5Init(MD5_CTX *context)
MD5 initialization.
Definition IccMD5.cpp:99
void icMD5Final(unsigned char *digest, MD5_CTX *context)
MD5 finalization.
Definition IccMD5.cpp:150
void icMD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputLen)
MD5 block update operation.
Definition IccMD5.cpp:114
IccMD5.H - header file for IccMD5.cpp.
File: IccCmm.h.
static bool compare_float(float x, float y, float eps=0.01f)
CIccProfile * ValidateIccProfile(CIccIO *pIO, std::string &sReport, icValidateStatus &nStatus)
Name: ValidateIccProfile.
bool SaveIccProfile(const icChar *szFilename, CIccProfile *pIcc, icProfileIDSaveMethod nWriteId)
Name: SaveIccProfile.
CIccProfile * ReadIccProfile(const icChar *szFilename, bool bUseSubProfile)
Name: ReadIccProfile.
CIccProfile * OpenIccProfile(const icChar *szFilename, bool bUseSubProfile)
Name: OpenIccProfile.
void CalcProfileID(CIccIO *pIO, icProfileID *pProfileID)
Name: CalcProfileID.
File: IccProfile.h.
File: IccTag.h.
IIccArray * icGetTagArrayHandler(CIccTag *pTag)
icValidateStatus icMaxStatus(icValidateStatus s1, icValidateStatus s2)
Name: icMaxStatus.
Definition IccUtil.cpp:244
std::string icGetSigPath(icUInt32Number nSig)
Definition IccUtil.cpp:1191
const char * icMsgValidateWarning
Definition IccUtil.cpp:90
icUInt32Number icGetSpaceSamples(icColorSpaceSignature sig)
Definition IccUtil.cpp:1303
bool icIsIllumD50(icXYZNumber xyz)
Definition IccUtil.cpp:363
icFloatNumber icFtoD(icS15Fixed16Number num)
Definition IccUtil.cpp:559
bool icIsSpaceCLR(icColorSpaceSignature sig)
Definition IccUtil.cpp:262
icS15Fixed16Number icDtoF(icFloatNumber num)
Definition IccUtil.cpp:545
const char * icMsgValidateNonCompliant
Definition IccUtil.cpp:91
const char * icMsgValidateCriticalError
Definition IccUtil.cpp:92
icFloatNumber icF16toF(icFloat16Number num)
Definition IccUtil.cpp:629
File: IccUtil.h.
static const CFAllocatorContext context
icTagTypeSignature
@ icSigUInt16ArrayType
unsigned int icUInt32Number
Class: CIccArrayNamedColor.
void SetColorSpaces(icColorSpaceSignature csPcs, icColorSpaceSignature csDevice, icSpectralColorSignature csSpectralPCS=icSigNoSpectralData, const icSpectralRange *pSpectralRange=NULL, const icSpectralRange *pBiSPectralRange=NULL)
Type: Class.
Definition IccIO.h:185
bool Attach(CIccIO *pIO, icInt32Number nSize=0, bool bOwnIO=false)
Definition IccIO.cpp:519
Type: Class.
Definition IccIO.h:150
void Detach()
Definition IccIO.cpp:437
bool Open(const icChar *szFilename, const icChar *szAttr)
Definition IccIO.cpp:382
bool Attach(FILE *f)
Definition IccIO.cpp:426
Type: Class.
Definition IccIO.h:97
virtual icInt32Number Write8(void *pBuf8, icInt32Number nNum=1)
Definition IccIO.h:105
virtual icInt32Number GetLength()
Definition IccIO.h:130
icInt32Number Write16(void *pBuf16, icInt32Number nNum=1)
Definition IccIO.cpp:122
virtual icInt32Number Read8(void *pBuf8, icInt32Number nNum=1)
Definition IccIO.h:104
icInt32Number Read16(void *pBuf16, icInt32Number nNum=1)
Definition IccIO.cpp:114
virtual icInt32Number Tell()
Definition IccIO.h:133
bool Align32()
Write operation to make sure that filelength is evenly divisible by 4.
Definition IccIO.cpp:341
icInt32Number Write32(void *pBuf32, icInt32Number nNum=1)
Definition IccIO.cpp:152
virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos)
Definition IccIO.h:132
icInt32Number Write64(void *pBuf64, icInt32Number nNum=1)
Definition IccIO.cpp:182
icInt32Number Read64(void *pBuf64, icInt32Number nNum=1)
Definition IccIO.cpp:173
icInt32Number Read32(void *pBuf32, icInt32Number nNum=1)
Definition IccIO.cpp:143
Type: Class.
Definition IccUtil.h:303
bool IsProfileIDCalculated(icProfileID *profileID)
Definition IccUtil.cpp:2305
const icChar * GetVersionName(icUInt32Number val)
Definition IccUtil.cpp:1428
const icChar * GetCmmSigName(icCmmSignature sig)
Definition IccUtil.cpp:1874
const icChar * GetProfileClassSigName(icProfileClassSignature sig)
Definition IccUtil.cpp:1804
bool IsValidSpace(icColorSpaceSignature sig)
Definition IccUtil.cpp:2531
const icChar * GetTagSigName(icTagSignature sig)
Definition IccUtil.cpp:1495
bool IsValidSpectralSpace(icColorSpaceSignature sig)
Definition IccUtil.cpp:2579
const icChar * GetPlatformSigName(icPlatformSignature sig)
Definition IccUtil.cpp:1845
const icChar * GetColorSpaceSigName(icColorSpaceSignature sig)
Definition IccUtil.cpp:1640
const icChar * GetTagTypeSigName(icTagTypeSignature sig)
Definition IccUtil.cpp:1594
const icChar * GetSigName(icUInt32Number val)
Definition IccUtil.cpp:2000
const icChar * GetRenderingIntentName(icRenderingIntent val, bool bIsV5=false)
Definition IccUtil.cpp:2091
icValidateStatus CheckData(std::string &sReport, const icDateTimeNumber &dateTime, std::string sDesc="")
Definition IccUtil.cpp:2414
Class: CIccMBB.
Definition IccTagLut.h:428
Type: Class.
icFloatNumber * entry(icUInt16Number nRow, icUInt16Number nCol=0)
icFloatNumber RowSum(icUInt16Number nRow) const
Name: CIccMatrixMath::RowSum.
void VectorScale(const icFloatNumber *vec)
Name: CIccMatrixMath::VectorScale.
virtual void VectorMult(icFloatNumber *pDst, const icFloatNumber *pSrc) const
Name: CIccMatrixMath::VectorMult.
void Scale(icFloatNumber v)
Name: CIccMatrixMath::Scale.
Type: Class.
Definition IccIO.h:217
bool Alloc(icUInt32Number nSize, bool bWrite=false)
Definition IccIO.cpp:665
virtual icInt32Number Seek(icInt32Number nOffset, icSeekVal pos)
Definition IccIO.cpp:761
icUInt8Number * GetData()
Definition IccIO.h:235
virtual icInt32Number GetLength()
Definition IccIO.cpp:752
bool Attach(icUInt8Number *pData, icUInt32Number nSize, bool bWrite=false)
Definition IccIO.cpp:686
Class: CIccTag.
virtual icTagTypeSignature GetType() const
Function: GetType()
static CIccTag * Create(icTagTypeSignature sig)
Name: CIccTag::Create.
virtual bool Read(icUInt32Number size, CIccIO *pIO)
Function: Read(size, pIO) - Read tag from file.
virtual bool IsMBBType()
virtual bool IsNumArrayType() const
virtual icArraySignature GetTagArrayType() const
virtual bool ReadAll()
Function: ReadAll() - Read All sub data for tag from file.
Class: CIccTagNamedColor2.
Class: CIccTagNumArray.
virtual bool GetValues(icFloatNumber *DstVector, icUInt32Number nStart=0, icUInt32Number nVectorSize=1) const =0
virtual icUInt32Number GetNumValues() const =0
Class: CIccTagSpectralDataInfo.
icSpectralRange m_biSpectralRange
icSpectralRange m_spectralRange
Class: CIccTagSpectralViewingConditions.
CIccMatrixMath * getObserverMatrix(const icSpectralRange &newRange) const
icFloatNumber getIlluminantCCT() const
icIlluminant getStdIllumiant() const
const icFloatNumber * getIlluminant(icSpectralRange &illumRange) const
icStandardObserver getStdObserver() const
Class: CIccTagXYZ.
icXYZNumber * GetXYZ(icUInt32Number index)
icFloatNumber * getEmissiveObserver(const icSpectralRange &range, const icFloatNumber *pWhite, icFloatNumber *obsMatrix=NULL)
Definition IccPcc.cpp:231
virtual const CIccTagSpectralViewingConditions * getPccViewingConditions()=0
CIccMatrixMath * getReflectanceObserver(const icSpectralRange &rangeRef)
Definition IccPcc.cpp:287
unsigned char icUInt8Number
Number definitions.
#define icVersionNumberV4_2
unsigned short icUInt16Number
long icInt32Number
#define icVersionNumberV4
#define icNumColorSpaceChannels(sig)
icProfileClassSignature
profileClass enumerations
@ icSigAbstractClass
@ icSigColorEncodingClass
@ icSigDisplayClass
@ icSigMaterialVisualizationClass
@ icSigOutputClass
@ icSigInputClass
@ icSigMaterialLinkClass
@ icSigColorSpaceClass
@ icSigNamedColorClass
@ icSigMaterialIdentificationClass
@ icSigLinkClass
icIlluminant
Pre-defined illuminants, used in measurement and viewing conditions type.
@ icIlluminantUnknown
@ icIlluminantD50
#define icIsSameColorSpaceType(sig, type)
#define icGetColorSpaceType(sig)
@ icSigNoMCSData
icColorSpaceSignature
Color Space Signatures.
@ icSig14colorData
@ icSigLabData
@ icSig2colorData
@ icSig8colorData
@ icSigNoColorData
@ icSig10colorData
@ icSig7colorData
@ icSig9colorData
@ icSigXYZData
@ icSig13colorData
@ icSigSrcMCSChannelData
@ icSig6colorData
@ icSig4colorData
@ icSig12colorData
@ icSig11colorData
@ icSigGrayData
@ icSig15colorData
@ icSig3colorData
@ icSig5colorData
#define icMagicNumber
Defines used in the specification.
icUInt32Number icSignature
@ icSigCicpType
@ icSigSpectralDataInfoType
@ icSigUInt8ArrayType
@ icSigUtf8TextType
@ icSigProfileSequenceDescType
@ icSigEmbeddedProfileType
@ icSigTagArrayType
@ icSigMultiProcessElementType
@ icSigMeasurementType
@ icSigTagStructType
@ icSigEmbeddedHeightImageType
@ icSigFloat16ArrayType
@ icSigParametricCurveType
@ icSigLut8Type
@ icSigMultiLocalizedUnicodeType
@ icSigXYZType
@ icSigLutBtoAType
@ icSigResponseCurveSet16Type
@ icSigS15Fixed16ArrayType
@ icSigColorantTableType
@ icSigViewingConditionsType
@ icSigTextDescriptionType
@ icSigEmbeddedNormalImageType
@ icSigCurveType
@ icSigColorantOrderType
@ icSigDateTimeType
@ icSigLut16Type
@ icSigTextType
@ icSigZipXmlType
@ icSigNamedColor2Type
@ icSigChromaticityType
@ icSigSignatureType
@ icSigZipUtf8TextType
@ icSigFloat32ArrayType
@ icSigLutAtoBType
@ icSigGamutBoundaryDescType
icStructSignature
Tag Structure type signatures.
@ icSigBRDFStruct
@ icSigColorEncodingParamsSruct
#define icVersionNumberV5
@ icSigReflectanceSpectralData
@ icSigTransmisionSpectralData
@ icSigNoSpectralData
@ icSigBiSpectralReflectanceData
@ icSigRadiantSpectralData
@ icSigSparseMatrixReflectanceData
icPlatformSignature
Platform Signatures.
@ icSigSGI
@ icSigTaligent
@ icSigMacintosh
@ icSigUnkownPlatform
@ icSigSolaris
@ icSigMicrosoft
icArraySignature
Tag Array type signatures.
@ icSigNamedColorArray
@ icSigUtf8TextTypeArray
icTagSignature
public tags and sizes
@ icSigEmbeddedV5ProfileTag
@ icSigBToD0Tag
@ icSigGrayTRCTag
@ icSigBrdfColorimetricParameter3Tag
@ icSigPerceptualRenderingIntentGamutTag
@ icSigBToA2Tag
@ icSigDeviceMfgDescTag
@ icSigGamutBoundaryDescription3Tag
@ icSigColorantOrderTag
@ icSigBRDFDToB0Tag
@ icSigViewingConditionsTag
@ icSigAToB3Tag
@ icSigBlueMatrixColumnTag
@ icSigColorantInfoTag
@ icSigBrdfColorimetricParameter2Tag
@ icSigGamutBoundaryDescription2Tag
@ icSigGamutBoundaryDescription1Tag
@ icSigGamutBoundaryDescription0Tag
@ icSigMaterialDefaultValuesTag
@ icSigColorSpaceNameTag
@ icSigMToS3Tag
@ icSigBrdfSpectralParameter0Tag
@ icSigGreenTRCTag
@ icSigMeasurementTag
@ icSigBrdfSpectralParameter1Tag
@ icSigBToD2Tag
@ icSigAToM0Tag
@ icSigPreview1Tag
@ icSigSpectralDataInfoTag
@ icSigCicpTag
@ icSigSaturationRenderingIntentGamutTag
@ icSigMToB0Tag
@ icSigAToB0Tag
@ icSigDeviceModelDescTag
@ icSigCxFTag
@ icSigMToB3Tag
@ icSigBrdfSpectralParameter3Tag
@ icSigBToA1Tag
@ icSigColorantTableTag
@ icSigDToB3Tag
@ icSigAToB2Tag
@ icSigBRDFAToB1Tag
@ icSigBRDFAToB2Tag
@ icSigProfileSequenceDescTag
@ icSigBRDFAToB0Tag
@ icSigDToB0Tag
@ icSigSpectralWhitePointTag
@ icSigBToD3Tag
@ icSigBToA0Tag
@ icSigMToS0Tag
@ icSigRedTRCTag
@ icSigMToS2Tag
@ icSigBToD1Tag
@ icSigBlueTRCTag
@ icSigSurfaceMapTag
@ icSigMToB1Tag
@ icSigProfileDescriptionTag
@ icSigColorantInfoOutTag
@ icSigRedColorantTag
@ icSigGreenMatrixColumnTag
@ icSigMediaBlackPointTag
@ icSigCharTargetTag
@ icSigCopyrightTag
@ icSigOutputResponseTag
@ icSigChromaticAdaptationTag
@ icSigMediaWhitePointTag
@ icSigViewingCondDescTag
@ icSigBRDFAToB3Tag
@ icSigAToB1Tag
@ icSigColorantTableOutTag
@ icSigColorEncodingParamsTag
@ icSigBToA3Tag
@ icSigColorantOrderOutTag
@ icSigBrdfSpectralParameter2Tag
@ icSigChromaticityTag
@ icSigCalibrationDateTimeTag
@ icSigPreview0Tag
@ icSigNamedColor2Tag
@ icSigReferenceNameTag
@ icSigGreenColorantTag
@ icSigDToB2Tag
@ icSigLuminanceTag
@ icSigRedMatrixColumnTag
@ icSigGamutTag
@ icSigMToA0Tag
@ icSigTechnologyTag
@ icSigMToS1Tag
@ icSigDToB1Tag
@ icSigBRDFDToB1Tag
@ icSigBrdfColorimetricParameter0Tag
@ icSigMaterialTypeArrayTag
@ icSigBRDFDToB2Tag
@ icSigPreview2Tag
@ icSigBlueColorantTag
@ icSigBrdfColorimetricParameter1Tag
@ icSigMToB2Tag
@ icSigBRDFDToB3Tag
#define icDefaultLuminance
icRenderingIntent
Rendering Intents, used in the profile header.
@ icPerceptual
@ icRelativeColorimetric
@ icAbsoluteColorimetric
@ icSaturation
icStandardObserver
Standard Observer, used in the measurmentType tag.
@ icStdObsUnknown
@ icStdObs1931TwoDegrees
#define icSigGamutData
Convenience Enum Definitions - Not defined in ICC specification.
icCmmSignature
CMM signatures from the signature registry (as of Mar 6, 2018)
@ icSigDemoIccMAX
@ icSigAgfa
@ icSigColorGearC
@ icSigColorGear
@ icSigTheImagingFactory
@ icSigLogoSync
@ icSigWindowsCMS
@ icSigRolfGierling
@ icSigColorGearLite
@ icSigKonicaMinolta
@ icSigUnknownCmm
@ icSigKodak
@ icSigSampleICC
@ icSigArgyllCMS
@ icSigHarlequinRIP
@ icSigToshiba
@ icSigExactScan
@ icSigHeidelberg
@ icSigOnyxGraphics
@ icSigMutoh
@ icSigEFI
@ icSigZoran
@ icSigFujiFilm
@ icSigAdobe
@ icSigLittleCMS
@ icSigRefIccMAX
@ icSigVivo
@ icSigApple
@ icSigWareToGo
#define icVersionNumberV4_4
MD5 context.
Definition IccMD5.h:52
icFloat32Number Z
icFloat32Number Y
icFloat32Number X
spectral range
icUInt16Number steps
Lists of tags, tags, profile header and profile structure.
icS15Fixed16Number Y
icS15Fixed16Number Z
icS15Fixed16Number X
Profile ID.
icUInt8Number ID8[16]