1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2011 Marti Maria Saguer
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //---------------------------------------------------------------------------------
27 #include "lcms2_internal.h"
29 // Tag Serialization -----------------------------------------------------------------------------
30 // This file implements every single tag and tag type as described in the ICC spec. Some types
31 // have been deprecated, like ncl and Data. There is no implementation for those types as there
32 // are no profiles holding them. The programmer can also extend this list by defining his own types
33 // by using the appropiate plug-in. There are three types of plug ins regarding that. First type
34 // allows to define new tags using any existing type. Next plug-in type allows to define new types
35 // and the third one is very specific: allows to extend the number of elements in the multiprofile
36 // elements special type.
37 //--------------------------------------------------------------------------------------------------
40 #define cmsCorbisBrokenXYZtype ((cmsTagTypeSignature) 0x17A505B8)
41 #define cmsMonacoBrokenCurveType ((cmsTagTypeSignature) 0x9478ee00)
43 // This is the linked list that keeps track of the defined types
44 typedef struct _cmsTagTypeLinkedList_st {
46 cmsTagTypeHandler Handler;
47 struct _cmsTagTypeLinkedList_st* Next;
49 } _cmsTagTypeLinkedList;
51 // Some macros to define callbacks.
52 #define READ_FN(x) Type_##x##_Read
53 #define WRITE_FN(x) Type_##x##_Write
54 #define FREE_FN(x) Type_##x##_Free
55 #define DUP_FN(x) Type_##x##_Dup
57 // Helper macro to define a handler. Callbacks do have a fixed naming convention.
58 #define TYPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x), NULL, 0 }
60 // Helper macro to define a MPE handler. Callbacks do have a fixed naming convention
61 #define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 }
63 // Register a new type handler. This routine is shared between normal types and MPE
65 cmsBool RegisterTypesPlugin(cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount)
67 cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
68 _cmsTagTypeLinkedList *pt, *Anterior = NULL;
70 // Calling the function with NULL as plug-in would unregister the plug in.
73 LinkedList[DefaultListCount-1].Next = NULL;
77 pt = Anterior = LinkedList;
80 if (Plugin->Handler.Signature == pt -> Handler.Signature) {
81 pt ->Handler = Plugin ->Handler; // Replace old behaviour.
82 // Note that since no memory is allocated, unregister does not
91 // Registering happens in plug-in memory pool
92 pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagTypeLinkedList));
93 if (pt == NULL) return FALSE;
95 pt ->Handler = Plugin ->Handler;
99 Anterior -> Next = pt;
104 // Return handler for a given type or NULL if not found. Shared between normal types and MPE
106 cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList)
108 _cmsTagTypeLinkedList* pt;
110 for (pt = LinkedList;
114 if (sig == pt -> Handler.Signature) return &pt ->Handler;
121 // Auxiliar to convert UTF-32 to UTF-16 in some cases
123 cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array)
127 _cmsAssert(io != NULL);
128 _cmsAssert(Array != NULL);
130 for (i=0; i < n; i++) {
131 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE;
138 cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
143 _cmsAssert(io != NULL);
145 for (i=0; i < n; i++) {
149 if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
150 Array[i] = (wchar_t) tmp;
153 if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
160 // To deal with position tables
161 typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
165 cmsUInt32Number SizeOfTag);
167 // Helper function to deal with position tables as decribed in ICC spec 4.3
168 // A table of n elements is readed, where first comes n records containing offsets and sizes and
169 // then a block containing the data itself. This allows to reuse same data in more than one entry
171 cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
173 cmsUInt32Number Count,
174 cmsUInt32Number BaseOffset,
176 PositionTableEntryFn ElementFn)
179 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
181 // Let's take the offsets to each element
182 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
183 if (ElementOffsets == NULL) goto Error;
185 ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
186 if (ElementSizes == NULL) goto Error;
188 for (i=0; i < Count; i++) {
190 if (!_cmsReadUInt32Number(io, &ElementOffsets[i])) goto Error;
191 if (!_cmsReadUInt32Number(io, &ElementSizes[i])) goto Error;
193 ElementOffsets[i] += BaseOffset;
196 // Seek to each element and read it
197 for (i=0; i < Count; i++) {
199 if (!io -> Seek(io, ElementOffsets[i])) goto Error;
201 // This is the reader callback
202 if (!ElementFn(self, io, Cargo, i, ElementSizes[i])) goto Error;
206 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
207 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
211 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
212 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
216 // Same as anterior, but for write position tables
218 cmsBool WritePositionTable(struct _cms_typehandler_struct* self,
220 cmsUInt32Number SizeOfTag,
221 cmsUInt32Number Count,
222 cmsUInt32Number BaseOffset,
224 PositionTableEntryFn ElementFn)
227 cmsUInt32Number DirectoryPos, CurrentPos, Before;
228 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
231 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
232 if (ElementOffsets == NULL) goto Error;
234 ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
235 if (ElementSizes == NULL) goto Error;
237 // Keep starting position of curve offsets
238 DirectoryPos = io ->Tell(io);
240 // Write a fake directory to be filled latter on
241 for (i=0; i < Count; i++) {
243 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
244 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
247 // Write each element. Keep track of the size as well.
248 for (i=0; i < Count; i++) {
250 Before = io ->Tell(io);
251 ElementOffsets[i] = Before - BaseOffset;
253 // Callback to write...
254 if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error;
257 ElementSizes[i] = io ->Tell(io) - Before;
260 // Write the directory
261 CurrentPos = io ->Tell(io);
262 if (!io ->Seek(io, DirectoryPos)) goto Error;
264 for (i=0; i < Count; i++) {
265 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
266 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
269 if (!io ->Seek(io, CurrentPos)) goto Error;
271 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
272 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
276 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
277 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
282 // ********************************************************************************
283 // Type XYZ. Only one value is allowed
284 // ********************************************************************************
286 //The XYZType contains an array of three encoded values for the XYZ tristimulus
287 //values. Tristimulus values must be non-negative. The signed encoding allows for
288 //implementation optimizations by minimizing the number of fixed formats.
292 void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
297 xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ));
298 if (xyz == NULL) return NULL;
300 if (!_cmsReadXYZNumber(io, xyz)) {
301 _cmsFree(self ->ContextID, xyz);
308 cmsUNUSED_PARAMETER(SizeOfTag);
312 cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
314 return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr);
316 cmsUNUSED_PARAMETER(nItems);
317 cmsUNUSED_PARAMETER(self);
321 void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
323 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ));
325 cmsUNUSED_PARAMETER(n);
329 void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr)
331 _cmsFree(self ->ContextID, Ptr);
336 cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data)
338 return cmsSigXYZType;
340 cmsUNUSED_PARAMETER(ICCVersion);
341 cmsUNUSED_PARAMETER(Data);
345 // ********************************************************************************
346 // Type chromaticity. Only one value is allowed
347 // ********************************************************************************
348 // The chromaticity tag type provides basic chromaticity data and type of
349 // phosphors or colorants of a monitor to applications and utilities.
352 void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
354 cmsCIExyYTRIPLE* chrm;
355 cmsUInt16Number nChans, Table;
358 chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE));
359 if (chrm == NULL) return NULL;
361 if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
363 // Let's recover from a bug introduced in early versions of lcms1
364 if (nChans == 0 && SizeOfTag == 32) {
366 if (!_cmsReadUInt16Number(io, NULL)) goto Error;
367 if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
370 if (nChans != 3) goto Error;
372 if (!_cmsReadUInt16Number(io, &Table)) goto Error;
374 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error;
375 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error;
379 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error;
380 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error;
382 chrm ->Green.Y = 1.0;
384 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error;
385 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error;
393 _cmsFree(self ->ContextID, (void*) chrm);
396 cmsUNUSED_PARAMETER(SizeOfTag);
400 cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io)
402 if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE;
403 if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE;
409 cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
411 cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr;
413 if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels
414 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table
416 if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE;
417 if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE;
418 if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE;
422 cmsUNUSED_PARAMETER(nItems);
423 cmsUNUSED_PARAMETER(self);
427 void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
429 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE));
430 cmsUNUSED_PARAMETER(n);
434 void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr)
436 _cmsFree(self ->ContextID, Ptr);
440 // ********************************************************************************
441 // Type cmsSigColorantOrderType
442 // ********************************************************************************
444 // This is an optional tag which specifies the laydown order in which colorants will
445 // be printed on an n-colorant device. The laydown order may be the same as the
446 // channel generation order listed in the colorantTableTag or the channel order of a
447 // colour space such as CMYK, in which case this tag is not needed. When this is not
448 // the case (for example, ink-towers sometimes use the order KCMY), this tag may be
449 // used to specify the laydown order of the colorants.
453 void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
455 cmsUInt8Number* ColorantOrder;
456 cmsUInt32Number Count;
459 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
460 if (Count > cmsMAXCHANNELS) return NULL;
462 ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number));
463 if (ColorantOrder == NULL) return NULL;
465 // We use FF as end marker
466 memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
468 if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) {
470 _cmsFree(self ->ContextID, (void*) ColorantOrder);
475 return (void*) ColorantOrder;
477 cmsUNUSED_PARAMETER(SizeOfTag);
481 cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
483 cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr;
484 cmsUInt32Number i, sz, Count;
487 for (Count=i=0; i < cmsMAXCHANNELS; i++) {
488 if (ColorantOrder[i] != 0xFF) Count++;
491 if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
493 sz = Count * sizeof(cmsUInt8Number);
494 if (!io -> Write(io, sz, ColorantOrder)) return FALSE;
498 cmsUNUSED_PARAMETER(nItems);
499 cmsUNUSED_PARAMETER(self);
503 void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
505 return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
507 cmsUNUSED_PARAMETER(n);
512 void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr)
514 _cmsFree(self ->ContextID, Ptr);
517 // ********************************************************************************
518 // Type cmsSigS15Fixed16ArrayType
519 // ********************************************************************************
520 // This type represents an array of generic 4-byte/32-bit fixed point quantity.
521 // The number of values is determined from the size of the tag.
524 void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
526 cmsFloat64Number* array_double;
527 cmsUInt32Number i, n;
530 n = SizeOfTag / sizeof(cmsUInt32Number);
531 array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
532 if (array_double == NULL) return NULL;
534 for (i=0; i < n; i++) {
536 if (!_cmsRead15Fixed16Number(io, &array_double[i])) {
538 _cmsFree(self ->ContextID, array_double);
544 return (void*) array_double;
548 cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
550 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
553 for (i=0; i < nItems; i++) {
555 if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE;
560 cmsUNUSED_PARAMETER(self);
564 void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
566 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
571 void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
573 _cmsFree(self ->ContextID, Ptr);
576 // ********************************************************************************
577 // Type cmsSigU16Fixed16ArrayType
578 // ********************************************************************************
579 // This type represents an array of generic 4-byte/32-bit quantity.
580 // The number of values is determined from the size of the tag.
584 void *Type_U16Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
586 cmsFloat64Number* array_double;
588 cmsUInt32Number i, n;
591 n = SizeOfTag / sizeof(cmsUInt32Number);
592 array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
593 if (array_double == NULL) return NULL;
595 for (i=0; i < n; i++) {
597 if (!_cmsReadUInt32Number(io, &v)) {
598 _cmsFree(self ->ContextID, (void*) array_double);
602 // Convert to cmsFloat64Number
603 array_double[i] = (cmsFloat64Number) (v / 65536.0);
607 return (void*) array_double;
611 cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
613 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
616 for (i=0; i < nItems; i++) {
618 cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5);
620 if (!_cmsWriteUInt32Number(io, v)) return FALSE;
625 cmsUNUSED_PARAMETER(self);
630 void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
632 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
636 void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
638 _cmsFree(self ->ContextID, Ptr);
641 // ********************************************************************************
642 // Type cmsSigSignatureType
643 // ********************************************************************************
645 // The signatureType contains a four-byte sequence, Sequences of less than four
646 // characters are padded at the end with spaces, 20h.
647 // Typically this type is used for registered tags that can be displayed on many
648 // development systems as a sequence of four characters.
651 void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
653 cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature));
654 if (SigPtr == NULL) return NULL;
656 if (!_cmsReadUInt32Number(io, SigPtr)) return NULL;
661 cmsUNUSED_PARAMETER(SizeOfTag);
665 cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
667 cmsSignature* SigPtr = (cmsSignature*) Ptr;
669 return _cmsWriteUInt32Number(io, *SigPtr);
671 cmsUNUSED_PARAMETER(nItems);
672 cmsUNUSED_PARAMETER(self);
676 void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
678 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature));
682 void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr)
684 _cmsFree(self ->ContextID, Ptr);
688 // ********************************************************************************
689 // Type cmsSigTextType
690 // ********************************************************************************
692 // The textType is a simple text structure that contains a 7-bit ASCII text string.
693 // The length of the string is obtained by subtracting 8 from the element size portion
694 // of the tag itself. This string must be terminated with a 00h byte.
697 void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
702 // Create a container
703 mlu = cmsMLUalloc(self ->ContextID, 1);
704 if (mlu == NULL) return NULL;
708 // We need to store the "\0" at the end, so +1
709 if (SizeOfTag == UINT_MAX) goto Error;
711 Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
712 if (Text == NULL) goto Error;
714 if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error;
716 // Make sure text is properly ended
721 if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
723 _cmsFree(self ->ContextID, Text);
730 _cmsFree(self ->ContextID, Text);
735 // The conversion implies to choose a language. So, we choose the actual language.
737 cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
739 cmsMLU* mlu = (cmsMLU*) Ptr;
740 cmsUInt32Number size;
744 // Get the size of the string. Note there is an extra "\0" at the end
745 size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
746 if (size == 0) return FALSE; // Cannot be zero!
749 Text = (char*) _cmsMalloc(self ->ContextID, size);
750 cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
752 // Write it, including separator
753 rc = io ->Write(io, size, Text);
755 _cmsFree(self ->ContextID, Text);
758 cmsUNUSED_PARAMETER(nItems);
762 void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
764 return (void*) cmsMLUdup((cmsMLU*) Ptr);
766 cmsUNUSED_PARAMETER(n);
767 cmsUNUSED_PARAMETER(self);
772 void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr)
774 cmsMLU* mlu = (cmsMLU*) Ptr;
778 cmsUNUSED_PARAMETER(self);
782 cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data)
784 if (ICCVersion >= 4.0)
785 return cmsSigMultiLocalizedUnicodeType;
787 return cmsSigTextType;
789 cmsUNUSED_PARAMETER(Data);
793 // ********************************************************************************
794 // Type cmsSigDataType
795 // ********************************************************************************
797 // General purpose data type
799 void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
802 cmsUInt32Number LenOfData;
806 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
808 LenOfData = SizeOfTag - sizeof(cmsUInt32Number);
809 if (LenOfData > INT_MAX) return NULL;
811 BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1);
812 if (BinData == NULL) return NULL;
814 BinData ->len = LenOfData;
815 if (!_cmsReadUInt32Number(io, &BinData->flag)) {
816 _cmsFree(self ->ContextID, BinData);
820 if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) {
822 _cmsFree(self ->ContextID, BinData);
828 return (void*) BinData;
833 cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
835 cmsICCData* BinData = (cmsICCData*) Ptr;
837 if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE;
839 return io ->Write(io, BinData ->len, BinData ->data);
841 cmsUNUSED_PARAMETER(nItems);
842 cmsUNUSED_PARAMETER(self);
847 void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
849 cmsICCData* BinData = (cmsICCData*) Ptr;
851 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1);
853 cmsUNUSED_PARAMETER(n);
857 void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr)
859 _cmsFree(self ->ContextID, Ptr);
862 // ********************************************************************************
863 // Type cmsSigTextDescriptionType
864 // ********************************************************************************
867 void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
871 cmsUInt32Number AsciiCount;
872 cmsUInt32Number i, UnicodeCode, UnicodeCount;
873 cmsUInt16Number ScriptCodeCode, Dummy;
874 cmsUInt8Number ScriptCodeCount;
878 // One dword should be there
879 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
882 if (!_cmsReadUInt32Number(io, &AsciiCount)) return NULL;
883 SizeOfTag -= sizeof(cmsUInt32Number);
886 if (SizeOfTag < AsciiCount) return NULL;
888 // All seems Ok, allocate the container
889 mlu = cmsMLUalloc(self ->ContextID, 1);
890 if (mlu == NULL) return NULL;
892 // As many memory as size of tag
893 Text = (char*) _cmsMalloc(self ->ContextID, AsciiCount + 1);
894 if (Text == NULL) goto Error;
897 if (io ->Read(io, Text, sizeof(char), AsciiCount) != AsciiCount) goto Error;
898 SizeOfTag -= AsciiCount;
900 // Make sure there is a terminator
901 Text[AsciiCount] = 0;
903 // Set the MLU entry. From here we can be tolerant to wrong types
904 if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
905 _cmsFree(self ->ContextID, (void*) Text);
909 if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done;
910 if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done;
911 if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done;
912 SizeOfTag -= 2* sizeof(cmsUInt32Number);
914 if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
916 for (i=0; i < UnicodeCount; i++) {
917 if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done;
919 SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number);
921 // Skip ScriptCode code if present. Some buggy profiles does have less
922 // data that stricttly required. We need to skip it as this type may come
923 // embedded in other types.
925 if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) {
927 if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done;
928 if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done;
931 for (i=0; i < 67; i++) {
932 if (!io ->Read(io, &Dummy, sizeof(cmsUInt8Number), 1)) goto Error;
942 if (Text) _cmsFree(self ->ContextID, (void*) Text);
943 if (mlu) cmsMLUfree(mlu);
948 // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
950 cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
952 cmsMLU* mlu = (cmsMLU*) Ptr;
954 wchar_t *Wide = NULL;
955 cmsUInt32Number len, len_aligned, len_filler_alignment;
959 // Used below for writting zeroes
960 memset(Filler, 0, sizeof(Filler));
962 // Get the len of string
963 len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
965 // From ICC3.4: It has been found that textDescriptionType can contain misaligned data
966 //(see clause 4.1 for the definition of
\93aligned
\94). Because the Unicode language
967 // code and Unicode count immediately follow the ASCII description, their
968 // alignment is not correct if the ASCII count is not a multiple of four. The
969 // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
970 // writing software must be written carefully in order to handle these alignment
973 // Compute an aligned size
974 len_aligned = _cmsALIGNLONG(len);
975 len_filler_alignment = len_aligned - len;
980 Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char));
981 Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t));
984 // Create independent buffers
985 Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char));
986 if (Text == NULL) goto Error;
988 Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t));
989 if (Wide == NULL) goto Error;
991 // Get both representations.
992 cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char));
993 cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t));
996 // * cmsUInt32Number count; * Description length
997 // * cmsInt8Number desc[count] * NULL terminated ascii string
998 // * cmsUInt32Number ucLangCode; * UniCode language code
999 // * cmsUInt32Number ucCount; * UniCode description length
1000 // * cmsInt16Number ucDesc[ucCount];* The UniCode description
1001 // * cmsUInt16Number scCode; * ScriptCode code
1002 // * cmsUInt8Number scCount; * ScriptCode count
1003 // * cmsInt8Number scDesc[67]; * ScriptCode Description
1005 if (!_cmsWriteUInt32Number(io, len_aligned)) goto Error;
1006 if (!io ->Write(io, len, Text)) goto Error;
1007 if (!io ->Write(io, len_filler_alignment, Filler)) goto Error;
1009 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode
1011 // This part is tricky: we need an aligned tag size, and the ScriptCode part
1012 // takes 70 bytes, so we need 2 extra bytes to do the alignment
1014 if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error;
1016 // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
1017 if (!_cmsWriteWCharArray(io, len, Wide)) goto Error;
1018 if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error;
1020 // ScriptCode Code & count (unused)
1021 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
1022 if (!_cmsWriteUInt8Number(io, 0)) goto Error;
1024 if (!io ->Write(io, 67, Filler)) goto Error;
1029 if (Text) _cmsFree(self ->ContextID, Text);
1030 if (Wide) _cmsFree(self ->ContextID, Wide);
1034 cmsUNUSED_PARAMETER(nItems);
1039 void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1041 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1043 cmsUNUSED_PARAMETER(n);
1044 cmsUNUSED_PARAMETER(self);
1048 void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr)
1050 cmsMLU* mlu = (cmsMLU*) Ptr;
1055 cmsUNUSED_PARAMETER(self);
1060 cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data)
1062 if (ICCVersion >= 4.0)
1063 return cmsSigMultiLocalizedUnicodeType;
1065 return cmsSigTextDescriptionType;
1067 cmsUNUSED_PARAMETER(Data);
1071 // ********************************************************************************
1072 // Type cmsSigCurveType
1073 // ********************************************************************************
1076 void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1078 cmsUInt32Number Count;
1079 cmsToneCurve* NewGamma;
1080 cmsUInt16Number Linear[2] = { 0, 0xffff };
1084 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1090 NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, 2, Linear);
1091 if (!NewGamma) return NULL;
1095 case 1: // Specified as the exponent of gamma function
1097 cmsUInt16Number SingleGammaFixed;
1098 cmsFloat64Number SingleGamma;
1100 if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL;
1101 SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed);
1104 return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1109 NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
1110 if (!NewGamma) return NULL;
1112 if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL;
1118 cmsUNUSED_PARAMETER(SizeOfTag);
1123 cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1125 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1127 if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) {
1129 // Single gamma, preserve number
1130 cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]);
1132 if (!_cmsWriteUInt32Number(io, 1)) return FALSE;
1133 if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE;
1138 if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE;
1139 return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16);
1141 cmsUNUSED_PARAMETER(nItems);
1142 cmsUNUSED_PARAMETER(self);
1147 void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1149 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1151 cmsUNUSED_PARAMETER(n);
1152 cmsUNUSED_PARAMETER(self);
1156 void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1158 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1160 cmsFreeToneCurve(gamma);
1163 cmsUNUSED_PARAMETER(self);
1167 // ********************************************************************************
1168 // Type cmsSigParametricCurveType
1169 // ********************************************************************************
1172 // Decide which curve type to use on writting
1174 cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data)
1176 cmsToneCurve* Curve = (cmsToneCurve*) Data;
1178 if (ICCVersion < 4.0) return cmsSigCurveType;
1179 if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric
1180 if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves
1182 return cmsSigParametricCurveType;
1186 void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1188 static const int ParamsByType[] = { 1, 3, 4, 5, 7 };
1189 cmsFloat64Number Params[10];
1190 cmsUInt16Number Type;
1192 cmsToneCurve* NewGamma;
1194 if (!_cmsReadUInt16Number(io, &Type)) return NULL;
1195 if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved
1199 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type);
1203 memset(Params, 0, sizeof(Params));
1204 n = ParamsByType[Type];
1206 for (i=0; i < n; i++) {
1208 if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL;
1211 NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params);
1216 cmsUNUSED_PARAMETER(SizeOfTag);
1221 cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1223 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1224 int i, nParams, typen;
1225 static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
1227 typen = Curve -> Segments[0].Type;
1229 if (Curve ->nSegments > 1 || typen < 1) {
1231 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written");
1236 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve");
1240 nParams = ParamsByType[typen];
1242 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE;
1243 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved
1245 for (i=0; i < nParams; i++) {
1247 if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE;
1252 cmsUNUSED_PARAMETER(nItems);
1256 void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1258 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1260 cmsUNUSED_PARAMETER(n);
1261 cmsUNUSED_PARAMETER(self);
1265 void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1267 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1269 cmsFreeToneCurve(gamma);
1272 cmsUNUSED_PARAMETER(self);
1276 // ********************************************************************************
1277 // Type cmsSigDateTimeType
1278 // ********************************************************************************
1280 // A 12-byte value representation of the time and date, where the byte usage is assigned
1281 // as specified in table 1. The actual values are encoded as 16-bit unsigned integers
1282 // (uInt16Number - see 5.1.6).
1284 // All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
1285 // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
1286 // time to UTC when setting these values. Programmes that display these values may show
1287 // the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
1288 // display both UTC and local versions of the dateTimeNumber.
1291 void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1293 cmsDateTimeNumber timestamp;
1294 struct tm * NewDateTime;
1297 NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm));
1298 if (NewDateTime == NULL) return NULL;
1300 if (io->Read(io, ×tamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL;
1302 _cmsDecodeDateTimeNumber(×tamp, NewDateTime);
1307 cmsUNUSED_PARAMETER(SizeOfTag);
1312 cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1314 struct tm * DateTime = (struct tm*) Ptr;
1315 cmsDateTimeNumber timestamp;
1317 _cmsEncodeDateTimeNumber(×tamp, DateTime);
1318 if (!io ->Write(io, sizeof(cmsDateTimeNumber), ×tamp)) return FALSE;
1322 cmsUNUSED_PARAMETER(nItems);
1323 cmsUNUSED_PARAMETER(self);
1327 void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1329 return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm));
1331 cmsUNUSED_PARAMETER(n);
1335 void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr)
1337 _cmsFree(self ->ContextID, Ptr);
1342 // ********************************************************************************
1343 // Type icMeasurementType
1344 // ********************************************************************************
1347 The measurementType information refers only to the internal profile data and is
1348 meant to provide profile makers an alternative to the default measurement
1353 void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1355 cmsICCMeasurementConditions mc;
1357 if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
1358 if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL;
1359 if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
1360 if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL;
1361 if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL;
1364 return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions));
1366 cmsUNUSED_PARAMETER(SizeOfTag);
1371 cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1373 cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr;
1375 if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE;
1376 if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE;
1377 if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE;
1378 if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE;
1379 if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE;
1383 cmsUNUSED_PARAMETER(nItems);
1384 cmsUNUSED_PARAMETER(self);
1388 void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1390 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions));
1392 cmsUNUSED_PARAMETER(n);
1396 void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr)
1398 _cmsFree(self ->ContextID, Ptr);
1402 // ********************************************************************************
1403 // Type cmsSigMultiLocalizedUnicodeType
1404 // ********************************************************************************
1406 // Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
1407 // Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
1408 // taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
1412 void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1415 cmsUInt32Number Count, RecLen, NumOfWchar;
1416 cmsUInt32Number SizeOfHeader;
1417 cmsUInt32Number Len, Offset;
1420 cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition;
1423 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1424 if (!_cmsReadUInt32Number(io, &RecLen)) return NULL;
1428 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "multiLocalizedUnicodeType of len != 12 is not supported.");
1432 mlu = cmsMLUalloc(self ->ContextID, Count);
1433 if (mlu == NULL) return NULL;
1435 mlu ->UsedEntries = Count;
1437 SizeOfHeader = 12 * Count + sizeof(_cmsTagBase);
1438 LargestPosition = 0;
1440 for (i=0; i < Count; i++) {
1442 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error;
1443 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error;
1445 // Now deal with Len and offset.
1446 if (!_cmsReadUInt32Number(io, &Len)) goto Error;
1447 if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
1449 // Check for overflow
1450 if (Offset < (SizeOfHeader + 8)) goto Error;
1452 // True begin of the string
1453 BeginOfThisString = Offset - SizeOfHeader - 8;
1455 // Ajust to wchar_t elements
1456 mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1457 mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1459 // To guess maximum size, add offset + len
1460 EndOfThisString = BeginOfThisString + Len;
1461 if (EndOfThisString > LargestPosition)
1462 LargestPosition = EndOfThisString;
1465 // Now read the remaining of tag and fill all strings. Substract the directory
1466 SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1468 Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
1469 if (Block == NULL) goto Error;
1471 NumOfWchar = SizeOfTag / sizeof(wchar_t);
1473 if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error;
1475 mlu ->MemPool = Block;
1476 mlu ->PoolSize = SizeOfTag;
1477 mlu ->PoolUsed = SizeOfTag;
1483 if (mlu) cmsMLUfree(mlu);
1488 cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1490 cmsMLU* mlu =(cmsMLU*) Ptr;
1491 cmsUInt32Number HeaderSize;
1492 cmsUInt32Number Len, Offset;
1497 // Empty placeholder
1498 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
1499 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1503 if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
1504 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1506 HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
1508 for (i=0; i < mlu ->UsedEntries; i++) {
1510 Len = mlu ->Entries[i].Len;
1511 Offset = mlu ->Entries[i].StrW;
1513 Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
1514 Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8;
1516 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE;
1517 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE;
1518 if (!_cmsWriteUInt32Number(io, Len)) return FALSE;
1519 if (!_cmsWriteUInt32Number(io, Offset)) return FALSE;
1522 if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE;
1526 cmsUNUSED_PARAMETER(nItems);
1527 cmsUNUSED_PARAMETER(self);
1532 void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1534 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1536 cmsUNUSED_PARAMETER(n);
1537 cmsUNUSED_PARAMETER(self);
1541 void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr)
1543 cmsMLUfree((cmsMLU*) Ptr);
1546 cmsUNUSED_PARAMETER(self);
1550 // ********************************************************************************
1551 // Type cmsSigLut8Type
1552 // ********************************************************************************
1554 // Decide which LUT type to use on writting
1556 cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data)
1558 cmsPipeline* Lut = (cmsPipeline*) Data;
1560 if (ICCVersion < 4.0) {
1561 if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1562 return cmsSigLut16Type;
1565 return cmsSigLutAtoBType;
1570 cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data)
1572 cmsPipeline* Lut = (cmsPipeline*) Data;
1574 if (ICCVersion < 4.0) {
1575 if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1576 return cmsSigLut16Type;
1579 return cmsSigLutBtoAType;
1584 This structure represents a colour transform using tables of 8-bit precision.
1585 This type contains four processing elements: a 3 by 3 matrix (which shall be
1586 the identity matrix unless the input colour space is XYZ), a set of one dimensional
1587 input tables, a multidimensional lookup table, and a set of one dimensional output
1588 tables. Data is processed using these elements via the following sequence:
1589 (matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables)
1591 Byte Position Field Length (bytes) Content Encoded as...
1592 8 1 Number of Input Channels (i) uInt8Number
1593 9 1 Number of Output Channels (o) uInt8Number
1594 10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number
1595 11 1 Reserved for padding (fill with 00h)
1597 12..15 4 Encoded e00 parameter s15Fixed16Number
1601 // Read 8 bit tables as gamma functions
1603 cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels)
1606 cmsUInt8Number* Temp = NULL;
1608 cmsToneCurve* Tables[cmsMAXCHANNELS];
1610 if (nChannels > cmsMAXCHANNELS) return FALSE;
1611 if (nChannels <= 0) return FALSE;
1613 memset(Tables, 0, sizeof(Tables));
1615 Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256);
1616 if (Temp == NULL) return FALSE;
1618 for (i=0; i < nChannels; i++) {
1619 Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
1620 if (Tables[i] == NULL) goto Error;
1623 for (i=0; i < nChannels; i++) {
1625 if (io ->Read(io, Temp, 256, 1) != 1) goto Error;
1627 for (j=0; j < 256; j++)
1628 Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]);
1631 _cmsFree(ContextID, Temp);
1635 mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables);
1636 if (mpe == NULL) goto Error;
1638 cmsPipelineInsertStage(lut, cmsAT_END, mpe);
1640 for (i=0; i < nChannels; i++)
1641 cmsFreeToneCurve(Tables[i]);
1646 for (i=0; i < nChannels; i++) {
1647 if (Tables[i]) cmsFreeToneCurve(Tables[i]);
1650 if (Temp) _cmsFree(ContextID, Temp);
1656 cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables)
1662 for (i=0; i < n; i++) {
1666 if (Tables ->TheCurves[i]->nEntries != 256) {
1667 cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization");
1673 for (j=0; j < 256; j++) {
1676 val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]);
1678 val = (cmsUInt8Number) j;
1680 if (!_cmsWriteUInt8Number(io, val)) return FALSE;
1689 unsigned int uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
1691 cmsUInt32Number rv = 1, rc;
1693 if (a == 0) return 0;
1694 if (n == 0) return 0;
1696 for (; b > 0; b--) {
1700 // Check for overflow
1701 if (rv > UINT_MAX / a) return 0;
1707 if (rv != rc / n) return 0;
1712 // That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
1713 // 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust
1714 // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
1717 void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1719 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
1720 cmsUInt8Number* Temp = NULL;
1721 cmsPipeline* NewLUT = NULL;
1722 cmsStage *mpemat, *mpeclut;
1723 cmsUInt32Number nTabSize, i;
1724 cmsFloat64Number Matrix[3*3];
1728 if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error;
1729 if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error;
1730 if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error;
1733 if (!_cmsReadUInt8Number(io, NULL)) goto Error;
1737 if (InputChannels > cmsMAXCHANNELS) goto Error;
1738 if (OutputChannels > cmsMAXCHANNELS) goto Error;
1740 // Allocates an empty Pipeline
1741 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
1742 if (NewLUT == NULL) goto Error;
1745 if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
1746 if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
1747 if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
1748 if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
1749 if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
1750 if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
1751 if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
1752 if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
1753 if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
1756 // Only operates if not identity...
1757 if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
1759 mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL);
1760 if (mpemat == NULL) goto Error;
1761 cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, mpemat);
1765 if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error;
1767 // Get 3D CLUT. Check the overflow....
1768 nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
1771 cmsUInt16Number *PtrW, *T;
1772 cmsUInt32Number Tsize;
1774 Tsize = (cmsUInt32Number) nTabSize * sizeof(cmsUInt16Number);
1776 PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
1777 if (T == NULL) goto Error;
1779 Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize);
1780 if (Temp == NULL) goto Error;
1782 if (io ->Read(io, Temp, nTabSize, 1) != 1) goto Error;
1784 for (i = 0; i < nTabSize; i++) {
1786 *PtrW++ = FROM_8_TO_16(Temp[i]);
1788 _cmsFree(self ->ContextID, Temp);
1792 mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T);
1793 if (mpeclut == NULL) goto Error;
1794 cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut);
1795 _cmsFree(self ->ContextID, T);
1799 // Get output tables
1800 if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error;
1806 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
1809 cmsUNUSED_PARAMETER(SizeOfTag);
1812 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1814 cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1816 cmsUInt32Number j, nTabSize;
1818 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
1820 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
1821 _cmsStageMatrixData* MatMPE = NULL;
1822 _cmsStageCLutData* clut = NULL;
1825 // Disassemble the LUT into components.
1826 mpe = NewLUT -> Elements;
1827 if (mpe ->Type == cmsSigMatrixElemType) {
1829 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
1833 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1834 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1838 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
1839 clut = (_cmsStageCLutData*) mpe -> Data;
1843 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1844 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1848 // That should be all
1850 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
1858 clutPoints = clut->Params->nSamples[0];
1860 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE;
1861 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE;
1862 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
1863 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
1866 if (MatMPE != NULL) {
1868 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
1869 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
1870 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
1871 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
1872 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
1873 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
1874 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
1875 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
1876 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
1881 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1882 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1883 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1884 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1885 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1886 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1887 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1888 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1889 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1892 // The prelinearization table
1893 if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
1895 nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
1901 for (j=0; j < nTabSize; j++) {
1903 val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
1904 if (!_cmsWriteUInt8Number(io, val)) return FALSE;
1909 // The postlinearization table
1910 if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE;
1914 cmsUNUSED_PARAMETER(nItems);
1919 void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1921 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
1923 cmsUNUSED_PARAMETER(n);
1924 cmsUNUSED_PARAMETER(self);
1928 void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
1930 cmsPipelineFree((cmsPipeline*) Ptr);
1933 cmsUNUSED_PARAMETER(self);
1936 // ********************************************************************************
1937 // Type cmsSigLut16Type
1938 // ********************************************************************************
1940 // Read 16 bit tables as gamma functions
1942 cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries)
1946 cmsToneCurve* Tables[cmsMAXCHANNELS];
1948 // Maybe an empty table? (this is a lcms extension)
1949 if (nEntries <= 0) return TRUE;
1951 // Check for malicious profiles
1952 if (nChannels > cmsMAXCHANNELS) return FALSE;
1954 // Init table to zero
1955 memset(Tables, 0, sizeof(Tables));
1957 for (i=0; i < nChannels; i++) {
1959 Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL);
1960 if (Tables[i] == NULL) goto Error;
1962 if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error;
1966 // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code)
1967 mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables);
1968 if (mpe == NULL) goto Error;
1970 cmsPipelineInsertStage(lut, cmsAT_END, mpe);
1972 for (i=0; i < nChannels; i++)
1973 cmsFreeToneCurve(Tables[i]);
1978 for (i=0; i < nChannels; i++) {
1979 if (Tables[i]) cmsFreeToneCurve(Tables[i]);
1986 cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables)
1990 cmsUInt16Number val;
1993 nEntries = Tables->TheCurves[0]->nEntries;
1995 for (i=0; i < Tables ->nCurves; i++) {
1997 for (j=0; j < nEntries; j++) {
2000 val = Tables->TheCurves[i]->Table16[j];
2002 val = _cmsQuantizeVal(j, nEntries);
2004 if (!_cmsWriteUInt16Number(io, val)) return FALSE;
2009 cmsUNUSED_PARAMETER(ContextID);
2013 void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2015 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
2016 cmsPipeline* NewLUT = NULL;
2017 cmsStage *mpemat, *mpeclut;
2018 cmsUInt32Number nTabSize;
2019 cmsFloat64Number Matrix[3*3];
2020 cmsUInt16Number InputEntries, OutputEntries;
2024 if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL;
2025 if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL;
2026 if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum
2029 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2032 if (InputChannels > cmsMAXCHANNELS) goto Error;
2033 if (OutputChannels > cmsMAXCHANNELS) goto Error;
2035 // Allocates an empty LUT
2036 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
2037 if (NewLUT == NULL) goto Error;
2040 if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
2041 if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
2042 if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
2043 if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
2044 if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
2045 if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
2046 if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
2047 if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
2048 if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
2051 // Only operates on 3 channels
2053 if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
2055 mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL);
2056 if (mpemat == NULL) goto Error;
2057 cmsPipelineInsertStage(NewLUT, cmsAT_END, mpemat);
2060 if (!_cmsReadUInt16Number(io, &InputEntries)) return NULL;
2061 if (!_cmsReadUInt16Number(io, &OutputEntries)) return NULL;
2065 if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error;
2068 nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
2073 T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
2074 if (T == NULL) goto Error;
2076 if (!_cmsReadUInt16Array(io, nTabSize, T)) {
2077 _cmsFree(self ->ContextID, T);
2081 mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T);
2082 if (mpeclut == NULL) {
2083 _cmsFree(self ->ContextID, T);
2087 cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut);
2088 _cmsFree(self ->ContextID, T);
2092 // Get output tables
2093 if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error;
2099 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
2102 cmsUNUSED_PARAMETER(SizeOfTag);
2105 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
2106 // Some empty defaults are created for missing parts
2109 cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2111 cmsUInt32Number nTabSize;
2112 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
2114 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
2115 _cmsStageMatrixData* MatMPE = NULL;
2116 _cmsStageCLutData* clut = NULL;
2117 int InputChannels, OutputChannels, clutPoints;
2119 // Disassemble the LUT into components.
2120 mpe = NewLUT -> Elements;
2121 if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
2123 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
2128 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2129 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2133 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
2134 clut = (_cmsStageCLutData*) mpe -> Data;
2138 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2139 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2143 // That should be all
2145 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
2149 InputChannels = cmsPipelineInputChannels(NewLUT);
2150 OutputChannels = cmsPipelineOutputChannels(NewLUT);
2155 clutPoints = clut->Params->nSamples[0];
2157 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE;
2158 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE;
2159 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
2160 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
2163 if (MatMPE != NULL) {
2165 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
2166 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
2167 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
2168 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
2169 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
2170 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
2171 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
2172 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
2173 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
2177 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2178 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2179 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2180 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2181 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2182 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2183 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2184 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2185 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2189 if (PreMPE != NULL) {
2190 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE;
2192 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2195 if (PostMPE != NULL) {
2196 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE;
2198 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2202 // The prelinearization table
2204 if (PreMPE != NULL) {
2205 if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE;
2208 nTabSize = uipow(OutputChannels, clutPoints, InputChannels);
2213 if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
2217 // The postlinearization table
2218 if (PostMPE != NULL) {
2219 if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE;
2225 cmsUNUSED_PARAMETER(nItems);
2229 void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2231 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2233 cmsUNUSED_PARAMETER(n);
2234 cmsUNUSED_PARAMETER(self);
2238 void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr)
2240 cmsPipelineFree((cmsPipeline*) Ptr);
2243 cmsUNUSED_PARAMETER(self);
2247 // ********************************************************************************
2248 // Type cmsSigLutAToBType
2249 // ********************************************************************************
2252 // V4 stuff. Read matrix for LutAtoB and LutBtoA
2255 cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset)
2257 cmsFloat64Number dMat[3*3];
2258 cmsFloat64Number dOff[3];
2262 if (!io -> Seek(io, Offset)) return NULL;
2265 if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL;
2266 if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL;
2267 if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL;
2268 if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL;
2269 if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL;
2270 if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL;
2271 if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL;
2272 if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL;
2273 if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL;
2275 if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL;
2276 if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL;
2277 if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL;
2279 Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff);
2287 // V4 stuff. Read CLUT part for LutAtoB and LutBtoA
2290 cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels)
2292 cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension.
2293 cmsUInt32Number GridPoints[cmsMAXCHANNELS], i;
2294 cmsUInt8Number Precision;
2296 _cmsStageCLutData* Data;
2298 if (!io -> Seek(io, Offset)) return NULL;
2299 if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL;
2301 for (i=0; i < cmsMAXCHANNELS; i++)
2302 GridPoints[i] = gridPoints8[i];
2304 if (!_cmsReadUInt8Number(io, &Precision)) return NULL;
2306 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2307 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2308 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2310 CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL);
2311 if (CLUT == NULL) return NULL;
2313 Data = (_cmsStageCLutData*) CLUT ->Data;
2315 // Precision can be 1 or 2 bytes
2316 if (Precision == 1) {
2320 for (i=0; i < Data ->nEntries; i++) {
2322 if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
2323 Data ->Tab.T[i] = FROM_8_TO_16(v);
2328 if (Precision == 2) {
2330 if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL;
2333 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
2342 cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
2344 cmsTagTypeSignature BaseType;
2345 cmsUInt32Number nItems;
2347 BaseType = _cmsReadTypeBase(io);
2350 case cmsSigCurveType:
2351 return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0);
2353 case cmsSigParametricCurveType:
2354 return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0);
2360 _cmsTagSignature2String(String, (cmsTagSignature) BaseType);
2361 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
2368 // Read a set of curves from specific offset
2370 cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves)
2372 cmsToneCurve* Curves[cmsMAXCHANNELS];
2374 cmsStage* Lin = NULL;
2376 if (nCurves > cmsMAXCHANNELS) return FALSE;
2378 if (!io -> Seek(io, Offset)) return FALSE;
2380 for (i=0; i < nCurves; i++)
2383 for (i=0; i < nCurves; i++) {
2385 Curves[i] = ReadEmbeddedCurve(self, io);
2386 if (Curves[i] == NULL) goto Error;
2387 if (!_cmsReadAlignment(io)) goto Error;
2390 Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves);
2393 for (i=0; i < nCurves; i++)
2394 cmsFreeToneCurve(Curves[i]);
2402 // This structure represents a colour transform. The type contains up to five processing
2403 // elements which are stored in the AtoBTag tag in the following order: a set of one
2404 // dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves,
2405 // a multidimensional lookup table, and a set of one dimensional output curves.
2406 // Data are processed using these elements via the following sequence:
2408 //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves).
2411 It is possible to use any or all of these processing elements. At least one processing element
2412 must be included.Only the following combinations are allowed:
2417 A - CLUT - M - Matrix - B
2422 void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2424 cmsUInt32Number BaseOffset;
2425 cmsUInt8Number inputChan; // Number of input channels
2426 cmsUInt8Number outputChan; // Number of output channels
2427 cmsUInt32Number offsetB; // Offset to first "B" curve
2428 cmsUInt32Number offsetMat; // Offset to matrix
2429 cmsUInt32Number offsetM; // Offset to first "M" curve
2430 cmsUInt32Number offsetC; // Offset to CLUT
2431 cmsUInt32Number offsetA; // Offset to first "A" curve
2433 cmsPipeline* NewLUT = NULL;
2436 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2438 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
2439 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
2441 if (!_cmsReadUInt16Number(io, NULL)) return NULL;
2443 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
2444 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
2445 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
2446 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
2447 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
2449 // Allocates an empty LUT
2450 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
2451 if (NewLUT == NULL) return NULL;
2454 mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan);
2455 cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2459 mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan);
2460 if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2464 mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan);
2465 if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2468 if (offsetMat != 0) {
2469 mpe = ReadMatrix(self, io, BaseOffset + offsetMat);
2470 if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2474 mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan);
2475 if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2481 cmsUNUSED_PARAMETER(SizeOfTag);
2484 // Write a set of curves
2486 cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
2488 _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
2491 if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE;
2492 if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE;
2493 if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE;
2494 if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE;
2495 if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE;
2496 if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE;
2497 if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE;
2498 if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE;
2499 if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE;
2501 if (m ->Offset != NULL) {
2503 if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE;
2504 if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE;
2505 if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE;
2508 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2509 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2510 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2517 cmsUNUSED_PARAMETER(self);
2521 // Write a set of curves
2523 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
2525 cmsUInt32Number i, n;
2526 cmsTagTypeSignature CurrentType;
2527 cmsToneCurve** Curves;
2530 n = cmsStageOutputChannels(mpe);
2531 Curves = _cmsStageGetPtrToCurveSet(mpe);
2533 for (i=0; i < n; i++) {
2535 // If this is a table-based curve, use curve type even on V4
2538 if ((Curves[i] ->nSegments == 0)||(Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0))
2539 CurrentType = cmsSigCurveType;
2541 if (Curves[i] ->Segments[0].Type < 0)
2542 CurrentType = cmsSigCurveType;
2544 if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE;
2546 switch (CurrentType) {
2548 case cmsSigCurveType:
2549 if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE;
2552 case cmsSigParametricCurveType:
2553 if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE;
2560 _cmsTagSignature2String(String, (cmsTagSignature) Type);
2561 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
2566 if (!_cmsWriteAlignment(io)) return FALSE;
2575 cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe)
2577 cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension.
2579 _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data;
2581 if (CLUT ->HasFloatValues) {
2582 cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only");
2586 memset(gridPoints, 0, sizeof(gridPoints));
2587 for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++)
2588 gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i];
2590 if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE;
2592 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE;
2593 if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2594 if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2595 if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2597 // Precision can be 1 or 2 bytes
2598 if (Precision == 1) {
2600 for (i=0; i < CLUT->nEntries; i++) {
2602 if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE;
2606 if (Precision == 2) {
2608 if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE;
2611 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
2615 if (!_cmsWriteAlignment(io)) return FALSE;
2624 cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2626 cmsPipeline* Lut = (cmsPipeline*) Ptr;
2627 int inputChan, outputChan;
2628 cmsStage *A = NULL, *B = NULL, *M = NULL;
2629 cmsStage * Matrix = NULL;
2630 cmsStage * CLUT = NULL;
2631 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2632 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2634 // Get the base for all offsets
2635 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2637 if (Lut ->Elements != NULL)
2638 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
2639 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B))
2640 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B))
2641 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType,
2642 cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) {
2644 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB");
2648 // Get input, output channels
2649 inputChan = cmsPipelineInputChannels(Lut);
2650 outputChan = cmsPipelineOutputChannels(Lut);
2652 // Write channel count
2653 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
2654 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
2655 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2657 // Keep directory to be filled latter
2658 DirectoryPos = io ->Tell(io);
2660 // Write the directory
2661 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2662 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2663 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2664 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2665 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2669 offsetA = io ->Tell(io) - BaseOffset;
2670 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
2674 offsetC = io ->Tell(io) - BaseOffset;
2675 if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
2680 offsetM = io ->Tell(io) - BaseOffset;
2681 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
2684 if (Matrix != NULL) {
2685 offsetMat = io ->Tell(io) - BaseOffset;
2686 if (!WriteMatrix(self, io, Matrix)) return FALSE;
2691 offsetB = io ->Tell(io) - BaseOffset;
2692 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2695 CurrentPos = io ->Tell(io);
2697 if (!io ->Seek(io, DirectoryPos)) return FALSE;
2699 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2700 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2701 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2702 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2703 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2705 if (!io ->Seek(io, CurrentPos)) return FALSE;
2709 cmsUNUSED_PARAMETER(nItems);
2714 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2716 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2718 cmsUNUSED_PARAMETER(n);
2719 cmsUNUSED_PARAMETER(self);
2723 void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr)
2725 cmsPipelineFree((cmsPipeline*) Ptr);
2728 cmsUNUSED_PARAMETER(self);
2735 void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2737 cmsUInt8Number inputChan; // Number of input channels
2738 cmsUInt8Number outputChan; // Number of output channels
2739 cmsUInt32Number BaseOffset; // Actual position in file
2740 cmsUInt32Number offsetB; // Offset to first "B" curve
2741 cmsUInt32Number offsetMat; // Offset to matrix
2742 cmsUInt32Number offsetM; // Offset to first "M" curve
2743 cmsUInt32Number offsetC; // Offset to CLUT
2744 cmsUInt32Number offsetA; // Offset to first "A" curve
2746 cmsPipeline* NewLUT = NULL;
2749 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2751 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
2752 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
2755 if (!_cmsReadUInt16Number(io, NULL)) return NULL;
2757 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
2758 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
2759 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
2760 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
2761 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
2763 // Allocates an empty LUT
2764 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
2765 if (NewLUT == NULL) return NULL;
2768 mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan);
2769 if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2772 if (offsetMat != 0) {
2773 mpe = ReadMatrix(self, io, BaseOffset + offsetMat);
2774 if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2778 mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan);
2779 if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2783 mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan);
2784 if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2788 mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan);
2789 if (mpe != NULL) cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
2795 cmsUNUSED_PARAMETER(SizeOfTag);
2803 B - Matrix - M - CLUT - A
2807 cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2809 cmsPipeline* Lut = (cmsPipeline*) Ptr;
2810 int inputChan, outputChan;
2811 cmsStage *A = NULL, *B = NULL, *M = NULL;
2812 cmsStage *Matrix = NULL;
2813 cmsStage *CLUT = NULL;
2814 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2815 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2818 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2820 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
2821 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M))
2822 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A))
2823 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
2824 cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) {
2825 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA");
2829 inputChan = cmsPipelineInputChannels(Lut);
2830 outputChan = cmsPipelineOutputChannels(Lut);
2832 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
2833 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
2834 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2836 DirectoryPos = io ->Tell(io);
2838 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2839 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2840 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2841 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2842 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2846 offsetA = io ->Tell(io) - BaseOffset;
2847 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
2851 offsetC = io ->Tell(io) - BaseOffset;
2852 if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
2857 offsetM = io ->Tell(io) - BaseOffset;
2858 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
2861 if (Matrix != NULL) {
2862 offsetMat = io ->Tell(io) - BaseOffset;
2863 if (!WriteMatrix(self, io, Matrix)) return FALSE;
2868 offsetB = io ->Tell(io) - BaseOffset;
2869 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2872 CurrentPos = io ->Tell(io);
2874 if (!io ->Seek(io, DirectoryPos)) return FALSE;
2876 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2877 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2878 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2879 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2880 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2882 if (!io ->Seek(io, CurrentPos)) return FALSE;
2886 cmsUNUSED_PARAMETER(nItems);
2892 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2894 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2896 cmsUNUSED_PARAMETER(n);
2897 cmsUNUSED_PARAMETER(self);
2901 void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr)
2903 cmsPipelineFree((cmsPipeline*) Ptr);
2906 cmsUNUSED_PARAMETER(self);
2911 // ********************************************************************************
2912 // Type cmsSigColorantTableType
2913 // ********************************************************************************
2915 The purpose of this tag is to identify the colorants used in the profile by a
2916 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
2917 value. The first colorant listed is the colorant of the first device channel of
2918 a lut tag. The second colorant listed is the colorant of the second device channel
2919 of a lut tag, and so on.
2923 void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2925 cmsUInt32Number i, Count;
2926 cmsNAMEDCOLORLIST* List;
2928 cmsUInt16Number PCS[3];
2931 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
2933 if (Count > cmsMAXCHANNELS) {
2934 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count);
2938 List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", "");
2939 for (i=0; i < Count; i++) {
2941 if (io ->Read(io, Name, 32, 1) != 1) goto Error;
2944 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
2946 if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error;
2955 cmsFreeNamedColorList(List);
2958 cmsUNUSED_PARAMETER(SizeOfTag);
2963 // Saves a colorant table. It is using the named color structure for simplicity sake
2965 cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2967 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
2970 nColors = cmsNamedColorCount(NamedColorList);
2972 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
2974 for (i=0; i < nColors; i++) {
2977 cmsUInt16Number PCS[3];
2979 if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0;
2982 if (!io ->Write(io, 32, root)) return FALSE;
2983 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
2988 cmsUNUSED_PARAMETER(nItems);
2989 cmsUNUSED_PARAMETER(self);
2994 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
2996 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
2997 return (void*) cmsDupNamedColorList(nc);
2999 cmsUNUSED_PARAMETER(n);
3000 cmsUNUSED_PARAMETER(self);
3005 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
3007 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3010 cmsUNUSED_PARAMETER(self);
3014 // ********************************************************************************
3015 // Type cmsSigNamedColor2Type
3016 // ********************************************************************************
3018 //The namedColor2Type is a count value and array of structures that provide color
3019 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3020 //device representation of the color are given. Both representations are 16-bit values.
3021 //The device representation corresponds to the header
\92s
\93color space of data
\94 field.
3022 //This representation should be consistent with the
\93number of device components
\94
3023 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3024 //The PCS representation corresponds to the header
\92s PCS field. The PCS representation
3025 //is always provided. Color names are fixed-length, 32-byte fields including null
3026 //termination. In order to maintain maximum portability, it is strongly recommended
3027 //that special characters of the 7-bit ASCII set not be used.
3030 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3033 cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use
3034 cmsUInt32Number count; // Count of named colors
3035 cmsUInt32Number nDeviceCoords; // Num of device coordinates
3036 char prefix[32]; // Prefix for each color name
3037 char suffix[32]; // Suffix for each color name
3038 cmsNAMEDCOLORLIST* v;
3043 if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL;
3044 if (!_cmsReadUInt32Number(io, &count)) return NULL;
3045 if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL;
3047 if (io -> Read(io, prefix, 32, 1) != 1) return NULL;
3048 if (io -> Read(io, suffix, 32, 1) != 1) return NULL;
3050 prefix[31] = suffix[31] = 0;
3052 v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix);
3054 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count);
3058 if (nDeviceCoords > cmsMAXCHANNELS) {
3059 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
3062 for (i=0; i < count; i++) {
3064 cmsUInt16Number PCS[3];
3065 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3068 memset(Colorant, 0, sizeof(Colorant));
3069 if (io -> Read(io, Root, 32, 1) != 1) return NULL;
3070 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3071 if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
3073 if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
3080 cmsFreeNamedColorList(v);
3083 cmsUNUSED_PARAMETER(SizeOfTag);
3087 // Saves a named color list into a named color profile
3089 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3091 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3092 char prefix[32]; // Prefix for each color name
3093 char suffix[32]; // Suffix for each color name
3096 nColors = cmsNamedColorCount(NamedColorList);
3098 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
3099 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3100 if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
3102 strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
3103 strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
3105 suffix[31] = prefix[31] = 0;
3107 if (!io ->Write(io, 32, prefix)) return FALSE;
3108 if (!io ->Write(io, 32, suffix)) return FALSE;
3110 for (i=0; i < nColors; i++) {
3112 cmsUInt16Number PCS[3];
3113 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3116 if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
3117 if (!io ->Write(io, 32 , Root)) return FALSE;
3118 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3119 if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
3124 cmsUNUSED_PARAMETER(nItems);
3125 cmsUNUSED_PARAMETER(self);
3129 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3131 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3133 return (void*) cmsDupNamedColorList(nc);
3135 cmsUNUSED_PARAMETER(n);
3136 cmsUNUSED_PARAMETER(self);
3141 void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr)
3143 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3146 cmsUNUSED_PARAMETER(self);
3150 // ********************************************************************************
3151 // Type cmsSigProfileSequenceDescType
3152 // ********************************************************************************
3154 // This type is an array of structures, each of which contains information from the
3155 // header fields and tags from the original profiles which were combined to create
3156 // the final profile. The order of the structures is the order in which the profiles
3157 // were combined and includes a structure for the final profile. This provides a
3158 // description of the profile sequence from source to destination,
3159 // typically used with the DeviceLink profile.
3162 cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag)
3164 cmsTagTypeSignature BaseType;
3165 cmsUInt32Number nItems;
3167 BaseType = _cmsReadTypeBase(io);
3171 case cmsSigTextType:
3172 if (*mlu) cmsMLUfree(*mlu);
3173 *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag);
3174 return (*mlu != NULL);
3176 case cmsSigTextDescriptionType:
3177 if (*mlu) cmsMLUfree(*mlu);
3178 *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag);
3179 return (*mlu != NULL);
3182 TBD: Size is needed for MLU, and we have no idea on which is the available size
3185 case cmsSigMultiLocalizedUnicodeType:
3186 if (*mlu) cmsMLUfree(*mlu);
3187 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag);
3188 return (*mlu != NULL);
3190 default: return FALSE;
3196 void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3199 cmsUInt32Number i, Count;
3203 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3205 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3206 SizeOfTag -= sizeof(cmsUInt32Number);
3209 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
3210 if (OutSeq == NULL) return NULL;
3214 // Get structures as well
3216 for (i=0; i < Count; i++) {
3218 cmsPSEQDESC* sec = &OutSeq -> seq[i];
3220 if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) return NULL;
3221 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3222 SizeOfTag -= sizeof(cmsUInt32Number);
3224 if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) return NULL;
3225 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3226 SizeOfTag -= sizeof(cmsUInt32Number);
3228 if (!_cmsReadUInt64Number(io, &sec ->attributes)) return NULL;
3229 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3230 SizeOfTag -= sizeof(cmsUInt64Number);
3232 if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) return NULL;
3233 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3234 SizeOfTag -= sizeof(cmsUInt32Number);
3236 if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) return NULL;
3237 if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) return NULL;
3245 // Aux--Embed a text description type. It can be of type text description or multilocalized unicode
3246 // and it depends of the version number passed on cmsTagDescriptor structure instead of stack
3248 cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text)
3250 if (self ->ICCVersion < 0x4000000) {
3252 if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE;
3253 return Type_Text_Description_Write(self, io, Text, 1);
3256 if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE;
3257 return Type_MLU_Write(self, io, Text, 1);
3263 cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3265 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3268 if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE;
3270 for (i=0; i < Seq ->n; i++) {
3272 cmsPSEQDESC* sec = &Seq -> seq[i];
3274 if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE;
3275 if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE;
3276 if (!_cmsWriteUInt64Number(io, sec ->attributes)) return FALSE;
3277 if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE;
3279 if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE;
3280 if (!SaveDescription(self, io, sec ->Model)) return FALSE;
3285 cmsUNUSED_PARAMETER(nItems);
3290 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3292 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3294 cmsUNUSED_PARAMETER(n);
3295 cmsUNUSED_PARAMETER(self);
3299 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr)
3301 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3304 cmsUNUSED_PARAMETER(self);
3308 // ********************************************************************************
3309 // Type cmsSigProfileSequenceIdType
3310 // ********************************************************************************
3312 In certain workflows using ICC Device Link Profiles, it is necessary to identify the
3313 original profiles that were combined to create the Device Link Profile.
3314 This type is an array of structures, each of which contains information for
3315 identification of a profile used in a sequence
3320 cmsBool ReadSeqID(struct _cms_typehandler_struct* self,
3324 cmsUInt32Number SizeOfTag)
3326 cmsSEQ* OutSeq = (cmsSEQ*) Cargo;
3327 cmsPSEQDESC* seq = &OutSeq ->seq[n];
3329 if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE;
3330 if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE;
3338 void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3341 cmsUInt32Number Count;
3342 cmsUInt32Number BaseOffset;
3346 // Get actual position as a basis for element offsets
3347 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3350 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3351 SizeOfTag -= sizeof(cmsUInt32Number);
3353 // Allocate an empty structure
3354 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
3355 if (OutSeq == NULL) return NULL;
3358 // Read the position table
3359 if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) {
3361 cmsFreeProfileSequenceDescription(OutSeq);
3373 cmsBool WriteSeqID(struct _cms_typehandler_struct* self,
3377 cmsUInt32Number SizeOfTag)
3379 cmsSEQ* Seq = (cmsSEQ*) Cargo;
3381 if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE;
3383 // Store here the MLU
3384 if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE;
3388 cmsUNUSED_PARAMETER(SizeOfTag);
3392 cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3394 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3395 cmsUInt32Number BaseOffset;
3397 // Keep the base offset
3398 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3400 // This is the table count
3401 if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE;
3403 // This is the position table and content
3404 if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE;
3408 cmsUNUSED_PARAMETER(nItems);
3412 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3414 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3416 cmsUNUSED_PARAMETER(n);
3417 cmsUNUSED_PARAMETER(self);
3421 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr)
3423 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3426 cmsUNUSED_PARAMETER(self);
3430 // ********************************************************************************
3431 // Type cmsSigUcrBgType
3432 // ********************************************************************************
3434 This type contains curves representing the under color removal and black
3435 generation and a text string which is a general description of the method used
3440 void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3442 cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3443 cmsUInt32Number CountUcr, CountBg;
3447 if (n == NULL) return NULL;
3449 // First curve is Under color removal
3450 if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
3451 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3452 SizeOfTag -= sizeof(cmsUInt32Number);
3454 n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
3455 if (n ->Ucr == NULL) return NULL;
3457 if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
3458 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3459 SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
3461 // Second curve is Black generation
3462 if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
3463 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3464 SizeOfTag -= sizeof(cmsUInt32Number);
3466 n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
3467 if (n ->Bg == NULL) return NULL;
3468 if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
3469 if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL;
3470 SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
3471 if (SizeOfTag == UINT_MAX) return NULL;
3473 // Now comes the text. The length is specified by the tag size
3474 n ->Desc = cmsMLUalloc(self ->ContextID, 1);
3475 if (n ->Desc == NULL) return NULL;
3477 ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
3478 if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
3479 ASCIIString[SizeOfTag] = 0;
3480 cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
3481 _cmsFree(self ->ContextID, ASCIIString);
3488 cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3490 cmsUcrBg* Value = (cmsUcrBg*) Ptr;
3491 cmsUInt32Number TextSize;
3494 // First curve is Under color removal
3495 if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE;
3496 if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE;
3498 // Then black generation
3499 if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE;
3500 if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE;
3502 // Now comes the text. The length is specified by the tag size
3503 TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0);
3504 Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
3505 if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE;
3507 if (!io ->Write(io, TextSize, Text)) return FALSE;
3508 _cmsFree(self ->ContextID, Text);
3512 cmsUNUSED_PARAMETER(nItems);
3516 void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3518 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3519 cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3521 if (NewUcrBg == NULL) return NULL;
3523 NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg);
3524 NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr);
3525 NewUcrBg ->Desc = cmsMLUdup(Src ->Desc);
3527 return (void*) NewUcrBg;
3529 cmsUNUSED_PARAMETER(n);
3533 void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr)
3535 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3537 if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr);
3538 if (Src ->Bg) cmsFreeToneCurve(Src ->Bg);
3539 if (Src ->Desc) cmsMLUfree(Src ->Desc);
3541 _cmsFree(self ->ContextID, Ptr);
3544 // ********************************************************************************
3545 // Type cmsSigCrdInfoType
3546 // ********************************************************************************
3549 This type contains the PostScript product name to which this profile corresponds
3550 and the names of the companion CRDs. Recall that a single profile can generate
3551 multiple CRDs. It is implemented as a MLU being the language code "PS" and then
3552 country varies for each element:
3554 nm: PostScript product name
3555 #0: Rendering intent 0 CRD name
3556 #1: Rendering intent 1 CRD name
3557 #2: Rendering intent 2 CRD name
3558 #3: Rendering intent 3 CRD name
3563 // Auxiliar, read an string specified as count + string
3565 cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
3567 cmsUInt32Number Count;
3570 if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE;
3572 if (!_cmsReadUInt32Number(io, &Count)) return FALSE;
3574 if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE;
3575 if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE;
3577 Text = (char*) _cmsMalloc(self ->ContextID, Count+1);
3578 if (Text == NULL) return FALSE;
3580 if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) {
3581 _cmsFree(self ->ContextID, Text);
3587 cmsMLUsetASCII(mlu, "PS", Section, Text);
3588 _cmsFree(self ->ContextID, Text);
3590 *SizeOfTag -= (Count + sizeof(cmsUInt32Number));
3595 cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section)
3597 cmsUInt32Number TextSize;
3600 TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0);
3601 Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
3603 if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE;
3605 if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE;
3607 if (!io ->Write(io, TextSize, Text)) return FALSE;
3608 _cmsFree(self ->ContextID, Text);
3614 void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3616 cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5);
3619 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error;
3620 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error;
3621 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error;
3622 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error;
3623 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error;
3635 cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3638 cmsMLU* mlu = (cmsMLU*) Ptr;
3640 if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error;
3641 if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error;
3642 if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error;
3643 if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error;
3644 if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error;
3651 cmsUNUSED_PARAMETER(nItems);
3656 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3658 return (void*) cmsMLUdup((cmsMLU*) Ptr);
3660 cmsUNUSED_PARAMETER(n);
3661 cmsUNUSED_PARAMETER(self);
3665 void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr)
3667 cmsMLUfree((cmsMLU*) Ptr);
3670 cmsUNUSED_PARAMETER(self);
3673 // ********************************************************************************
3674 // Type cmsSigScreeningType
3675 // ********************************************************************************
3677 //The screeningType describes various screening parameters including screen
3678 //frequency, screening angle, and spot shape.
3681 void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3683 cmsScreening* sc = NULL;
3686 sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening));
3687 if (sc == NULL) return NULL;
3691 if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error;
3692 if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error;
3694 if (sc ->nChannels > cmsMAXCHANNELS - 1)
3695 sc ->nChannels = cmsMAXCHANNELS - 1;
3697 for (i=0; i < sc ->nChannels; i++) {
3699 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error;
3700 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error;
3701 if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error;
3711 _cmsFree(self ->ContextID, sc);
3715 cmsUNUSED_PARAMETER(SizeOfTag);
3720 cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3722 cmsScreening* sc = (cmsScreening* ) Ptr;
3725 if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE;
3726 if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE;
3728 for (i=0; i < sc ->nChannels; i++) {
3730 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE;
3731 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE;
3732 if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE;
3737 cmsUNUSED_PARAMETER(nItems);
3738 cmsUNUSED_PARAMETER(self);
3743 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3745 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3747 cmsUNUSED_PARAMETER(n);
3752 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
3754 _cmsFree(self ->ContextID, Ptr);
3757 // ********************************************************************************
3758 // Type cmsSigViewingConditionsType
3759 // ********************************************************************************
3761 //This type represents a set of viewing condition parameters including:
3762 //CIE
\92absolute
\92 illuminant white point tristimulus values and CIE
\92absolute
\92
3763 //surround tristimulus values.
3766 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3768 cmsICCViewingConditions* vc = NULL;
3770 vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
3771 if (vc == NULL) return NULL;
3775 if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
3776 if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
3777 if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
3785 _cmsFree(self ->ContextID, vc);
3789 cmsUNUSED_PARAMETER(SizeOfTag);
3794 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3796 cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
3798 if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
3799 if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
3800 if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
3804 cmsUNUSED_PARAMETER(nItems);
3805 cmsUNUSED_PARAMETER(self);
3810 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3812 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3814 cmsUNUSED_PARAMETER(n);
3819 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
3821 _cmsFree(self ->ContextID, Ptr);
3825 // ********************************************************************************
3826 // Type cmsSigMultiProcessElementType
3827 // ********************************************************************************
3831 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3833 return (void*) cmsStageDup((cmsStage*) Ptr);
3835 cmsUNUSED_PARAMETER(n);
3836 cmsUNUSED_PARAMETER(self);
3840 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
3842 cmsStageFree((cmsStage*) Ptr);
3845 cmsUNUSED_PARAMETER(self);
3848 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
3849 // The first curve segment always starts at
\96Infinity, and the last curve segment always ends at +Infinity. The
3850 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
3851 // specified either in terms of a formula, or by a sampled curve.
3854 // Read an embedded segmented curve
3856 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
3858 cmsCurveSegSignature ElementSig;
3859 cmsUInt32Number i, j;
3860 cmsUInt16Number nSegments;
3861 cmsCurveSegment* Segments;
3862 cmsToneCurve* Curve;
3863 cmsFloat32Number PrevBreak = -1E22F; // - infinite
3865 // Take signature and channels for each element.
3866 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL;
3868 // That should be a segmented curve
3869 if (ElementSig != cmsSigSegmentedCurve) return NULL;
3871 if (!_cmsReadUInt32Number(io, NULL)) return NULL;
3872 if (!_cmsReadUInt16Number(io, &nSegments)) return NULL;
3873 if (!_cmsReadUInt16Number(io, NULL)) return NULL;
3875 if (nSegments < 1) return NULL;
3876 Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment));
3877 if (Segments == NULL) return NULL;
3880 for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) {
3882 Segments[i].x0 = PrevBreak;
3883 if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error;
3884 PrevBreak = Segments[i].x1;
3887 Segments[nSegments-1].x0 = PrevBreak;
3888 Segments[nSegments-1].x1 = 1E22F; // A big cmsFloat32Number number
3891 for (i=0; i < nSegments; i++) {
3893 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error;
3894 if (!_cmsReadUInt32Number(io, NULL)) goto Error;
3896 switch (ElementSig) {
3898 case cmsSigFormulaCurveSeg: {
3900 cmsUInt16Number Type;
3901 cmsUInt32Number ParamsByType[] = {4, 5, 5 };
3903 if (!_cmsReadUInt16Number(io, &Type)) goto Error;
3904 if (!_cmsReadUInt16Number(io, NULL)) goto Error;
3906 Segments[i].Type = Type + 6;
3907 if (Type > 2) goto Error;
3909 for (j=0; j < ParamsByType[Type]; j++) {
3912 if (!_cmsReadFloat32Number(io, &f)) goto Error;
3913 Segments[i].Params[j] = f;
3919 case cmsSigSampledCurveSeg: {
3920 cmsUInt32Number Count;
3922 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3924 Segments[i].nGridPoints = Count;
3925 Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number));
3926 if (Segments[i].SampledPoints == NULL) goto Error;
3928 for (j=0; j < Count; j++) {
3929 if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
3938 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
3939 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String);
3946 Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments);
3948 for (i=0; i < nSegments; i++) {
3949 if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
3951 _cmsFree(self ->ContextID, Segments);
3955 if (Segments) _cmsFree(self ->ContextID, Segments);
3961 cmsBool ReadMPECurve(struct _cms_typehandler_struct* self,
3965 cmsUInt32Number SizeOfTag)
3967 cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo;
3969 GammaTables[n] = ReadSegmentedCurve(self, io);
3970 return (GammaTables[n] != NULL);
3972 cmsUNUSED_PARAMETER(SizeOfTag);
3976 void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3978 cmsStage* mpe = NULL;
3979 cmsUInt16Number InputChans, OutputChans;
3980 cmsUInt32Number i, BaseOffset;
3981 cmsToneCurve** GammaTables;
3985 // Get actual position as a basis for element offsets
3986 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3988 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
3989 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
3991 if (InputChans != OutputChans) return NULL;
3993 GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*));
3994 if (GammaTables == NULL) return NULL;
3996 if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) {
3998 mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables);
4004 for (i=0; i < InputChans; i++) {
4005 if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]);
4008 _cmsFree(self ->ContextID, GammaTables);
4009 *nItems = (mpe != NULL) ? 1 : 0;
4012 cmsUNUSED_PARAMETER(SizeOfTag);
4016 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
4018 cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g)
4020 cmsUInt32Number i, j;
4021 cmsCurveSegment* Segments = g ->Segments;
4022 cmsUInt32Number nSegments = g ->nSegments;
4024 if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error;
4025 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4026 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error;
4027 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4029 // Write the break-points
4030 for (i=0; i < nSegments - 1; i++) {
4031 if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error;
4034 // Write the segments
4035 for (i=0; i < g ->nSegments; i++) {
4037 cmsCurveSegment* ActualSeg = Segments + i;
4039 if (ActualSeg -> Type == 0) {
4041 // This is a sampled curve
4042 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error;
4043 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4044 if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error;
4046 for (j=0; j < g ->Segments[i].nGridPoints; j++) {
4047 if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error;
4053 cmsUInt32Number ParamsByType[] = { 4, 5, 5 };
4055 // This is a formula-based
4056 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error;
4057 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4059 // We only allow 1, 2 and 3 as types
4060 Type = ActualSeg ->Type - 6;
4061 if (Type > 2 || Type < 0) goto Error;
4063 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error;
4064 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4066 for (j=0; j < ParamsByType[Type]; j++) {
4067 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error;
4071 // It seems there is no need to align. Code is here, and for safety commented out
4072 // if (!_cmsWriteAlignment(io)) goto Error;
4083 cmsBool WriteMPECurve(struct _cms_typehandler_struct* self,
4087 cmsUInt32Number SizeOfTag)
4089 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo;
4091 return WriteSegmentedCurve(io, Curves ->TheCurves[n]);
4093 cmsUNUSED_PARAMETER(SizeOfTag);
4094 cmsUNUSED_PARAMETER(self);
4097 // Write a curve, checking first for validity
4099 cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4101 cmsUInt32Number BaseOffset;
4102 cmsStage* mpe = (cmsStage*) Ptr;
4103 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data;
4105 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4107 // Write the header. Since those are curves, input and output channels are same
4108 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4109 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4111 if (!WritePositionTable(self, io, 0,
4112 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
4117 cmsUNUSED_PARAMETER(nItems);
4122 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4123 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4124 // is organized as follows:
4125 // array = [e11, e12,
\85, e1P, e21, e22,
\85, e2P,
\85, eQ1, eQ2,
\85, eQP, e1, e2,
\85, eQ]
4128 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4131 cmsUInt16Number InputChans, OutputChans;
4132 cmsUInt32Number nElems, i;
4133 cmsFloat64Number* Matrix;
4134 cmsFloat64Number* Offsets;
4136 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4137 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4140 nElems = InputChans * OutputChans;
4142 // Input and output chans may be ANY (up to 0xffff)
4143 Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number));
4144 if (Matrix == NULL) return NULL;
4146 Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number));
4147 if (Offsets == NULL) {
4149 _cmsFree(self ->ContextID, Matrix);
4153 for (i=0; i < nElems; i++) {
4157 if (!_cmsReadFloat32Number(io, &v)) return NULL;
4162 for (i=0; i < OutputChans; i++) {
4166 if (!_cmsReadFloat32Number(io, &v)) return NULL;
4171 mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets);
4172 _cmsFree(self ->ContextID, Matrix);
4173 _cmsFree(self ->ContextID, Offsets);
4179 cmsUNUSED_PARAMETER(SizeOfTag);
4183 cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4185 cmsUInt32Number i, nElems;
4186 cmsStage* mpe = (cmsStage*) Ptr;
4187 _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data;
4189 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4190 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4192 nElems = mpe ->InputChannels * mpe ->OutputChannels;
4194 for (i=0; i < nElems; i++) {
4195 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE;
4199 for (i=0; i < mpe ->OutputChannels; i++) {
4201 if (Matrix ->Offset == NULL) {
4203 if (!_cmsWriteFloat32Number(io, 0)) return FALSE;
4206 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE;
4212 cmsUNUSED_PARAMETER(nItems);
4213 cmsUNUSED_PARAMETER(self);
4219 void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4221 cmsStage* mpe = NULL;
4222 cmsUInt16Number InputChans, OutputChans;
4223 cmsUInt8Number Dimensions8[16];
4224 cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS];
4225 _cmsStageCLutData* clut;
4227 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4228 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4230 if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
4233 // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
4234 nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans;
4235 for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i];
4237 // Allocate the true CLUT
4238 mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
4239 if (mpe == NULL) goto Error;
4242 clut = (_cmsStageCLutData*) mpe ->Data;
4243 for (i=0; i < clut ->nEntries; i++) {
4245 if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
4253 if (mpe != NULL) cmsStageFree(mpe);
4256 cmsUNUSED_PARAMETER(SizeOfTag);
4259 // Write a CLUT in floating point
4261 cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4263 cmsUInt8Number Dimensions8[16];
4265 cmsStage* mpe = (cmsStage*) Ptr;
4266 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
4268 // Check for maximum number of channels
4269 if (mpe -> InputChannels > 15) return FALSE;
4271 // Only floats are supported in MPE
4272 if (clut ->HasFloatValues == FALSE) return FALSE;
4274 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4275 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4277 memset(Dimensions8, 0, sizeof(Dimensions8));
4279 for (i=0; i < mpe ->InputChannels; i++)
4280 Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
4282 if (!io ->Write(io, 16, Dimensions8)) return FALSE;
4284 for (i=0; i < clut ->nEntries; i++) {
4286 if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
4291 cmsUNUSED_PARAMETER(nItems);
4292 cmsUNUSED_PARAMETER(self);
4297 // This is the list of built-in MPE types
4298 static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
4300 {{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now
4301 {{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says)
4303 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] },
4304 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] },
4305 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL },
4308 #define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList))
4311 cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
4315 cmsUInt32Number SizeOfTag)
4317 cmsStageSignature ElementSig;
4318 cmsTagTypeHandler* TypeHandler;
4319 cmsStage *mpe = NULL;
4320 cmsUInt32Number nItems;
4321 cmsPipeline *NewLUT = (cmsPipeline *) Cargo;
4323 // Take signature and channels for each element.
4324 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE;
4326 // The reserved placeholder
4327 if (!_cmsReadUInt32Number(io, NULL)) return FALSE;
4329 // Read diverse MPE types
4330 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
4331 if (TypeHandler == NULL) {
4335 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4337 // An unknown element was found.
4338 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String);
4342 // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
4343 // Read the MPE. No size is given
4344 if (TypeHandler ->ReadPtr != NULL) {
4346 // This is a real element which should be read and processed
4347 mpe = (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag);
4348 if (mpe == NULL) return FALSE;
4350 // All seems ok, insert element
4351 cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
4356 cmsUNUSED_PARAMETER(SizeOfTag);
4357 cmsUNUSED_PARAMETER(n);
4361 // This is the main dispatcher for MPE
4363 void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4365 cmsUInt16Number InputChans, OutputChans;
4366 cmsUInt32Number ElementCount;
4367 cmsPipeline *NewLUT = NULL;
4368 cmsUInt32Number BaseOffset;
4370 // Get actual position as a basis for element offsets
4371 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4373 // Read channels and element count
4374 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4375 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4377 // Allocates an empty LUT
4378 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
4379 if (NewLUT == NULL) return NULL;
4381 if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL;
4383 if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) {
4384 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
4393 cmsUNUSED_PARAMETER(SizeOfTag);
4398 // This one is a liitle bit more complex, so we don't use position tables this time.
4400 cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4402 cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos;
4403 int inputChan, outputChan;
4404 cmsUInt32Number ElemCount;
4405 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before;
4406 cmsStageSignature ElementSig;
4407 cmsPipeline* Lut = (cmsPipeline*) Ptr;
4408 cmsStage* Elem = Lut ->Elements;
4409 cmsTagTypeHandler* TypeHandler;
4411 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4413 inputChan = cmsPipelineInputChannels(Lut);
4414 outputChan = cmsPipelineOutputChannels(Lut);
4415 ElemCount = cmsPipelineStageCount(Lut);
4417 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *));
4418 if (ElementOffsets == NULL) goto Error;
4420 ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *));
4421 if (ElementSizes == NULL) goto Error;
4424 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error;
4425 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error;
4426 if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error;
4428 DirectoryPos = io ->Tell(io);
4430 // Write a fake directory to be filled latter on
4431 for (i=0; i < ElemCount; i++) {
4432 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
4433 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
4436 // Write each single tag. Keep track of the size as well.
4437 for (i=0; i < ElemCount; i++) {
4439 ElementOffsets[i] = io ->Tell(io) - BaseOffset;
4441 ElementSig = Elem ->Type;
4443 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
4444 if (TypeHandler == NULL) {
4448 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4450 // An unknow element was found.
4451 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String);
4455 if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error;
4456 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4457 Before = io ->Tell(io);
4458 if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error;
4459 if (!_cmsWriteAlignment(io)) goto Error;
4461 ElementSizes[i] = io ->Tell(io) - Before;
4466 // Write the directory
4467 CurrentPos = io ->Tell(io);
4469 if (!io ->Seek(io, DirectoryPos)) goto Error;
4471 for (i=0; i < ElemCount; i++) {
4472 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
4473 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
4476 if (!io ->Seek(io, CurrentPos)) goto Error;
4478 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4479 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4483 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4484 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4487 cmsUNUSED_PARAMETER(nItems);
4492 void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4494 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
4496 cmsUNUSED_PARAMETER(n);
4497 cmsUNUSED_PARAMETER(self);
4501 void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr)
4503 cmsPipelineFree((cmsPipeline*) Ptr);
4506 cmsUNUSED_PARAMETER(self);
4510 // ********************************************************************************
4511 // Type cmsSigVcgtType
4512 // ********************************************************************************
4515 #define cmsVideoCardGammaTableType 0
4516 #define cmsVideoCardGammaFormulaType 1
4527 void *Type_vcgt_Read(struct _cms_typehandler_struct* self,
4529 cmsUInt32Number* nItems,
4530 cmsUInt32Number SizeOfTag)
4532 cmsUInt32Number TagType, n, i;
4533 cmsToneCurve** Curves;
4538 if (!_cmsReadUInt32Number(io, &TagType)) return NULL;
4540 // Allocate space for the array
4541 Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4542 if (Curves == NULL) return NULL;
4544 // There are two possible flavors
4547 // Gamma is stored as a table
4548 case cmsVideoCardGammaTableType:
4550 cmsUInt16Number nChannels, nElems, nBytes;
4552 // Check channel count, which should be 3 (we don't support monochrome this time)
4553 if (!_cmsReadUInt16Number(io, &nChannels)) goto Error;
4555 if (nChannels != 3) {
4556 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels);
4560 // Get Table element count and bytes per element
4561 if (!_cmsReadUInt16Number(io, &nElems)) goto Error;
4562 if (!_cmsReadUInt16Number(io, &nBytes)) goto Error;
4564 // Adobe's quirk fixup. Fixing broken profiles...
4565 if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576)
4569 // Populate tone curves
4570 for (n=0; n < 3; n++) {
4572 Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL);
4573 if (Curves[n] == NULL) goto Error;
4575 // On depending on byte depth
4580 for (i=0; i < nElems; i++) {
4584 if (!_cmsReadUInt8Number(io, &v)) goto Error;
4585 Curves[n] ->Table16[i] = FROM_8_TO_16(v);
4589 // One word 0..65535
4591 if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error;
4596 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8);
4599 } // For all 3 channels
4603 // In this case, gamma is stored as a formula
4604 case cmsVideoCardGammaFormulaType:
4606 _cmsVCGTGAMMA Colorant[3];
4608 // Populate tone curves
4609 for (n=0; n < 3; n++) {
4613 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error;
4614 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error;
4615 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error;
4617 // Parametric curve type 5 is:
4618 // Y = (aX + b)^Gamma + e | X >= d
4619 // Y = cX + f | X < d
4622 // Y = (Max
\96 Min) * (X ^ Gamma) + Min
4624 // So, the translation is
4625 // a = (Max
\96 Min) ^ ( 1 / Gamma)
4629 Params[0] = Colorant[n].Gamma;
4630 Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma));
4634 Params[5] = Colorant[n].Min;
4637 Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
4638 if (Curves[n] == NULL) goto Error;
4645 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
4650 return (void*) Curves;
4652 // Regret, free all resources
4655 cmsFreeToneCurveTriple(Curves);
4656 _cmsFree(self ->ContextID, Curves);
4659 cmsUNUSED_PARAMETER(SizeOfTag);
4663 // We don't support all flavors, only 16bits tables and formula
4665 cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4667 cmsToneCurve** Curves = (cmsToneCurve**) Ptr;
4668 cmsUInt32Number i, j;
4670 if (cmsGetToneCurveParametricType(Curves[0]) == 5 &&
4671 cmsGetToneCurveParametricType(Curves[1]) == 5 &&
4672 cmsGetToneCurveParametricType(Curves[2]) == 5) {
4674 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
4677 for (i=0; i < 3; i++) {
4681 v.Gamma = Curves[i] ->Segments[0].Params[0];
4682 v.Min = Curves[i] ->Segments[0].Params[5];
4683 v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min;
4685 if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE;
4686 if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE;
4687 if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE;
4693 // Always store as a table of 256 words
4694 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE;
4695 if (!_cmsWriteUInt16Number(io, 3)) return FALSE;
4696 if (!_cmsWriteUInt16Number(io, 256)) return FALSE;
4697 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
4699 for (i=0; i < 3; i++) {
4700 for (j=0; j < 256; j++) {
4702 cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0));
4703 cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0);
4705 if (!_cmsWriteUInt16Number(io, n)) return FALSE;
4712 cmsUNUSED_PARAMETER(self);
4713 cmsUNUSED_PARAMETER(nItems);
4717 void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4719 cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr;
4720 cmsToneCurve** NewCurves;
4722 NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4723 if (NewCurves == NULL) return NULL;
4725 NewCurves[0] = cmsDupToneCurve(OldCurves[0]);
4726 NewCurves[1] = cmsDupToneCurve(OldCurves[1]);
4727 NewCurves[2] = cmsDupToneCurve(OldCurves[2]);
4729 return (void*) NewCurves;
4731 cmsUNUSED_PARAMETER(n);
4736 void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr)
4738 cmsFreeToneCurveTriple((cmsToneCurve**) Ptr);
4739 _cmsFree(self ->ContextID, Ptr);
4743 // ********************************************************************************
4744 // Type cmsSigDictType
4745 // ********************************************************************************
4747 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data
4749 cmsContext ContextID;
4750 cmsUInt32Number *Offsets;
4751 cmsUInt32Number *Sizes;
4755 _cmsDICelem Name, Value, DisplayName, DisplayValue;
4759 // Allocate an empty array element
4761 cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count)
4763 e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number *));
4764 if (e->Offsets == NULL) return FALSE;
4766 e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number *));
4767 if (e->Sizes == NULL) {
4769 _cmsFree(ContextID, e -> Offsets);
4773 e ->ContextID = ContextID;
4777 // Free an array element
4779 void FreeElem(_cmsDICelem* e)
4781 if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets);
4782 if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e ->Sizes);
4783 e->Offsets = e ->Sizes = NULL;
4786 // Get rid of whole array
4788 void FreeArray( _cmsDICarray* a)
4790 if (a ->Name.Offsets != NULL) FreeElem(&a->Name);
4791 if (a ->Value.Offsets != NULL) FreeElem(&a ->Value);
4792 if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName);
4793 if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue);
4797 // Allocate whole array
4799 cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
4802 memset(a, 0, sizeof(_cmsDICarray));
4804 // On depending on record size, create column arrays
4805 if (!AllocElem(ContextID, &a ->Name, Count)) goto Error;
4806 if (!AllocElem(ContextID, &a ->Value, Count)) goto Error;
4809 if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error;
4813 if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error;
4824 cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset)
4826 if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE;
4827 if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE;
4829 // An offset of zero has special meaning and shal be preserved
4830 if (e ->Offsets[i] > 0)
4831 e ->Offsets[i] += BaseOffset;
4837 cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset)
4841 // Read column arrays
4842 for (i=0; i < Count; i++) {
4844 if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE;
4845 if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE;
4849 if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE;
4855 if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE;
4862 // Write one element
4864 cmsBool WriteOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i)
4866 if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE;
4867 if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE;
4873 cmsBool WriteOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
4877 for (i=0; i < Count; i++) {
4879 if (!WriteOneElem(io, &a -> Name, i)) return FALSE;
4880 if (!WriteOneElem(io, &a -> Value, i)) return FALSE;
4884 if (!WriteOneElem(io, &a -> DisplayName, i)) return FALSE;
4889 if (!WriteOneElem(io, &a -> DisplayValue, i)) return FALSE;
4897 cmsBool ReadOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr)
4900 cmsUInt32Number nChars;
4902 // Special case for undefined strings (see ICC Votable
4903 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
4904 if (e -> Offsets[i] == 0) {
4910 if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
4912 nChars = e ->Sizes[i] / sizeof(cmsUInt16Number);
4915 *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t));
4916 if (*wcstr == NULL) return FALSE;
4918 if (!_cmsReadWCharArray(io, nChars, *wcstr)) {
4919 _cmsFree(e ->ContextID, *wcstr);
4923 // End of string marker
4924 (*wcstr)[nChars] = 0;
4929 cmsUInt32Number mywcslen(const wchar_t *s)
4937 return (cmsUInt32Number)(p - s);
4941 cmsBool WriteOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset)
4943 cmsUInt32Number Before = io ->Tell(io);
4946 e ->Offsets[i] = Before - BaseOffset;
4948 if (wcstr == NULL) {
4954 n = mywcslen(wcstr);
4955 if (!_cmsWriteWCharArray(io, n, wcstr)) return FALSE;
4957 e ->Sizes[i] = io ->Tell(io) - Before;
4962 cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu)
4964 cmsUInt32Number nItems = 0;
4966 // A way to get null MLUCs
4967 if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) {
4973 if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
4975 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]);
4976 return *mlu != NULL;
4980 cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset)
4982 cmsUInt32Number Before;
4984 // Special case for undefined strings (see ICC Votable
4985 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
4992 Before = io ->Tell(io);
4993 e ->Offsets[i] = Before - BaseOffset;
4995 if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE;
4997 e ->Sizes[i] = io ->Tell(io) - Before;
5003 void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
5006 cmsUInt32Number i, Count, Length;
5007 cmsUInt32Number BaseOffset;
5009 wchar_t *NameWCS = NULL, *ValueWCS = NULL;
5010 cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL;
5015 // Get actual position as a basis for element offsets
5016 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
5018 // Get name-value record count
5019 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
5020 SizeOfTag -= sizeof(cmsUInt32Number);
5023 if (!_cmsReadUInt32Number(io, &Length)) return NULL;
5024 SizeOfTag -= sizeof(cmsUInt32Number);
5026 // Check for valid lengths
5027 if (Length != 16 && Length != 24 && Length != 32) {
5028 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length);
5032 // Creates an empty dictionary
5033 hDict = cmsDictAlloc(self -> ContextID);
5034 if (hDict == NULL) return NULL;
5036 // On depending on record size, create column arrays
5037 if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error;
5039 // Read column arrays
5040 if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error;
5042 // Seek to each element and read it
5043 for (i=0; i < Count; i++) {
5045 if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error;
5046 if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error;
5049 if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error;
5053 if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error;
5056 rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
5058 if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS);
5059 if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS);
5060 if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU);
5061 if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU);
5063 if (!rc) return FALSE;
5068 return (void*) hDict;
5078 cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
5080 cmsHANDLE hDict = (cmsHANDLE) Ptr;
5081 const cmsDICTentry* p;
5082 cmsBool AnyName, AnyValue;
5083 cmsUInt32Number i, Count, Length;
5084 cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset;
5087 if (hDict == NULL) return FALSE;
5089 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
5091 // Let's inspect the dictionary
5092 Count = 0; AnyName = FALSE; AnyValue = FALSE;
5093 for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) {
5095 if (p ->DisplayName != NULL) AnyName = TRUE;
5096 if (p ->DisplayValue != NULL) AnyValue = TRUE;
5101 if (AnyName) Length += 8;
5102 if (AnyValue) Length += 8;
5104 if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
5105 if (!_cmsWriteUInt32Number(io, Length)) return FALSE;
5107 // Keep starting position of offsets table
5108 DirectoryPos = io ->Tell(io);
5110 // Allocate offsets array
5111 if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error;
5113 // Write a fake directory to be filled latter on
5114 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5116 // Write each element. Keep track of the size as well.
5117 p = cmsDictGetEntryList(hDict);
5118 for (i=0; i < Count; i++) {
5120 if (!WriteOneWChar(io, &a.Name, i, p ->Name, BaseOffset)) goto Error;
5121 if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error;
5123 if (p ->DisplayName != NULL) {
5124 if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error;
5127 if (p ->DisplayValue != NULL) {
5128 if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error;
5131 p = cmsDictNextEntry(p);
5134 // Write the directory
5135 CurrentPos = io ->Tell(io);
5136 if (!io ->Seek(io, DirectoryPos)) goto Error;
5138 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5140 if (!io ->Seek(io, CurrentPos)) goto Error;
5149 cmsUNUSED_PARAMETER(nItems);
5154 void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
5156 return (void*) cmsDictDup((cmsHANDLE) Ptr);
5158 cmsUNUSED_PARAMETER(n);
5159 cmsUNUSED_PARAMETER(self);
5164 void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr)
5166 cmsDictFree((cmsHANDLE) Ptr);
5167 cmsUNUSED_PARAMETER(self);
5171 // ********************************************************************************
5172 // Type support main routines
5173 // ********************************************************************************
5176 // This is the list of built-in types
5177 static _cmsTagTypeLinkedList SupportedTagTypes[] = {
5179 {TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] },
5180 {TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), &SupportedTagTypes[2] },
5181 {TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), &SupportedTagTypes[3] },
5182 {TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), &SupportedTagTypes[4] },
5183 {TYPE_HANDLER(cmsSigTextType, Text), &SupportedTagTypes[5] },
5184 {TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), &SupportedTagTypes[6] },
5185 {TYPE_HANDLER(cmsSigCurveType, Curve), &SupportedTagTypes[7] },
5186 {TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), &SupportedTagTypes[8] },
5187 {TYPE_HANDLER(cmsSigDateTimeType, DateTime), &SupportedTagTypes[9] },
5188 {TYPE_HANDLER(cmsSigLut8Type, LUT8), &SupportedTagTypes[10] },
5189 {TYPE_HANDLER(cmsSigLut16Type, LUT16), &SupportedTagTypes[11] },
5190 {TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), &SupportedTagTypes[12] },
5191 {TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), &SupportedTagTypes[13] },
5192 {TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), &SupportedTagTypes[14] },
5193 {TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc), &SupportedTagTypes[15] },
5194 {TYPE_HANDLER(cmsSigSignatureType, Signature), &SupportedTagTypes[16] },
5195 {TYPE_HANDLER(cmsSigMeasurementType, Measurement), &SupportedTagTypes[17] },
5196 {TYPE_HANDLER(cmsSigDataType, Data), &SupportedTagTypes[18] },
5197 {TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), &SupportedTagTypes[19] },
5198 {TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), &SupportedTagTypes[20] },
5199 {TYPE_HANDLER(cmsSigUcrBgType, UcrBg), &SupportedTagTypes[21] },
5200 {TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), &SupportedTagTypes[22] },
5201 {TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), &SupportedTagTypes[23] },
5202 {TYPE_HANDLER(cmsSigScreeningType, Screening), &SupportedTagTypes[24] },
5203 {TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), &SupportedTagTypes[25] },
5204 {TYPE_HANDLER(cmsSigXYZType, XYZ), &SupportedTagTypes[26] },
5205 {TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] },
5206 {TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] },
5207 {TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] },
5208 {TYPE_HANDLER(cmsSigDictType, Dictionary), &SupportedTagTypes[30] },
5209 {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL }
5212 #define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList))
5214 // Both kind of plug-ins share same structure
5215 cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Data)
5217 return RegisterTypesPlugin(Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT);
5220 cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Data)
5222 return RegisterTypesPlugin(Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT);
5226 // Wrapper for tag types
5227 cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig)
5229 return GetHandler(sig, SupportedTagTypes);
5232 // ********************************************************************************
5233 // Tag support main routines
5234 // ********************************************************************************
5236 typedef struct _cmsTagLinkedList_st {
5238 cmsTagSignature Signature;
5239 cmsTagDescriptor Descriptor;
5240 struct _cmsTagLinkedList_st* Next;
5242 } _cmsTagLinkedList;
5244 // This is the list of built-in tags
5245 static _cmsTagLinkedList SupportedTags[] = {
5247 { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]},
5248 { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]},
5249 { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]},
5250 { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]},
5251 { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]},
5252 { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]},
5254 // Allow corbis and its broken XYZ type
5255 { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]},
5256 { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]},
5257 { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]},
5259 { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]},
5260 { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]},
5261 { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]},
5263 { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]},
5264 { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]},
5266 { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]},
5267 { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]},
5268 { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]},
5269 { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]},
5270 { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]},
5272 { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]},
5273 { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]},
5275 { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]},
5276 { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]},
5278 { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]},
5280 { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]},
5281 { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]},
5283 { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]},
5284 { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]},
5286 { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]},
5288 { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]},
5289 { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]},
5290 { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]},
5292 { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]},
5293 { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]},
5294 { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]},
5296 { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]},
5297 { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]},
5298 { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]},
5300 { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]},
5302 { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]},
5303 { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]},
5304 { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]},
5305 { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]},
5306 { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]},
5307 { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]},
5309 { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]},
5311 { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]},
5312 { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]},
5314 { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]},
5315 { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]},
5316 { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]},
5317 { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]},
5318 { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]},
5319 { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]},
5320 { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]},
5321 { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]},
5323 { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]},
5324 { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]},
5326 { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]},
5327 { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]},
5328 { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]},
5329 { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL}, NULL}
5335 ======================= =========================================
5336 cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
5337 cmsSigNamedColorTag ==> Deprecated
5338 cmsSigDataTag ==> Ancient, unused
5339 cmsSigDeviceSettingsTag ==> Deprecated, useless
5342 #define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList))
5344 cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Data)
5346 cmsPluginTag* Plugin = (cmsPluginTag*) Data;
5347 _cmsTagLinkedList *pt, *Anterior;
5352 SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL;
5356 pt = Anterior = SupportedTags;
5357 while (pt != NULL) {
5359 if (Plugin->Signature == pt -> Signature) {
5360 pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour
5368 pt = (_cmsTagLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagLinkedList));
5369 if (pt == NULL) return FALSE;
5371 pt ->Signature = Plugin ->Signature;
5372 pt ->Descriptor = Plugin ->Descriptor;
5375 if (Anterior != NULL) Anterior -> Next = pt;
5380 // Return a descriptor for a given tag or NULL
5381 cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig)
5383 _cmsTagLinkedList* pt;
5385 for (pt = SupportedTags;
5389 if (sig == pt -> Signature) return &pt ->Descriptor;