1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2016 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 multiprocessing
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. LinkedList points to the optional list head
65 cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos)
67 cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
68 _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos);
69 _cmsTagTypeLinkedList *pt;
71 // Calling the function with NULL as plug-in would unregister the plug in.
74 // There is no need to set free the memory, as pool is destroyed as a whole.
75 ctx ->TagTypes = NULL;
79 // Registering happens in plug-in memory pool.
80 pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList));
81 if (pt == NULL) return FALSE;
83 pt ->Handler = Plugin ->Handler;
84 pt ->Next = ctx ->TagTypes;
91 // Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons
92 // made by plug-ins and then the built-in defaults.
94 cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList)
96 _cmsTagTypeLinkedList* pt;
98 for (pt = PluginLinkedList;
102 if (sig == pt -> Handler.Signature) return &pt ->Handler;
105 for (pt = DefaultLinkedList;
109 if (sig == pt -> Handler.Signature) return &pt ->Handler;
116 // Auxiliar to convert UTF-32 to UTF-16 in some cases
118 cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array)
122 _cmsAssert(io != NULL);
123 _cmsAssert(!(Array == NULL && n > 0));
125 for (i=0; i < n; i++) {
126 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE;
132 // Auxiliar to read an array of wchar_t
134 cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
139 _cmsAssert(io != NULL);
141 for (i=0; i < n; i++) {
145 if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
146 Array[i] = (wchar_t) tmp;
149 if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
156 // To deal with position tables
157 typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
161 cmsUInt32Number SizeOfTag);
163 // Helper function to deal with position tables as decribed in ICC spec 4.3
164 // A table of n elements is readed, where first comes n records containing offsets and sizes and
165 // then a block containing the data itself. This allows to reuse same data in more than one entry
167 cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
169 cmsUInt32Number Count,
170 cmsUInt32Number BaseOffset,
172 PositionTableEntryFn ElementFn)
175 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
177 // Let's take the offsets to each element
178 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
179 if (ElementOffsets == NULL) goto Error;
181 ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
182 if (ElementSizes == NULL) goto Error;
184 for (i=0; i < Count; i++) {
186 if (!_cmsReadUInt32Number(io, &ElementOffsets[i])) goto Error;
187 if (!_cmsReadUInt32Number(io, &ElementSizes[i])) goto Error;
189 ElementOffsets[i] += BaseOffset;
192 // Seek to each element and read it
193 for (i=0; i < Count; i++) {
195 if (!io -> Seek(io, ElementOffsets[i])) goto Error;
197 // This is the reader callback
198 if (!ElementFn(self, io, Cargo, i, ElementSizes[i])) goto Error;
202 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
203 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
207 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
208 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
212 // Same as anterior, but for write position tables
214 cmsBool WritePositionTable(struct _cms_typehandler_struct* self,
216 cmsUInt32Number SizeOfTag,
217 cmsUInt32Number Count,
218 cmsUInt32Number BaseOffset,
220 PositionTableEntryFn ElementFn)
223 cmsUInt32Number DirectoryPos, CurrentPos, Before;
224 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
227 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
228 if (ElementOffsets == NULL) goto Error;
230 ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
231 if (ElementSizes == NULL) goto Error;
233 // Keep starting position of curve offsets
234 DirectoryPos = io ->Tell(io);
236 // Write a fake directory to be filled latter on
237 for (i=0; i < Count; i++) {
239 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
240 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
243 // Write each element. Keep track of the size as well.
244 for (i=0; i < Count; i++) {
246 Before = io ->Tell(io);
247 ElementOffsets[i] = Before - BaseOffset;
249 // Callback to write...
250 if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error;
253 ElementSizes[i] = io ->Tell(io) - Before;
256 // Write the directory
257 CurrentPos = io ->Tell(io);
258 if (!io ->Seek(io, DirectoryPos)) goto Error;
260 for (i=0; i < Count; i++) {
261 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
262 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
265 if (!io ->Seek(io, CurrentPos)) goto Error;
267 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
268 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
272 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
273 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
278 // ********************************************************************************
279 // Type XYZ. Only one value is allowed
280 // ********************************************************************************
282 //The XYZType contains an array of three encoded values for the XYZ tristimulus
283 //values. Tristimulus values must be non-negative. The signed encoding allows for
284 //implementation optimizations by minimizing the number of fixed formats.
288 void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
293 xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ));
294 if (xyz == NULL) return NULL;
296 if (!_cmsReadXYZNumber(io, xyz)) {
297 _cmsFree(self ->ContextID, xyz);
304 cmsUNUSED_PARAMETER(SizeOfTag);
308 cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
310 return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr);
312 cmsUNUSED_PARAMETER(nItems);
313 cmsUNUSED_PARAMETER(self);
317 void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
319 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ));
321 cmsUNUSED_PARAMETER(n);
325 void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr)
327 _cmsFree(self ->ContextID, Ptr);
332 cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data)
334 return cmsSigXYZType;
336 cmsUNUSED_PARAMETER(ICCVersion);
337 cmsUNUSED_PARAMETER(Data);
341 // ********************************************************************************
342 // Type chromaticity. Only one value is allowed
343 // ********************************************************************************
344 // The chromaticity tag type provides basic chromaticity data and type of
345 // phosphors or colorants of a monitor to applications and utilities.
348 void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
350 cmsCIExyYTRIPLE* chrm;
351 cmsUInt16Number nChans, Table;
354 chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE));
355 if (chrm == NULL) return NULL;
357 if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
359 // Let's recover from a bug introduced in early versions of lcms1
360 if (nChans == 0 && SizeOfTag == 32) {
362 if (!_cmsReadUInt16Number(io, NULL)) goto Error;
363 if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
366 if (nChans != 3) goto Error;
368 if (!_cmsReadUInt16Number(io, &Table)) goto Error;
370 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error;
371 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error;
375 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error;
376 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error;
378 chrm ->Green.Y = 1.0;
380 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error;
381 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error;
389 _cmsFree(self ->ContextID, (void*) chrm);
392 cmsUNUSED_PARAMETER(SizeOfTag);
396 cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io)
398 if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE;
399 if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE;
405 cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
407 cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr;
409 if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels
410 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table
412 if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE;
413 if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE;
414 if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE;
418 cmsUNUSED_PARAMETER(nItems);
419 cmsUNUSED_PARAMETER(self);
423 void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
425 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE));
427 cmsUNUSED_PARAMETER(n);
431 void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr)
433 _cmsFree(self ->ContextID, Ptr);
437 // ********************************************************************************
438 // Type cmsSigColorantOrderType
439 // ********************************************************************************
441 // This is an optional tag which specifies the laydown order in which colorants will
442 // be printed on an n-colorant device. The laydown order may be the same as the
443 // channel generation order listed in the colorantTableTag or the channel order of a
444 // colour space such as CMYK, in which case this tag is not needed. When this is not
445 // the case (for example, ink-towers sometimes use the order KCMY), this tag may be
446 // used to specify the laydown order of the colorants.
450 void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
452 cmsUInt8Number* ColorantOrder;
453 cmsUInt32Number Count;
456 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
457 if (Count > cmsMAXCHANNELS) return NULL;
459 ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number));
460 if (ColorantOrder == NULL) return NULL;
462 // We use FF as end marker
463 memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
465 if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) {
467 _cmsFree(self ->ContextID, (void*) ColorantOrder);
472 return (void*) ColorantOrder;
474 cmsUNUSED_PARAMETER(SizeOfTag);
478 cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
480 cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr;
481 cmsUInt32Number i, sz, Count;
484 for (Count=i=0; i < cmsMAXCHANNELS; i++) {
485 if (ColorantOrder[i] != 0xFF) Count++;
488 if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
490 sz = Count * sizeof(cmsUInt8Number);
491 if (!io -> Write(io, sz, ColorantOrder)) return FALSE;
495 cmsUNUSED_PARAMETER(nItems);
496 cmsUNUSED_PARAMETER(self);
500 void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
502 return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
504 cmsUNUSED_PARAMETER(n);
509 void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr)
511 _cmsFree(self ->ContextID, Ptr);
514 // ********************************************************************************
515 // Type cmsSigS15Fixed16ArrayType
516 // ********************************************************************************
517 // This type represents an array of generic 4-byte/32-bit fixed point quantity.
518 // The number of values is determined from the size of the tag.
521 void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
523 cmsFloat64Number* array_double;
524 cmsUInt32Number i, n;
527 n = SizeOfTag / sizeof(cmsUInt32Number);
528 array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
529 if (array_double == NULL) return NULL;
531 for (i=0; i < n; i++) {
533 if (!_cmsRead15Fixed16Number(io, &array_double[i])) {
535 _cmsFree(self ->ContextID, array_double);
541 return (void*) array_double;
545 cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
547 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
550 for (i=0; i < nItems; i++) {
552 if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE;
557 cmsUNUSED_PARAMETER(self);
561 void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
563 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
568 void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
570 _cmsFree(self ->ContextID, Ptr);
573 // ********************************************************************************
574 // Type cmsSigU16Fixed16ArrayType
575 // ********************************************************************************
576 // This type represents an array of generic 4-byte/32-bit quantity.
577 // The number of values is determined from the size of the tag.
581 void *Type_U16Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
583 cmsFloat64Number* array_double;
585 cmsUInt32Number i, n;
588 n = SizeOfTag / sizeof(cmsUInt32Number);
589 array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
590 if (array_double == NULL) return NULL;
592 for (i=0; i < n; i++) {
594 if (!_cmsReadUInt32Number(io, &v)) {
595 _cmsFree(self ->ContextID, (void*) array_double);
599 // Convert to cmsFloat64Number
600 array_double[i] = (cmsFloat64Number) (v / 65536.0);
604 return (void*) array_double;
608 cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
610 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
613 for (i=0; i < nItems; i++) {
615 cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5);
617 if (!_cmsWriteUInt32Number(io, v)) return FALSE;
622 cmsUNUSED_PARAMETER(self);
627 void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
629 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
633 void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
635 _cmsFree(self ->ContextID, Ptr);
638 // ********************************************************************************
639 // Type cmsSigSignatureType
640 // ********************************************************************************
642 // The signatureType contains a four-byte sequence, Sequences of less than four
643 // characters are padded at the end with spaces, 20h.
644 // Typically this type is used for registered tags that can be displayed on many
645 // development systems as a sequence of four characters.
648 void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
650 cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature));
651 if (SigPtr == NULL) return NULL;
653 if (!_cmsReadUInt32Number(io, SigPtr)) return NULL;
658 cmsUNUSED_PARAMETER(SizeOfTag);
662 cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
664 cmsSignature* SigPtr = (cmsSignature*) Ptr;
666 return _cmsWriteUInt32Number(io, *SigPtr);
668 cmsUNUSED_PARAMETER(nItems);
669 cmsUNUSED_PARAMETER(self);
673 void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
675 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature));
679 void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr)
681 _cmsFree(self ->ContextID, Ptr);
685 // ********************************************************************************
686 // Type cmsSigTextType
687 // ********************************************************************************
689 // The textType is a simple text structure that contains a 7-bit ASCII text string.
690 // The length of the string is obtained by subtracting 8 from the element size portion
691 // of the tag itself. This string must be terminated with a 00h byte.
694 void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
699 // Create a container
700 mlu = cmsMLUalloc(self ->ContextID, 1);
701 if (mlu == NULL) return NULL;
705 // We need to store the "\0" at the end, so +1
706 if (SizeOfTag == UINT_MAX) goto Error;
708 Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
709 if (Text == NULL) goto Error;
711 if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error;
713 // Make sure text is properly ended
718 if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
720 _cmsFree(self ->ContextID, Text);
727 _cmsFree(self ->ContextID, Text);
732 // The conversion implies to choose a language. So, we choose the actual language.
734 cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
736 cmsMLU* mlu = (cmsMLU*) Ptr;
737 cmsUInt32Number size;
741 // Get the size of the string. Note there is an extra "\0" at the end
742 size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
743 if (size == 0) return FALSE; // Cannot be zero!
746 Text = (char*) _cmsMalloc(self ->ContextID, size);
747 if (Text == NULL) return FALSE;
749 cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
751 // Write it, including separator
752 rc = io ->Write(io, size, Text);
754 _cmsFree(self ->ContextID, Text);
757 cmsUNUSED_PARAMETER(nItems);
761 void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
763 return (void*) cmsMLUdup((cmsMLU*) Ptr);
765 cmsUNUSED_PARAMETER(n);
766 cmsUNUSED_PARAMETER(self);
771 void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr)
773 cmsMLU* mlu = (cmsMLU*) Ptr;
777 cmsUNUSED_PARAMETER(self);
781 cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data)
783 if (ICCVersion >= 4.0)
784 return cmsSigMultiLocalizedUnicodeType;
786 return cmsSigTextType;
788 cmsUNUSED_PARAMETER(Data);
792 // ********************************************************************************
793 // Type cmsSigDataType
794 // ********************************************************************************
796 // General purpose data type
798 void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
801 cmsUInt32Number LenOfData;
805 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
807 LenOfData = SizeOfTag - sizeof(cmsUInt32Number);
808 if (LenOfData > INT_MAX) return NULL;
810 BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1);
811 if (BinData == NULL) return NULL;
813 BinData ->len = LenOfData;
814 if (!_cmsReadUInt32Number(io, &BinData->flag)) {
815 _cmsFree(self ->ContextID, BinData);
819 if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) {
821 _cmsFree(self ->ContextID, BinData);
827 return (void*) BinData;
832 cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
834 cmsICCData* BinData = (cmsICCData*) Ptr;
836 if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE;
838 return io ->Write(io, BinData ->len, BinData ->data);
840 cmsUNUSED_PARAMETER(nItems);
841 cmsUNUSED_PARAMETER(self);
846 void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
848 cmsICCData* BinData = (cmsICCData*) Ptr;
850 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1);
852 cmsUNUSED_PARAMETER(n);
856 void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr)
858 _cmsFree(self ->ContextID, Ptr);
861 // ********************************************************************************
862 // Type cmsSigTextDescriptionType
863 // ********************************************************************************
866 void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
870 cmsUInt32Number AsciiCount;
871 cmsUInt32Number i, UnicodeCode, UnicodeCount;
872 cmsUInt16Number ScriptCodeCode, Dummy;
873 cmsUInt8Number ScriptCodeCount;
877 // One dword should be there
878 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
881 if (!_cmsReadUInt32Number(io, &AsciiCount)) return NULL;
882 SizeOfTag -= sizeof(cmsUInt32Number);
885 if (SizeOfTag < AsciiCount) return NULL;
887 // All seems Ok, allocate the container
888 mlu = cmsMLUalloc(self ->ContextID, 1);
889 if (mlu == NULL) return NULL;
891 // As many memory as size of tag
892 Text = (char*) _cmsMalloc(self ->ContextID, AsciiCount + 1);
893 if (Text == NULL) goto Error;
896 if (io ->Read(io, Text, sizeof(char), AsciiCount) != AsciiCount) goto Error;
897 SizeOfTag -= AsciiCount;
899 // Make sure there is a terminator
900 Text[AsciiCount] = 0;
902 // Set the MLU entry. From here we can be tolerant to wrong types
903 if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
904 _cmsFree(self ->ContextID, (void*) Text);
908 if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done;
909 if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done;
910 if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done;
911 SizeOfTag -= 2* sizeof(cmsUInt32Number);
913 if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
915 for (i=0; i < UnicodeCount; i++) {
916 if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done;
918 SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number);
920 // Skip ScriptCode code if present. Some buggy profiles does have less
921 // data that stricttly required. We need to skip it as this type may come
922 // embedded in other types.
924 if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) {
926 if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done;
927 if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done;
930 for (i=0; i < 67; i++) {
931 if (!io ->Read(io, &Dummy, sizeof(cmsUInt8Number), 1)) goto Error;
941 if (Text) _cmsFree(self ->ContextID, (void*) Text);
942 if (mlu) cmsMLUfree(mlu);
947 // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
949 cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
951 cmsMLU* mlu = (cmsMLU*) Ptr;
953 wchar_t *Wide = NULL;
954 cmsUInt32Number len, len_text, len_tag_requirement, len_aligned;
958 // Used below for writting zeroes
959 memset(Filler, 0, sizeof(Filler));
961 // Get the len of string
962 len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
964 // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data
965 //(see clause 4.1 for the definition of �aligned�). Because the Unicode language
966 // code and Unicode count immediately follow the ASCII description, their
967 // alignment is not correct if the ASCII count is not a multiple of four. The
968 // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
969 // writing software must be written carefully in order to handle these alignment
972 // The above last sentence suggest to handle alignment issues in the
973 // parser. The provided example (Table 69 on Page 60) makes this clear.
974 // The padding only in the ASCII count is not sufficient for a aligned tag
975 // size, with the same text size in ASCII and Unicode.
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 // Tell the real text len including the null terminator and padding
997 len_text = strlen(Text) + 1;
998 // Compute an total tag size requirement
999 len_tag_requirement = (8+4+len_text+4+4+2*len_text+2+1+67);
1000 len_aligned = _cmsALIGNLONG(len_tag_requirement);
1002 // * cmsUInt32Number count; * Description length
1003 // * cmsInt8Number desc[count] * NULL terminated ascii string
1004 // * cmsUInt32Number ucLangCode; * UniCode language code
1005 // * cmsUInt32Number ucCount; * UniCode description length
1006 // * cmsInt16Number ucDesc[ucCount];* The UniCode description
1007 // * cmsUInt16Number scCode; * ScriptCode code
1008 // * cmsUInt8Number scCount; * ScriptCode count
1009 // * cmsInt8Number scDesc[67]; * ScriptCode Description
1011 if (!_cmsWriteUInt32Number(io, len_text)) goto Error;
1012 if (!io ->Write(io, len_text, Text)) goto Error;
1014 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode
1016 if (!_cmsWriteUInt32Number(io, len_text)) goto Error;
1017 // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
1018 if (!_cmsWriteWCharArray(io, len_text, Wide)) 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;
1026 // possibly add pad at the end of tag
1027 if(len_aligned - len_tag_requirement > 0)
1028 if (!io ->Write(io, len_aligned - len_tag_requirement, Filler)) goto Error;
1033 if (Text) _cmsFree(self ->ContextID, Text);
1034 if (Wide) _cmsFree(self ->ContextID, Wide);
1038 cmsUNUSED_PARAMETER(nItems);
1043 void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1045 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1047 cmsUNUSED_PARAMETER(n);
1048 cmsUNUSED_PARAMETER(self);
1052 void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr)
1054 cmsMLU* mlu = (cmsMLU*) Ptr;
1059 cmsUNUSED_PARAMETER(self);
1064 cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data)
1066 if (ICCVersion >= 4.0)
1067 return cmsSigMultiLocalizedUnicodeType;
1069 return cmsSigTextDescriptionType;
1071 cmsUNUSED_PARAMETER(Data);
1075 // ********************************************************************************
1076 // Type cmsSigCurveType
1077 // ********************************************************************************
1080 void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1082 cmsUInt32Number Count;
1083 cmsToneCurve* NewGamma;
1086 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1092 cmsFloat64Number SingleGamma = 1.0;
1094 NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1095 if (!NewGamma) return NULL;
1100 case 1: // Specified as the exponent of gamma function
1102 cmsUInt16Number SingleGammaFixed;
1103 cmsFloat64Number SingleGamma;
1105 if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL;
1106 SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed);
1109 return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1115 return NULL; // This is to prevent bad guys for doing bad things
1117 NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
1118 if (!NewGamma) return NULL;
1120 if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL;
1126 cmsUNUSED_PARAMETER(SizeOfTag);
1131 cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1133 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1135 if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) {
1137 // Single gamma, preserve number
1138 cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]);
1140 if (!_cmsWriteUInt32Number(io, 1)) return FALSE;
1141 if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE;
1146 if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE;
1147 return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16);
1149 cmsUNUSED_PARAMETER(nItems);
1150 cmsUNUSED_PARAMETER(self);
1155 void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1157 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1159 cmsUNUSED_PARAMETER(n);
1160 cmsUNUSED_PARAMETER(self);
1164 void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1166 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1168 cmsFreeToneCurve(gamma);
1171 cmsUNUSED_PARAMETER(self);
1175 // ********************************************************************************
1176 // Type cmsSigParametricCurveType
1177 // ********************************************************************************
1180 // Decide which curve type to use on writting
1182 cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data)
1184 cmsToneCurve* Curve = (cmsToneCurve*) Data;
1186 if (ICCVersion < 4.0) return cmsSigCurveType;
1187 if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric
1188 if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves
1189 if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves
1191 return cmsSigParametricCurveType;
1195 void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1197 static const int ParamsByType[] = { 1, 3, 4, 5, 7 };
1198 cmsFloat64Number Params[10];
1199 cmsUInt16Number Type;
1201 cmsToneCurve* NewGamma;
1203 if (!_cmsReadUInt16Number(io, &Type)) return NULL;
1204 if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved
1208 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type);
1212 memset(Params, 0, sizeof(Params));
1213 n = ParamsByType[Type];
1215 for (i=0; i < n; i++) {
1217 if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL;
1220 NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params);
1225 cmsUNUSED_PARAMETER(SizeOfTag);
1230 cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1232 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1233 int i, nParams, typen;
1234 static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
1236 typen = Curve -> Segments[0].Type;
1238 if (Curve ->nSegments > 1 || typen < 1) {
1240 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written");
1245 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve");
1249 nParams = ParamsByType[typen];
1251 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE;
1252 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved
1254 for (i=0; i < nParams; i++) {
1256 if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE;
1261 cmsUNUSED_PARAMETER(nItems);
1265 void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1267 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1269 cmsUNUSED_PARAMETER(n);
1270 cmsUNUSED_PARAMETER(self);
1274 void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1276 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1278 cmsFreeToneCurve(gamma);
1281 cmsUNUSED_PARAMETER(self);
1285 // ********************************************************************************
1286 // Type cmsSigDateTimeType
1287 // ********************************************************************************
1289 // A 12-byte value representation of the time and date, where the byte usage is assigned
1290 // as specified in table 1. The actual values are encoded as 16-bit unsigned integers
1291 // (uInt16Number - see 5.1.6).
1293 // All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
1294 // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
1295 // time to UTC when setting these values. Programmes that display these values may show
1296 // the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
1297 // display both UTC and local versions of the dateTimeNumber.
1300 void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1302 cmsDateTimeNumber timestamp;
1303 struct tm * NewDateTime;
1306 NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm));
1307 if (NewDateTime == NULL) return NULL;
1309 if (io->Read(io, ×tamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL;
1311 _cmsDecodeDateTimeNumber(×tamp, NewDateTime);
1316 cmsUNUSED_PARAMETER(SizeOfTag);
1321 cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1323 struct tm * DateTime = (struct tm*) Ptr;
1324 cmsDateTimeNumber timestamp;
1326 _cmsEncodeDateTimeNumber(×tamp, DateTime);
1327 if (!io ->Write(io, sizeof(cmsDateTimeNumber), ×tamp)) return FALSE;
1331 cmsUNUSED_PARAMETER(nItems);
1332 cmsUNUSED_PARAMETER(self);
1336 void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1338 return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm));
1340 cmsUNUSED_PARAMETER(n);
1344 void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr)
1346 _cmsFree(self ->ContextID, Ptr);
1351 // ********************************************************************************
1352 // Type icMeasurementType
1353 // ********************************************************************************
1356 The measurementType information refers only to the internal profile data and is
1357 meant to provide profile makers an alternative to the default measurement
1362 void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1364 cmsICCMeasurementConditions mc;
1367 memset(&mc, 0, sizeof(mc));
1369 if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
1370 if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL;
1371 if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
1372 if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL;
1373 if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL;
1376 return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions));
1378 cmsUNUSED_PARAMETER(SizeOfTag);
1383 cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1385 cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr;
1387 if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE;
1388 if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE;
1389 if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE;
1390 if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE;
1391 if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE;
1395 cmsUNUSED_PARAMETER(nItems);
1396 cmsUNUSED_PARAMETER(self);
1400 void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1402 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions));
1404 cmsUNUSED_PARAMETER(n);
1408 void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr)
1410 _cmsFree(self ->ContextID, Ptr);
1414 // ********************************************************************************
1415 // Type cmsSigMultiLocalizedUnicodeType
1416 // ********************************************************************************
1418 // Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
1419 // Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
1420 // taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
1424 void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1427 cmsUInt32Number Count, RecLen, NumOfWchar;
1428 cmsUInt32Number SizeOfHeader;
1429 cmsUInt32Number Len, Offset;
1432 cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition;
1435 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1436 if (!_cmsReadUInt32Number(io, &RecLen)) return NULL;
1440 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "multiLocalizedUnicodeType of len != 12 is not supported.");
1444 mlu = cmsMLUalloc(self ->ContextID, Count);
1445 if (mlu == NULL) return NULL;
1447 mlu ->UsedEntries = Count;
1449 SizeOfHeader = 12 * Count + sizeof(_cmsTagBase);
1450 LargestPosition = 0;
1452 for (i=0; i < Count; i++) {
1454 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error;
1455 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error;
1457 // Now deal with Len and offset.
1458 if (!_cmsReadUInt32Number(io, &Len)) goto Error;
1459 if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
1461 // Check for overflow
1462 if (Offset < (SizeOfHeader + 8)) goto Error;
1464 // True begin of the string
1465 BeginOfThisString = Offset - SizeOfHeader - 8;
1467 // Ajust to wchar_t elements
1468 mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1469 mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1471 // To guess maximum size, add offset + len
1472 EndOfThisString = BeginOfThisString + Len;
1473 if (EndOfThisString > LargestPosition)
1474 LargestPosition = EndOfThisString;
1477 // Now read the remaining of tag and fill all strings. Substract the directory
1478 SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1487 Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
1488 if (Block == NULL) goto Error;
1489 NumOfWchar = SizeOfTag / sizeof(wchar_t);
1490 if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error;
1493 mlu ->MemPool = Block;
1494 mlu ->PoolSize = SizeOfTag;
1495 mlu ->PoolUsed = SizeOfTag;
1501 if (mlu) cmsMLUfree(mlu);
1506 cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1508 cmsMLU* mlu =(cmsMLU*) Ptr;
1509 cmsUInt32Number HeaderSize;
1510 cmsUInt32Number Len, Offset;
1515 // Empty placeholder
1516 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
1517 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1521 if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
1522 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1524 HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
1526 for (i=0; i < mlu ->UsedEntries; i++) {
1528 Len = mlu ->Entries[i].Len;
1529 Offset = mlu ->Entries[i].StrW;
1531 Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
1532 Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8;
1534 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE;
1535 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE;
1536 if (!_cmsWriteUInt32Number(io, Len)) return FALSE;
1537 if (!_cmsWriteUInt32Number(io, Offset)) return FALSE;
1540 if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE;
1544 cmsUNUSED_PARAMETER(nItems);
1545 cmsUNUSED_PARAMETER(self);
1550 void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1552 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1554 cmsUNUSED_PARAMETER(n);
1555 cmsUNUSED_PARAMETER(self);
1559 void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr)
1561 cmsMLUfree((cmsMLU*) Ptr);
1564 cmsUNUSED_PARAMETER(self);
1568 // ********************************************************************************
1569 // Type cmsSigLut8Type
1570 // ********************************************************************************
1572 // Decide which LUT type to use on writting
1574 cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data)
1576 cmsPipeline* Lut = (cmsPipeline*) Data;
1578 if (ICCVersion < 4.0) {
1579 if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1580 return cmsSigLut16Type;
1583 return cmsSigLutAtoBType;
1588 cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data)
1590 cmsPipeline* Lut = (cmsPipeline*) Data;
1592 if (ICCVersion < 4.0) {
1593 if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1594 return cmsSigLut16Type;
1597 return cmsSigLutBtoAType;
1602 This structure represents a colour transform using tables of 8-bit precision.
1603 This type contains four processing elements: a 3 by 3 matrix (which shall be
1604 the identity matrix unless the input colour space is XYZ), a set of one dimensional
1605 input tables, a multidimensional lookup table, and a set of one dimensional output
1606 tables. Data is processed using these elements via the following sequence:
1607 (matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables)
1609 Byte Position Field Length (bytes) Content Encoded as...
1610 8 1 Number of Input Channels (i) uInt8Number
1611 9 1 Number of Output Channels (o) uInt8Number
1612 10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number
1613 11 1 Reserved for padding (fill with 00h)
1615 12..15 4 Encoded e00 parameter s15Fixed16Number
1619 // Read 8 bit tables as gamma functions
1621 cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels)
1623 cmsUInt8Number* Temp = NULL;
1625 cmsToneCurve* Tables[cmsMAXCHANNELS];
1627 if (nChannels > cmsMAXCHANNELS) return FALSE;
1628 if (nChannels <= 0) return FALSE;
1630 memset(Tables, 0, sizeof(Tables));
1632 Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256);
1633 if (Temp == NULL) return FALSE;
1635 for (i=0; i < nChannels; i++) {
1636 Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
1637 if (Tables[i] == NULL) goto Error;
1640 for (i=0; i < nChannels; i++) {
1642 if (io ->Read(io, Temp, 256, 1) != 1) goto Error;
1644 for (j=0; j < 256; j++)
1645 Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]);
1648 _cmsFree(ContextID, Temp);
1651 if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
1654 for (i=0; i < nChannels; i++)
1655 cmsFreeToneCurve(Tables[i]);
1660 for (i=0; i < nChannels; i++) {
1661 if (Tables[i]) cmsFreeToneCurve(Tables[i]);
1664 if (Temp) _cmsFree(ContextID, Temp);
1670 cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables)
1676 for (i=0; i < n; i++) {
1680 // Usual case of identity curves
1681 if ((Tables ->TheCurves[i]->nEntries == 2) &&
1682 (Tables->TheCurves[i]->Table16[0] == 0) &&
1683 (Tables->TheCurves[i]->Table16[1] == 65535)) {
1685 for (j=0; j < 256; j++) {
1686 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE;
1690 if (Tables ->TheCurves[i]->nEntries != 256) {
1691 cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization");
1695 for (j=0; j < 256; j++) {
1697 val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]);
1699 if (!_cmsWriteUInt8Number(io, val)) return FALSE;
1709 cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
1711 cmsUInt32Number rv = 1, rc;
1713 if (a == 0) return 0;
1714 if (n == 0) return 0;
1716 for (; b > 0; b--) {
1720 // Check for overflow
1721 if (rv > UINT_MAX / a) return (cmsUInt32Number) -1;
1727 if (rv != rc / n) return (cmsUInt32Number) -1;
1732 // That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
1733 // 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust
1734 // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
1737 void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1739 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
1740 cmsUInt8Number* Temp = NULL;
1741 cmsPipeline* NewLUT = NULL;
1742 cmsUInt32Number nTabSize, i;
1743 cmsFloat64Number Matrix[3*3];
1747 if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error;
1748 if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error;
1749 if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error;
1751 if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
1754 if (!_cmsReadUInt8Number(io, NULL)) goto Error;
1757 if (InputChannels > cmsMAXCHANNELS) goto Error;
1758 if (OutputChannels > cmsMAXCHANNELS) goto Error;
1760 // Allocates an empty Pipeline
1761 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
1762 if (NewLUT == NULL) goto Error;
1765 if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
1766 if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
1767 if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
1768 if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
1769 if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
1770 if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
1771 if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
1772 if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
1773 if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
1776 // Only operates if not identity...
1777 if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
1779 if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
1784 if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error;
1786 // Get 3D CLUT. Check the overflow....
1787 nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
1788 if (nTabSize == (cmsUInt32Number) -1) goto Error;
1791 cmsUInt16Number *PtrW, *T;
1793 PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
1794 if (T == NULL) goto Error;
1796 Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize);
1798 _cmsFree(self ->ContextID, T);
1802 if (io ->Read(io, Temp, nTabSize, 1) != 1) {
1803 _cmsFree(self ->ContextID, T);
1804 _cmsFree(self ->ContextID, Temp);
1808 for (i = 0; i < nTabSize; i++) {
1810 *PtrW++ = FROM_8_TO_16(Temp[i]);
1812 _cmsFree(self ->ContextID, Temp);
1815 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T)))
1817 _cmsFree(self ->ContextID, T);
1821 // Get output tables
1822 if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error;
1828 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
1831 cmsUNUSED_PARAMETER(SizeOfTag);
1834 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1836 cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1838 cmsUInt32Number j, nTabSize;
1840 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
1842 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
1843 _cmsStageMatrixData* MatMPE = NULL;
1844 _cmsStageCLutData* clut = NULL;
1847 // Disassemble the LUT into components.
1848 mpe = NewLUT -> Elements;
1849 if (mpe ->Type == cmsSigMatrixElemType) {
1851 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
1855 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1856 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1860 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
1861 clut = (_cmsStageCLutData*) mpe -> Data;
1865 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1866 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1870 // That should be all
1872 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
1880 clutPoints = clut->Params->nSamples[0];
1882 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE;
1883 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE;
1884 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
1885 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
1888 if (MatMPE != NULL) {
1890 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
1891 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
1892 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
1893 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
1894 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
1895 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
1896 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
1897 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
1898 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
1903 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1904 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1905 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1906 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1907 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1908 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1909 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1910 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1911 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1914 // The prelinearization table
1915 if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
1917 nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
1918 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
1924 for (j=0; j < nTabSize; j++) {
1926 val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
1927 if (!_cmsWriteUInt8Number(io, val)) return FALSE;
1932 // The postlinearization table
1933 if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE;
1937 cmsUNUSED_PARAMETER(nItems);
1942 void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1944 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
1946 cmsUNUSED_PARAMETER(n);
1947 cmsUNUSED_PARAMETER(self);
1951 void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
1953 cmsPipelineFree((cmsPipeline*) Ptr);
1956 cmsUNUSED_PARAMETER(self);
1959 // ********************************************************************************
1960 // Type cmsSigLut16Type
1961 // ********************************************************************************
1963 // Read 16 bit tables as gamma functions
1965 cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries)
1968 cmsToneCurve* Tables[cmsMAXCHANNELS];
1970 // Maybe an empty table? (this is a lcms extension)
1971 if (nEntries <= 0) return TRUE;
1973 // Check for malicious profiles
1974 if (nEntries < 2) return FALSE;
1975 if (nChannels > cmsMAXCHANNELS) return FALSE;
1977 // Init table to zero
1978 memset(Tables, 0, sizeof(Tables));
1980 for (i=0; i < nChannels; i++) {
1982 Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL);
1983 if (Tables[i] == NULL) goto Error;
1985 if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error;
1989 // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code)
1990 if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
1993 for (i=0; i < nChannels; i++)
1994 cmsFreeToneCurve(Tables[i]);
1999 for (i=0; i < nChannels; i++) {
2000 if (Tables[i]) cmsFreeToneCurve(Tables[i]);
2007 cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables)
2011 cmsUInt16Number val;
2014 _cmsAssert(Tables != NULL);
2016 nEntries = Tables->TheCurves[0]->nEntries;
2018 for (i=0; i < Tables ->nCurves; i++) {
2020 for (j=0; j < nEntries; j++) {
2022 val = Tables->TheCurves[i]->Table16[j];
2023 if (!_cmsWriteUInt16Number(io, val)) return FALSE;
2028 cmsUNUSED_PARAMETER(ContextID);
2032 void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2034 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
2035 cmsPipeline* NewLUT = NULL;
2036 cmsUInt32Number nTabSize;
2037 cmsFloat64Number Matrix[3*3];
2038 cmsUInt16Number InputEntries, OutputEntries;
2042 if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL;
2043 if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL;
2044 if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum
2047 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2050 if (InputChannels > cmsMAXCHANNELS) goto Error;
2051 if (OutputChannels > cmsMAXCHANNELS) goto Error;
2053 // Allocates an empty LUT
2054 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
2055 if (NewLUT == NULL) goto Error;
2058 if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
2059 if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
2060 if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
2061 if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
2062 if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
2063 if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
2064 if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
2065 if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
2066 if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
2069 // Only operates on 3 channels
2070 if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
2072 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
2076 if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error;
2077 if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error;
2079 if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error;
2080 if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
2083 if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error;
2086 nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
2087 if (nTabSize == (cmsUInt32Number) -1) goto Error;
2092 T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
2093 if (T == NULL) goto Error;
2095 if (!_cmsReadUInt16Array(io, nTabSize, T)) {
2096 _cmsFree(self ->ContextID, T);
2100 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) {
2101 _cmsFree(self ->ContextID, T);
2104 _cmsFree(self ->ContextID, T);
2108 // Get output tables
2109 if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error;
2115 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
2118 cmsUNUSED_PARAMETER(SizeOfTag);
2121 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
2122 // Some empty defaults are created for missing parts
2125 cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2127 cmsUInt32Number nTabSize;
2128 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
2130 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
2131 _cmsStageMatrixData* MatMPE = NULL;
2132 _cmsStageCLutData* clut = NULL;
2133 int i, InputChannels, OutputChannels, clutPoints;
2135 // Disassemble the LUT into components.
2136 mpe = NewLUT -> Elements;
2137 if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
2139 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
2144 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2145 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2149 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
2150 clut = (_cmsStageCLutData*) mpe -> Data;
2154 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2155 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2159 // That should be all
2161 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
2165 InputChannels = cmsPipelineInputChannels(NewLUT);
2166 OutputChannels = cmsPipelineOutputChannels(NewLUT);
2171 clutPoints = clut->Params->nSamples[0];
2173 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE;
2174 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE;
2175 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
2176 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
2179 if (MatMPE != NULL) {
2181 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
2182 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
2183 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
2184 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
2185 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
2186 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
2187 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
2188 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
2189 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
2193 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2194 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2195 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2196 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2197 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2198 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2199 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2200 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2201 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2205 if (PreMPE != NULL) {
2206 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE;
2208 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
2211 if (PostMPE != NULL) {
2212 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE;
2214 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
2218 // The prelinearization table
2220 if (PreMPE != NULL) {
2221 if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE;
2224 for (i=0; i < InputChannels; i++) {
2226 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2227 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
2231 nTabSize = uipow(OutputChannels, clutPoints, InputChannels);
2232 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
2236 if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
2240 // The postlinearization table
2241 if (PostMPE != NULL) {
2242 if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE;
2245 for (i=0; i < OutputChannels; i++) {
2247 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2248 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
2254 cmsUNUSED_PARAMETER(nItems);
2258 void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2260 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2262 cmsUNUSED_PARAMETER(n);
2263 cmsUNUSED_PARAMETER(self);
2267 void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr)
2269 cmsPipelineFree((cmsPipeline*) Ptr);
2272 cmsUNUSED_PARAMETER(self);
2276 // ********************************************************************************
2277 // Type cmsSigLutAToBType
2278 // ********************************************************************************
2281 // V4 stuff. Read matrix for LutAtoB and LutBtoA
2284 cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset)
2286 cmsFloat64Number dMat[3*3];
2287 cmsFloat64Number dOff[3];
2291 if (!io -> Seek(io, Offset)) return NULL;
2294 if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL;
2295 if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL;
2296 if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL;
2297 if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL;
2298 if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL;
2299 if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL;
2300 if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL;
2301 if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL;
2302 if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL;
2304 if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL;
2305 if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL;
2306 if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL;
2308 Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff);
2316 // V4 stuff. Read CLUT part for LutAtoB and LutBtoA
2319 cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels)
2321 cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension.
2322 cmsUInt32Number GridPoints[cmsMAXCHANNELS], i;
2323 cmsUInt8Number Precision;
2325 _cmsStageCLutData* Data;
2327 if (!io -> Seek(io, Offset)) return NULL;
2328 if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL;
2331 for (i=0; i < cmsMAXCHANNELS; i++) {
2333 if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least
2334 GridPoints[i] = gridPoints8[i];
2337 if (!_cmsReadUInt8Number(io, &Precision)) return NULL;
2339 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2340 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2341 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2343 CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL);
2344 if (CLUT == NULL) return NULL;
2346 Data = (_cmsStageCLutData*) CLUT ->Data;
2348 // Precision can be 1 or 2 bytes
2349 if (Precision == 1) {
2353 for (i=0; i < Data ->nEntries; i++) {
2355 if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
2356 Data ->Tab.T[i] = FROM_8_TO_16(v);
2361 if (Precision == 2) {
2363 if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) {
2370 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
2378 cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
2380 cmsTagTypeSignature BaseType;
2381 cmsUInt32Number nItems;
2383 BaseType = _cmsReadTypeBase(io);
2386 case cmsSigCurveType:
2387 return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0);
2389 case cmsSigParametricCurveType:
2390 return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0);
2396 _cmsTagSignature2String(String, (cmsTagSignature) BaseType);
2397 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
2404 // Read a set of curves from specific offset
2406 cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves)
2408 cmsToneCurve* Curves[cmsMAXCHANNELS];
2410 cmsStage* Lin = NULL;
2412 if (nCurves > cmsMAXCHANNELS) return FALSE;
2414 if (!io -> Seek(io, Offset)) return FALSE;
2416 for (i=0; i < nCurves; i++)
2419 for (i=0; i < nCurves; i++) {
2421 Curves[i] = ReadEmbeddedCurve(self, io);
2422 if (Curves[i] == NULL) goto Error;
2423 if (!_cmsReadAlignment(io)) goto Error;
2427 Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves);
2430 for (i=0; i < nCurves; i++)
2431 cmsFreeToneCurve(Curves[i]);
2439 // This structure represents a colour transform. The type contains up to five processing
2440 // elements which are stored in the AtoBTag tag in the following order: a set of one
2441 // dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves,
2442 // a multidimensional lookup table, and a set of one dimensional output curves.
2443 // Data are processed using these elements via the following sequence:
2445 //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves).
2448 It is possible to use any or all of these processing elements. At least one processing element
2449 must be included.Only the following combinations are allowed:
2454 A - CLUT - M - Matrix - B
2459 void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2461 cmsUInt32Number BaseOffset;
2462 cmsUInt8Number inputChan; // Number of input channels
2463 cmsUInt8Number outputChan; // Number of output channels
2464 cmsUInt32Number offsetB; // Offset to first "B" curve
2465 cmsUInt32Number offsetMat; // Offset to matrix
2466 cmsUInt32Number offsetM; // Offset to first "M" curve
2467 cmsUInt32Number offsetC; // Offset to CLUT
2468 cmsUInt32Number offsetA; // Offset to first "A" curve
2469 cmsPipeline* NewLUT = NULL;
2472 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2474 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
2475 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
2477 if (!_cmsReadUInt16Number(io, NULL)) return NULL;
2479 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
2480 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
2481 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
2482 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
2483 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
2485 // Allocates an empty LUT
2486 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
2487 if (NewLUT == NULL) return NULL;
2490 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan)))
2495 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
2500 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan)))
2504 if (offsetMat != 0) {
2505 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
2510 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
2517 cmsPipelineFree(NewLUT);
2520 cmsUNUSED_PARAMETER(SizeOfTag);
2523 // Write a set of curves
2525 cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
2527 _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
2530 if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE;
2531 if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE;
2532 if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE;
2533 if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE;
2534 if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE;
2535 if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE;
2536 if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE;
2537 if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE;
2538 if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE;
2540 if (m ->Offset != NULL) {
2542 if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE;
2543 if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE;
2544 if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE;
2547 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2548 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2549 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2556 cmsUNUSED_PARAMETER(self);
2560 // Write a set of curves
2562 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
2564 cmsUInt32Number i, n;
2565 cmsTagTypeSignature CurrentType;
2566 cmsToneCurve** Curves;
2569 n = cmsStageOutputChannels(mpe);
2570 Curves = _cmsStageGetPtrToCurveSet(mpe);
2572 for (i=0; i < n; i++) {
2574 // If this is a table-based curve, use curve type even on V4
2577 if ((Curves[i] ->nSegments == 0)||
2578 ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) )
2579 CurrentType = cmsSigCurveType;
2581 if (Curves[i] ->Segments[0].Type < 0)
2582 CurrentType = cmsSigCurveType;
2584 if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE;
2586 switch (CurrentType) {
2588 case cmsSigCurveType:
2589 if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE;
2592 case cmsSigParametricCurveType:
2593 if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE;
2600 _cmsTagSignature2String(String, (cmsTagSignature) Type);
2601 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
2606 if (!_cmsWriteAlignment(io)) return FALSE;
2615 cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe)
2617 cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension.
2619 _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data;
2621 if (CLUT ->HasFloatValues) {
2622 cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only");
2626 memset(gridPoints, 0, sizeof(gridPoints));
2627 for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++)
2628 gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i];
2630 if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE;
2632 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE;
2633 if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2634 if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2635 if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2637 // Precision can be 1 or 2 bytes
2638 if (Precision == 1) {
2640 for (i=0; i < CLUT->nEntries; i++) {
2642 if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE;
2646 if (Precision == 2) {
2648 if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE;
2651 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
2655 if (!_cmsWriteAlignment(io)) return FALSE;
2664 cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2666 cmsPipeline* Lut = (cmsPipeline*) Ptr;
2667 int inputChan, outputChan;
2668 cmsStage *A = NULL, *B = NULL, *M = NULL;
2669 cmsStage * Matrix = NULL;
2670 cmsStage * CLUT = NULL;
2671 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2672 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2674 // Get the base for all offsets
2675 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2677 if (Lut ->Elements != NULL)
2678 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
2679 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B))
2680 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B))
2681 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType,
2682 cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) {
2684 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB");
2688 // Get input, output channels
2689 inputChan = cmsPipelineInputChannels(Lut);
2690 outputChan = cmsPipelineOutputChannels(Lut);
2692 // Write channel count
2693 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
2694 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
2695 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2697 // Keep directory to be filled latter
2698 DirectoryPos = io ->Tell(io);
2700 // Write the directory
2701 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2702 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2703 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2704 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2705 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2709 offsetA = io ->Tell(io) - BaseOffset;
2710 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
2714 offsetC = io ->Tell(io) - BaseOffset;
2715 if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
2720 offsetM = io ->Tell(io) - BaseOffset;
2721 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
2724 if (Matrix != NULL) {
2725 offsetMat = io ->Tell(io) - BaseOffset;
2726 if (!WriteMatrix(self, io, Matrix)) return FALSE;
2731 offsetB = io ->Tell(io) - BaseOffset;
2732 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2735 CurrentPos = io ->Tell(io);
2737 if (!io ->Seek(io, DirectoryPos)) return FALSE;
2739 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2740 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2741 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2742 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2743 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2745 if (!io ->Seek(io, CurrentPos)) return FALSE;
2749 cmsUNUSED_PARAMETER(nItems);
2754 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2756 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2758 cmsUNUSED_PARAMETER(n);
2759 cmsUNUSED_PARAMETER(self);
2763 void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr)
2765 cmsPipelineFree((cmsPipeline*) Ptr);
2768 cmsUNUSED_PARAMETER(self);
2775 void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2777 cmsUInt8Number inputChan; // Number of input channels
2778 cmsUInt8Number outputChan; // Number of output channels
2779 cmsUInt32Number BaseOffset; // Actual position in file
2780 cmsUInt32Number offsetB; // Offset to first "B" curve
2781 cmsUInt32Number offsetMat; // Offset to matrix
2782 cmsUInt32Number offsetM; // Offset to first "M" curve
2783 cmsUInt32Number offsetC; // Offset to CLUT
2784 cmsUInt32Number offsetA; // Offset to first "A" curve
2785 cmsPipeline* NewLUT = NULL;
2788 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2790 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
2791 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
2794 if (!_cmsReadUInt16Number(io, NULL)) return NULL;
2796 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
2797 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
2798 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
2799 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
2800 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
2802 // Allocates an empty LUT
2803 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
2804 if (NewLUT == NULL) return NULL;
2807 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan)))
2811 if (offsetMat != 0) {
2812 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
2817 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan)))
2822 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
2827 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan)))
2834 cmsPipelineFree(NewLUT);
2837 cmsUNUSED_PARAMETER(SizeOfTag);
2845 B - Matrix - M - CLUT - A
2849 cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2851 cmsPipeline* Lut = (cmsPipeline*) Ptr;
2852 int inputChan, outputChan;
2853 cmsStage *A = NULL, *B = NULL, *M = NULL;
2854 cmsStage *Matrix = NULL;
2855 cmsStage *CLUT = NULL;
2856 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2857 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2860 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2862 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
2863 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M))
2864 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A))
2865 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
2866 cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) {
2867 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA");
2871 inputChan = cmsPipelineInputChannels(Lut);
2872 outputChan = cmsPipelineOutputChannels(Lut);
2874 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
2875 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
2876 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2878 DirectoryPos = io ->Tell(io);
2880 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2881 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2882 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2883 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2884 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2888 offsetA = io ->Tell(io) - BaseOffset;
2889 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
2893 offsetC = io ->Tell(io) - BaseOffset;
2894 if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
2899 offsetM = io ->Tell(io) - BaseOffset;
2900 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
2903 if (Matrix != NULL) {
2904 offsetMat = io ->Tell(io) - BaseOffset;
2905 if (!WriteMatrix(self, io, Matrix)) return FALSE;
2910 offsetB = io ->Tell(io) - BaseOffset;
2911 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2914 CurrentPos = io ->Tell(io);
2916 if (!io ->Seek(io, DirectoryPos)) return FALSE;
2918 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2919 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2920 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2921 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2922 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2924 if (!io ->Seek(io, CurrentPos)) return FALSE;
2928 cmsUNUSED_PARAMETER(nItems);
2934 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2936 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2938 cmsUNUSED_PARAMETER(n);
2939 cmsUNUSED_PARAMETER(self);
2943 void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr)
2945 cmsPipelineFree((cmsPipeline*) Ptr);
2948 cmsUNUSED_PARAMETER(self);
2953 // ********************************************************************************
2954 // Type cmsSigColorantTableType
2955 // ********************************************************************************
2957 The purpose of this tag is to identify the colorants used in the profile by a
2958 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
2959 value. The first colorant listed is the colorant of the first device channel of
2960 a lut tag. The second colorant listed is the colorant of the second device channel
2961 of a lut tag, and so on.
2965 void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2967 cmsUInt32Number i, Count;
2968 cmsNAMEDCOLORLIST* List;
2970 cmsUInt16Number PCS[3];
2973 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
2975 if (Count > cmsMAXCHANNELS) {
2976 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count);
2980 List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", "");
2981 for (i=0; i < Count; i++) {
2983 if (io ->Read(io, Name, 32, 1) != 1) goto Error;
2986 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
2988 if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error;
2997 cmsFreeNamedColorList(List);
3000 cmsUNUSED_PARAMETER(SizeOfTag);
3005 // Saves a colorant table. It is using the named color structure for simplicity sake
3007 cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3009 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3012 nColors = cmsNamedColorCount(NamedColorList);
3014 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3016 for (i=0; i < nColors; i++) {
3019 cmsUInt16Number PCS[3];
3021 if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0;
3024 if (!io ->Write(io, 32, root)) return FALSE;
3025 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3030 cmsUNUSED_PARAMETER(nItems);
3031 cmsUNUSED_PARAMETER(self);
3036 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3038 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3039 return (void*) cmsDupNamedColorList(nc);
3041 cmsUNUSED_PARAMETER(n);
3042 cmsUNUSED_PARAMETER(self);
3047 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
3049 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3052 cmsUNUSED_PARAMETER(self);
3056 // ********************************************************************************
3057 // Type cmsSigNamedColor2Type
3058 // ********************************************************************************
3060 //The namedColor2Type is a count value and array of structures that provide color
3061 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3062 //device representation of the color are given. Both representations are 16-bit values.
3063 //The device representation corresponds to the header�s �color space of data� field.
3064 //This representation should be consistent with the �number of device components�
3065 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3066 //The PCS representation corresponds to the header�s PCS field. The PCS representation
3067 //is always provided. Color names are fixed-length, 32-byte fields including null
3068 //termination. In order to maintain maximum portability, it is strongly recommended
3069 //that special characters of the 7-bit ASCII set not be used.
3072 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3075 cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use
3076 cmsUInt32Number count; // Count of named colors
3077 cmsUInt32Number nDeviceCoords; // Num of device coordinates
3078 char prefix[32]; // Prefix for each color name
3079 char suffix[32]; // Suffix for each color name
3080 cmsNAMEDCOLORLIST* v;
3085 if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL;
3086 if (!_cmsReadUInt32Number(io, &count)) return NULL;
3087 if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL;
3089 if (io -> Read(io, prefix, 32, 1) != 1) return NULL;
3090 if (io -> Read(io, suffix, 32, 1) != 1) return NULL;
3092 prefix[31] = suffix[31] = 0;
3094 v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix);
3096 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count);
3100 if (nDeviceCoords > cmsMAXCHANNELS) {
3101 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
3104 for (i=0; i < count; i++) {
3106 cmsUInt16Number PCS[3];
3107 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3110 memset(Colorant, 0, sizeof(Colorant));
3111 if (io -> Read(io, Root, 32, 1) != 1) return NULL;
3112 Root[32] = 0; // To prevent exploits
3114 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3115 if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
3117 if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
3124 cmsFreeNamedColorList(v);
3127 cmsUNUSED_PARAMETER(SizeOfTag);
3131 // Saves a named color list into a named color profile
3133 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3135 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3136 char prefix[33]; // Prefix for each color name
3137 char suffix[33]; // Suffix for each color name
3140 nColors = cmsNamedColorCount(NamedColorList);
3142 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
3143 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3144 if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
3146 strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
3147 strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
3149 suffix[32] = prefix[32] = 0;
3151 if (!io ->Write(io, 32, prefix)) return FALSE;
3152 if (!io ->Write(io, 32, suffix)) return FALSE;
3154 for (i=0; i < nColors; i++) {
3156 cmsUInt16Number PCS[3];
3157 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3160 if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
3162 if (!io ->Write(io, 32 , Root)) return FALSE;
3163 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3164 if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
3169 cmsUNUSED_PARAMETER(nItems);
3170 cmsUNUSED_PARAMETER(self);
3174 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3176 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3178 return (void*) cmsDupNamedColorList(nc);
3180 cmsUNUSED_PARAMETER(n);
3181 cmsUNUSED_PARAMETER(self);
3186 void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr)
3188 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3191 cmsUNUSED_PARAMETER(self);
3195 // ********************************************************************************
3196 // Type cmsSigProfileSequenceDescType
3197 // ********************************************************************************
3199 // This type is an array of structures, each of which contains information from the
3200 // header fields and tags from the original profiles which were combined to create
3201 // the final profile. The order of the structures is the order in which the profiles
3202 // were combined and includes a structure for the final profile. This provides a
3203 // description of the profile sequence from source to destination,
3204 // typically used with the DeviceLink profile.
3207 cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag)
3209 cmsTagTypeSignature BaseType;
3210 cmsUInt32Number nItems;
3212 BaseType = _cmsReadTypeBase(io);
3216 case cmsSigTextType:
3217 if (*mlu) cmsMLUfree(*mlu);
3218 *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag);
3219 return (*mlu != NULL);
3221 case cmsSigTextDescriptionType:
3222 if (*mlu) cmsMLUfree(*mlu);
3223 *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag);
3224 return (*mlu != NULL);
3227 TBD: Size is needed for MLU, and we have no idea on which is the available size
3230 case cmsSigMultiLocalizedUnicodeType:
3231 if (*mlu) cmsMLUfree(*mlu);
3232 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag);
3233 return (*mlu != NULL);
3235 default: return FALSE;
3241 void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3244 cmsUInt32Number i, Count;
3248 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3250 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3251 SizeOfTag -= sizeof(cmsUInt32Number);
3254 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
3255 if (OutSeq == NULL) return NULL;
3259 // Get structures as well
3261 for (i=0; i < Count; i++) {
3263 cmsPSEQDESC* sec = &OutSeq -> seq[i];
3265 if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error;
3266 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
3267 SizeOfTag -= sizeof(cmsUInt32Number);
3269 if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error;
3270 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
3271 SizeOfTag -= sizeof(cmsUInt32Number);
3273 if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error;
3274 if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error;
3275 SizeOfTag -= sizeof(cmsUInt64Number);
3277 if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error;
3278 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
3279 SizeOfTag -= sizeof(cmsUInt32Number);
3281 if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error;
3282 if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error;
3289 cmsFreeProfileSequenceDescription(OutSeq);
3294 // Aux--Embed a text description type. It can be of type text description or multilocalized unicode
3295 // and it depends of the version number passed on cmsTagDescriptor structure instead of stack
3297 cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text)
3299 if (self ->ICCVersion < 0x4000000) {
3301 if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE;
3302 return Type_Text_Description_Write(self, io, Text, 1);
3305 if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE;
3306 return Type_MLU_Write(self, io, Text, 1);
3312 cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3314 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3317 if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE;
3319 for (i=0; i < Seq ->n; i++) {
3321 cmsPSEQDESC* sec = &Seq -> seq[i];
3323 if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE;
3324 if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE;
3325 if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE;
3326 if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE;
3328 if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE;
3329 if (!SaveDescription(self, io, sec ->Model)) return FALSE;
3334 cmsUNUSED_PARAMETER(nItems);
3339 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3341 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3343 cmsUNUSED_PARAMETER(n);
3344 cmsUNUSED_PARAMETER(self);
3348 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr)
3350 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3353 cmsUNUSED_PARAMETER(self);
3357 // ********************************************************************************
3358 // Type cmsSigProfileSequenceIdType
3359 // ********************************************************************************
3361 In certain workflows using ICC Device Link Profiles, it is necessary to identify the
3362 original profiles that were combined to create the Device Link Profile.
3363 This type is an array of structures, each of which contains information for
3364 identification of a profile used in a sequence
3369 cmsBool ReadSeqID(struct _cms_typehandler_struct* self,
3373 cmsUInt32Number SizeOfTag)
3375 cmsSEQ* OutSeq = (cmsSEQ*) Cargo;
3376 cmsPSEQDESC* seq = &OutSeq ->seq[n];
3378 if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE;
3379 if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE;
3387 void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3390 cmsUInt32Number Count;
3391 cmsUInt32Number BaseOffset;
3395 // Get actual position as a basis for element offsets
3396 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3399 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3400 SizeOfTag -= sizeof(cmsUInt32Number);
3402 // Allocate an empty structure
3403 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
3404 if (OutSeq == NULL) return NULL;
3407 // Read the position table
3408 if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) {
3410 cmsFreeProfileSequenceDescription(OutSeq);
3422 cmsBool WriteSeqID(struct _cms_typehandler_struct* self,
3426 cmsUInt32Number SizeOfTag)
3428 cmsSEQ* Seq = (cmsSEQ*) Cargo;
3430 if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE;
3432 // Store here the MLU
3433 if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE;
3437 cmsUNUSED_PARAMETER(SizeOfTag);
3441 cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3443 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3444 cmsUInt32Number BaseOffset;
3446 // Keep the base offset
3447 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3449 // This is the table count
3450 if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE;
3452 // This is the position table and content
3453 if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE;
3457 cmsUNUSED_PARAMETER(nItems);
3461 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3463 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3465 cmsUNUSED_PARAMETER(n);
3466 cmsUNUSED_PARAMETER(self);
3470 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr)
3472 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3475 cmsUNUSED_PARAMETER(self);
3479 // ********************************************************************************
3480 // Type cmsSigUcrBgType
3481 // ********************************************************************************
3483 This type contains curves representing the under color removal and black
3484 generation and a text string which is a general description of the method used
3489 void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3491 cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3492 cmsUInt32Number CountUcr, CountBg;
3496 if (n == NULL) return NULL;
3498 // First curve is Under color removal
3499 if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
3500 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3501 SizeOfTag -= sizeof(cmsUInt32Number);
3503 n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
3504 if (n ->Ucr == NULL) return NULL;
3506 if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
3507 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3508 SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
3510 // Second curve is Black generation
3511 if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
3512 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3513 SizeOfTag -= sizeof(cmsUInt32Number);
3515 n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
3516 if (n ->Bg == NULL) return NULL;
3517 if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
3518 if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL;
3519 SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
3520 if (SizeOfTag == UINT_MAX) return NULL;
3522 // Now comes the text. The length is specified by the tag size
3523 n ->Desc = cmsMLUalloc(self ->ContextID, 1);
3524 if (n ->Desc == NULL) return NULL;
3526 ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
3527 if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
3528 ASCIIString[SizeOfTag] = 0;
3529 cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
3530 _cmsFree(self ->ContextID, ASCIIString);
3537 cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3539 cmsUcrBg* Value = (cmsUcrBg*) Ptr;
3540 cmsUInt32Number TextSize;
3543 // First curve is Under color removal
3544 if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE;
3545 if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE;
3547 // Then black generation
3548 if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE;
3549 if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE;
3551 // Now comes the text. The length is specified by the tag size
3552 TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0);
3553 Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
3554 if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE;
3556 if (!io ->Write(io, TextSize, Text)) return FALSE;
3557 _cmsFree(self ->ContextID, Text);
3561 cmsUNUSED_PARAMETER(nItems);
3565 void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3567 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3568 cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3570 if (NewUcrBg == NULL) return NULL;
3572 NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg);
3573 NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr);
3574 NewUcrBg ->Desc = cmsMLUdup(Src ->Desc);
3576 return (void*) NewUcrBg;
3578 cmsUNUSED_PARAMETER(n);
3582 void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr)
3584 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3586 if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr);
3587 if (Src ->Bg) cmsFreeToneCurve(Src ->Bg);
3588 if (Src ->Desc) cmsMLUfree(Src ->Desc);
3590 _cmsFree(self ->ContextID, Ptr);
3593 // ********************************************************************************
3594 // Type cmsSigCrdInfoType
3595 // ********************************************************************************
3598 This type contains the PostScript product name to which this profile corresponds
3599 and the names of the companion CRDs. Recall that a single profile can generate
3600 multiple CRDs. It is implemented as a MLU being the language code "PS" and then
3601 country varies for each element:
3603 nm: PostScript product name
3604 #0: Rendering intent 0 CRD name
3605 #1: Rendering intent 1 CRD name
3606 #2: Rendering intent 2 CRD name
3607 #3: Rendering intent 3 CRD name
3612 // Auxiliar, read an string specified as count + string
3614 cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
3616 cmsUInt32Number Count;
3619 if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE;
3621 if (!_cmsReadUInt32Number(io, &Count)) return FALSE;
3623 if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE;
3624 if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE;
3626 Text = (char*) _cmsMalloc(self ->ContextID, Count+1);
3627 if (Text == NULL) return FALSE;
3629 if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) {
3630 _cmsFree(self ->ContextID, Text);
3636 cmsMLUsetASCII(mlu, "PS", Section, Text);
3637 _cmsFree(self ->ContextID, Text);
3639 *SizeOfTag -= (Count + sizeof(cmsUInt32Number));
3644 cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section)
3646 cmsUInt32Number TextSize;
3649 TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0);
3650 Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
3652 if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE;
3654 if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE;
3656 if (!io ->Write(io, TextSize, Text)) return FALSE;
3657 _cmsFree(self ->ContextID, Text);
3663 void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3665 cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5);
3668 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error;
3669 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error;
3670 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error;
3671 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error;
3672 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error;
3684 cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3687 cmsMLU* mlu = (cmsMLU*) Ptr;
3689 if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error;
3690 if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error;
3691 if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error;
3692 if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error;
3693 if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error;
3700 cmsUNUSED_PARAMETER(nItems);
3705 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3707 return (void*) cmsMLUdup((cmsMLU*) Ptr);
3709 cmsUNUSED_PARAMETER(n);
3710 cmsUNUSED_PARAMETER(self);
3714 void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr)
3716 cmsMLUfree((cmsMLU*) Ptr);
3719 cmsUNUSED_PARAMETER(self);
3722 // ********************************************************************************
3723 // Type cmsSigScreeningType
3724 // ********************************************************************************
3726 //The screeningType describes various screening parameters including screen
3727 //frequency, screening angle, and spot shape.
3730 void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3732 cmsScreening* sc = NULL;
3735 sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening));
3736 if (sc == NULL) return NULL;
3740 if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error;
3741 if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error;
3743 if (sc ->nChannels > cmsMAXCHANNELS - 1)
3744 sc ->nChannels = cmsMAXCHANNELS - 1;
3746 for (i=0; i < sc ->nChannels; i++) {
3748 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error;
3749 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error;
3750 if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error;
3760 _cmsFree(self ->ContextID, sc);
3764 cmsUNUSED_PARAMETER(SizeOfTag);
3769 cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3771 cmsScreening* sc = (cmsScreening* ) Ptr;
3774 if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE;
3775 if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE;
3777 for (i=0; i < sc ->nChannels; i++) {
3779 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE;
3780 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE;
3781 if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE;
3786 cmsUNUSED_PARAMETER(nItems);
3787 cmsUNUSED_PARAMETER(self);
3792 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3794 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3796 cmsUNUSED_PARAMETER(n);
3801 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
3803 _cmsFree(self ->ContextID, Ptr);
3806 // ********************************************************************************
3807 // Type cmsSigViewingConditionsType
3808 // ********************************************************************************
3810 //This type represents a set of viewing condition parameters including:
3811 //CIE �absolute� illuminant white point tristimulus values and CIE �absolute�
3812 //surround tristimulus values.
3815 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3817 cmsICCViewingConditions* vc = NULL;
3819 vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
3820 if (vc == NULL) return NULL;
3824 if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
3825 if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
3826 if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
3834 _cmsFree(self ->ContextID, vc);
3838 cmsUNUSED_PARAMETER(SizeOfTag);
3843 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3845 cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
3847 if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
3848 if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
3849 if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
3853 cmsUNUSED_PARAMETER(nItems);
3854 cmsUNUSED_PARAMETER(self);
3859 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3861 return _cmsDupMem(self->ContextID, Ptr, sizeof(cmsICCViewingConditions));
3863 cmsUNUSED_PARAMETER(n);
3868 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
3870 _cmsFree(self ->ContextID, Ptr);
3874 // ********************************************************************************
3875 // Type cmsSigMultiProcessElementType
3876 // ********************************************************************************
3880 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3882 return (void*) cmsStageDup((cmsStage*) Ptr);
3884 cmsUNUSED_PARAMETER(n);
3885 cmsUNUSED_PARAMETER(self);
3889 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
3891 cmsStageFree((cmsStage*) Ptr);
3894 cmsUNUSED_PARAMETER(self);
3897 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
3898 // The first curve segment always starts at �Infinity, and the last curve segment always ends at +Infinity. The
3899 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
3900 // specified either in terms of a formula, or by a sampled curve.
3903 // Read an embedded segmented curve
3905 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
3907 cmsCurveSegSignature ElementSig;
3908 cmsUInt32Number i, j;
3909 cmsUInt16Number nSegments;
3910 cmsCurveSegment* Segments;
3911 cmsToneCurve* Curve;
3912 cmsFloat32Number PrevBreak = -1E22F; // - infinite
3914 // Take signature and channels for each element.
3915 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL;
3917 // That should be a segmented curve
3918 if (ElementSig != cmsSigSegmentedCurve) return NULL;
3920 if (!_cmsReadUInt32Number(io, NULL)) return NULL;
3921 if (!_cmsReadUInt16Number(io, &nSegments)) return NULL;
3922 if (!_cmsReadUInt16Number(io, NULL)) return NULL;
3924 if (nSegments < 1) return NULL;
3925 Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment));
3926 if (Segments == NULL) return NULL;
3929 for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) {
3931 Segments[i].x0 = PrevBreak;
3932 if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error;
3933 PrevBreak = Segments[i].x1;
3936 Segments[nSegments-1].x0 = PrevBreak;
3937 Segments[nSegments-1].x1 = 1E22F; // A big cmsFloat32Number number
3940 for (i=0; i < nSegments; i++) {
3942 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error;
3943 if (!_cmsReadUInt32Number(io, NULL)) goto Error;
3945 switch (ElementSig) {
3947 case cmsSigFormulaCurveSeg: {
3949 cmsUInt16Number Type;
3950 cmsUInt32Number ParamsByType[] = {4, 5, 5 };
3952 if (!_cmsReadUInt16Number(io, &Type)) goto Error;
3953 if (!_cmsReadUInt16Number(io, NULL)) goto Error;
3955 Segments[i].Type = Type + 6;
3956 if (Type > 2) goto Error;
3958 for (j=0; j < ParamsByType[Type]; j++) {
3961 if (!_cmsReadFloat32Number(io, &f)) goto Error;
3962 Segments[i].Params[j] = f;
3968 case cmsSigSampledCurveSeg: {
3969 cmsUInt32Number Count;
3971 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3973 Segments[i].nGridPoints = Count;
3974 Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number));
3975 if (Segments[i].SampledPoints == NULL) goto Error;
3977 for (j=0; j < Count; j++) {
3978 if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
3987 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
3988 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String);
3995 Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments);
3997 for (i=0; i < nSegments; i++) {
3998 if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
4000 _cmsFree(self ->ContextID, Segments);
4004 if (Segments) _cmsFree(self ->ContextID, Segments);
4010 cmsBool ReadMPECurve(struct _cms_typehandler_struct* self,
4014 cmsUInt32Number SizeOfTag)
4016 cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo;
4018 GammaTables[n] = ReadSegmentedCurve(self, io);
4019 return (GammaTables[n] != NULL);
4021 cmsUNUSED_PARAMETER(SizeOfTag);
4025 void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4027 cmsStage* mpe = NULL;
4028 cmsUInt16Number InputChans, OutputChans;
4029 cmsUInt32Number i, BaseOffset;
4030 cmsToneCurve** GammaTables;
4034 // Get actual position as a basis for element offsets
4035 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4037 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4038 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4040 if (InputChans != OutputChans) return NULL;
4042 GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*));
4043 if (GammaTables == NULL) return NULL;
4045 if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) {
4047 mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables);
4053 for (i=0; i < InputChans; i++) {
4054 if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]);
4057 _cmsFree(self ->ContextID, GammaTables);
4058 *nItems = (mpe != NULL) ? 1 : 0;
4061 cmsUNUSED_PARAMETER(SizeOfTag);
4065 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
4067 cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g)
4069 cmsUInt32Number i, j;
4070 cmsCurveSegment* Segments = g ->Segments;
4071 cmsUInt32Number nSegments = g ->nSegments;
4073 if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error;
4074 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4075 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error;
4076 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4078 // Write the break-points
4079 for (i=0; i < nSegments - 1; i++) {
4080 if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error;
4083 // Write the segments
4084 for (i=0; i < g ->nSegments; i++) {
4086 cmsCurveSegment* ActualSeg = Segments + i;
4088 if (ActualSeg -> Type == 0) {
4090 // This is a sampled curve
4091 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error;
4092 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4093 if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error;
4095 for (j=0; j < g ->Segments[i].nGridPoints; j++) {
4096 if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error;
4102 cmsUInt32Number ParamsByType[] = { 4, 5, 5 };
4104 // This is a formula-based
4105 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error;
4106 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4108 // We only allow 1, 2 and 3 as types
4109 Type = ActualSeg ->Type - 6;
4110 if (Type > 2 || Type < 0) goto Error;
4112 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error;
4113 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4115 for (j=0; j < ParamsByType[Type]; j++) {
4116 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error;
4120 // It seems there is no need to align. Code is here, and for safety commented out
4121 // if (!_cmsWriteAlignment(io)) goto Error;
4132 cmsBool WriteMPECurve(struct _cms_typehandler_struct* self,
4136 cmsUInt32Number SizeOfTag)
4138 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo;
4140 return WriteSegmentedCurve(io, Curves ->TheCurves[n]);
4142 cmsUNUSED_PARAMETER(SizeOfTag);
4143 cmsUNUSED_PARAMETER(self);
4146 // Write a curve, checking first for validity
4148 cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4150 cmsUInt32Number BaseOffset;
4151 cmsStage* mpe = (cmsStage*) Ptr;
4152 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data;
4154 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4156 // Write the header. Since those are curves, input and output channels are same
4157 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4158 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4160 if (!WritePositionTable(self, io, 0,
4161 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
4166 cmsUNUSED_PARAMETER(nItems);
4171 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4172 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4173 // is organized as follows:
4174 // array = [e11, e12, �, e1P, e21, e22, �, e2P, �, eQ1, eQ2, �, eQP, e1, e2, �, eQ]
4177 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4180 cmsUInt16Number InputChans, OutputChans;
4181 cmsUInt32Number nElems, i;
4182 cmsFloat64Number* Matrix;
4183 cmsFloat64Number* Offsets;
4185 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4186 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4189 nElems = InputChans * OutputChans;
4191 // Input and output chans may be ANY (up to 0xffff)
4192 Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number));
4193 if (Matrix == NULL) return NULL;
4195 Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number));
4196 if (Offsets == NULL) {
4198 _cmsFree(self ->ContextID, Matrix);
4202 for (i=0; i < nElems; i++) {
4206 if (!_cmsReadFloat32Number(io, &v)) return NULL;
4211 for (i=0; i < OutputChans; i++) {
4215 if (!_cmsReadFloat32Number(io, &v)) return NULL;
4220 mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets);
4221 _cmsFree(self ->ContextID, Matrix);
4222 _cmsFree(self ->ContextID, Offsets);
4228 cmsUNUSED_PARAMETER(SizeOfTag);
4232 cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4234 cmsUInt32Number i, nElems;
4235 cmsStage* mpe = (cmsStage*) Ptr;
4236 _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data;
4238 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4239 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4241 nElems = mpe ->InputChannels * mpe ->OutputChannels;
4243 for (i=0; i < nElems; i++) {
4244 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE;
4248 for (i=0; i < mpe ->OutputChannels; i++) {
4250 if (Matrix ->Offset == NULL) {
4252 if (!_cmsWriteFloat32Number(io, 0)) return FALSE;
4255 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE;
4261 cmsUNUSED_PARAMETER(nItems);
4262 cmsUNUSED_PARAMETER(self);
4268 void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4270 cmsStage* mpe = NULL;
4271 cmsUInt16Number InputChans, OutputChans;
4272 cmsUInt8Number Dimensions8[16];
4273 cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS];
4274 _cmsStageCLutData* clut;
4276 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4277 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4279 if (InputChans == 0) goto Error;
4280 if (OutputChans == 0) goto Error;
4282 if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
4285 // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
4286 nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans;
4287 for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i];
4289 // Allocate the true CLUT
4290 mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
4291 if (mpe == NULL) goto Error;
4294 clut = (_cmsStageCLutData*) mpe ->Data;
4295 for (i=0; i < clut ->nEntries; i++) {
4297 if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
4305 if (mpe != NULL) cmsStageFree(mpe);
4308 cmsUNUSED_PARAMETER(SizeOfTag);
4311 // Write a CLUT in floating point
4313 cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4315 cmsUInt8Number Dimensions8[16];
4317 cmsStage* mpe = (cmsStage*) Ptr;
4318 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
4320 // Check for maximum number of channels
4321 if (mpe -> InputChannels > 15) return FALSE;
4323 // Only floats are supported in MPE
4324 if (clut ->HasFloatValues == FALSE) return FALSE;
4326 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4327 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4329 memset(Dimensions8, 0, sizeof(Dimensions8));
4331 for (i=0; i < mpe ->InputChannels; i++)
4332 Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
4334 if (!io ->Write(io, 16, Dimensions8)) return FALSE;
4336 for (i=0; i < clut ->nEntries; i++) {
4338 if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
4343 cmsUNUSED_PARAMETER(nItems);
4344 cmsUNUSED_PARAMETER(self);
4349 // This is the list of built-in MPE types
4350 static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
4352 {{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now
4353 {{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says)
4355 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] },
4356 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] },
4357 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL },
4360 _cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL };
4363 cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
4367 cmsUInt32Number SizeOfTag)
4369 cmsStageSignature ElementSig;
4370 cmsTagTypeHandler* TypeHandler;
4371 cmsUInt32Number nItems;
4372 cmsPipeline *NewLUT = (cmsPipeline *) Cargo;
4373 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
4376 // Take signature and channels for each element.
4377 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE;
4379 // The reserved placeholder
4380 if (!_cmsReadUInt32Number(io, NULL)) return FALSE;
4382 // Read diverse MPE types
4383 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes);
4384 if (TypeHandler == NULL) {
4388 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4390 // An unknown element was found.
4391 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String);
4395 // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
4396 // Read the MPE. No size is given
4397 if (TypeHandler ->ReadPtr != NULL) {
4399 // This is a real element which should be read and processed
4400 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag)))
4406 cmsUNUSED_PARAMETER(SizeOfTag);
4407 cmsUNUSED_PARAMETER(n);
4411 // This is the main dispatcher for MPE
4413 void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4415 cmsUInt16Number InputChans, OutputChans;
4416 cmsUInt32Number ElementCount;
4417 cmsPipeline *NewLUT = NULL;
4418 cmsUInt32Number BaseOffset;
4420 // Get actual position as a basis for element offsets
4421 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4423 // Read channels and element count
4424 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4425 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4427 // Allocates an empty LUT
4428 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
4429 if (NewLUT == NULL) return NULL;
4431 if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL;
4433 if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) {
4434 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
4443 cmsUNUSED_PARAMETER(SizeOfTag);
4448 // This one is a liitle bit more complex, so we don't use position tables this time.
4450 cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4452 cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos;
4453 int inputChan, outputChan;
4454 cmsUInt32Number ElemCount;
4455 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before;
4456 cmsStageSignature ElementSig;
4457 cmsPipeline* Lut = (cmsPipeline*) Ptr;
4458 cmsStage* Elem = Lut ->Elements;
4459 cmsTagTypeHandler* TypeHandler;
4460 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
4462 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4464 inputChan = cmsPipelineInputChannels(Lut);
4465 outputChan = cmsPipelineOutputChannels(Lut);
4466 ElemCount = cmsPipelineStageCount(Lut);
4468 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
4469 if (ElementOffsets == NULL) goto Error;
4471 ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
4472 if (ElementSizes == NULL) goto Error;
4475 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error;
4476 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error;
4477 if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error;
4479 DirectoryPos = io ->Tell(io);
4481 // Write a fake directory to be filled latter on
4482 for (i=0; i < ElemCount; i++) {
4483 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
4484 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
4487 // Write each single tag. Keep track of the size as well.
4488 for (i=0; i < ElemCount; i++) {
4490 ElementOffsets[i] = io ->Tell(io) - BaseOffset;
4492 ElementSig = Elem ->Type;
4494 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes);
4495 if (TypeHandler == NULL) {
4499 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4501 // An unknow element was found.
4502 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String);
4506 if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error;
4507 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4508 Before = io ->Tell(io);
4509 if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error;
4510 if (!_cmsWriteAlignment(io)) goto Error;
4512 ElementSizes[i] = io ->Tell(io) - Before;
4517 // Write the directory
4518 CurrentPos = io ->Tell(io);
4520 if (!io ->Seek(io, DirectoryPos)) goto Error;
4522 for (i=0; i < ElemCount; i++) {
4523 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
4524 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
4527 if (!io ->Seek(io, CurrentPos)) goto Error;
4529 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4530 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4534 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4535 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4538 cmsUNUSED_PARAMETER(nItems);
4543 void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4545 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
4547 cmsUNUSED_PARAMETER(n);
4548 cmsUNUSED_PARAMETER(self);
4552 void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr)
4554 cmsPipelineFree((cmsPipeline*) Ptr);
4557 cmsUNUSED_PARAMETER(self);
4561 // ********************************************************************************
4562 // Type cmsSigVcgtType
4563 // ********************************************************************************
4566 #define cmsVideoCardGammaTableType 0
4567 #define cmsVideoCardGammaFormulaType 1
4578 void *Type_vcgt_Read(struct _cms_typehandler_struct* self,
4580 cmsUInt32Number* nItems,
4581 cmsUInt32Number SizeOfTag)
4583 cmsUInt32Number TagType, n, i;
4584 cmsToneCurve** Curves;
4589 if (!_cmsReadUInt32Number(io, &TagType)) return NULL;
4591 // Allocate space for the array
4592 Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4593 if (Curves == NULL) return NULL;
4595 // There are two possible flavors
4598 // Gamma is stored as a table
4599 case cmsVideoCardGammaTableType:
4601 cmsUInt16Number nChannels, nElems, nBytes;
4603 // Check channel count, which should be 3 (we don't support monochrome this time)
4604 if (!_cmsReadUInt16Number(io, &nChannels)) goto Error;
4606 if (nChannels != 3) {
4607 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels);
4611 // Get Table element count and bytes per element
4612 if (!_cmsReadUInt16Number(io, &nElems)) goto Error;
4613 if (!_cmsReadUInt16Number(io, &nBytes)) goto Error;
4615 // Adobe's quirk fixup. Fixing broken profiles...
4616 if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576)
4620 // Populate tone curves
4621 for (n=0; n < 3; n++) {
4623 Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL);
4624 if (Curves[n] == NULL) goto Error;
4626 // On depending on byte depth
4631 for (i=0; i < nElems; i++) {
4635 if (!_cmsReadUInt8Number(io, &v)) goto Error;
4636 Curves[n] ->Table16[i] = FROM_8_TO_16(v);
4640 // One word 0..65535
4642 if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error;
4647 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8);
4650 } // For all 3 channels
4654 // In this case, gamma is stored as a formula
4655 case cmsVideoCardGammaFormulaType:
4657 _cmsVCGTGAMMA Colorant[3];
4659 // Populate tone curves
4660 for (n=0; n < 3; n++) {
4664 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error;
4665 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error;
4666 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error;
4668 // Parametric curve type 5 is:
4669 // Y = (aX + b)^Gamma + e | X >= d
4670 // Y = cX + f | X < d
4673 // Y = (Max � Min) * (X ^ Gamma) + Min
4675 // So, the translation is
4676 // a = (Max � Min) ^ ( 1 / Gamma)
4680 Params[0] = Colorant[n].Gamma;
4681 Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma));
4685 Params[5] = Colorant[n].Min;
4688 Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
4689 if (Curves[n] == NULL) goto Error;
4696 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
4701 return (void*) Curves;
4703 // Regret, free all resources
4706 cmsFreeToneCurveTriple(Curves);
4707 _cmsFree(self ->ContextID, Curves);
4710 cmsUNUSED_PARAMETER(SizeOfTag);
4714 // We don't support all flavors, only 16bits tables and formula
4716 cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4718 cmsToneCurve** Curves = (cmsToneCurve**) Ptr;
4719 cmsUInt32Number i, j;
4721 if (cmsGetToneCurveParametricType(Curves[0]) == 5 &&
4722 cmsGetToneCurveParametricType(Curves[1]) == 5 &&
4723 cmsGetToneCurveParametricType(Curves[2]) == 5) {
4725 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
4728 for (i=0; i < 3; i++) {
4732 v.Gamma = Curves[i] ->Segments[0].Params[0];
4733 v.Min = Curves[i] ->Segments[0].Params[5];
4734 v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min;
4736 if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE;
4737 if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE;
4738 if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE;
4744 // Always store as a table of 256 words
4745 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE;
4746 if (!_cmsWriteUInt16Number(io, 3)) return FALSE;
4747 if (!_cmsWriteUInt16Number(io, 256)) return FALSE;
4748 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
4750 for (i=0; i < 3; i++) {
4751 for (j=0; j < 256; j++) {
4753 cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0));
4754 cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0);
4756 if (!_cmsWriteUInt16Number(io, n)) return FALSE;
4763 cmsUNUSED_PARAMETER(self);
4764 cmsUNUSED_PARAMETER(nItems);
4768 void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4770 cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr;
4771 cmsToneCurve** NewCurves;
4773 NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4774 if (NewCurves == NULL) return NULL;
4776 NewCurves[0] = cmsDupToneCurve(OldCurves[0]);
4777 NewCurves[1] = cmsDupToneCurve(OldCurves[1]);
4778 NewCurves[2] = cmsDupToneCurve(OldCurves[2]);
4780 return (void*) NewCurves;
4782 cmsUNUSED_PARAMETER(n);
4787 void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr)
4789 cmsFreeToneCurveTriple((cmsToneCurve**) Ptr);
4790 _cmsFree(self ->ContextID, Ptr);
4794 // ********************************************************************************
4795 // Type cmsSigDictType
4796 // ********************************************************************************
4798 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data
4800 cmsContext ContextID;
4801 cmsUInt32Number *Offsets;
4802 cmsUInt32Number *Sizes;
4806 _cmsDICelem Name, Value, DisplayName, DisplayValue;
4810 // Allocate an empty array element
4812 cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count)
4814 e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
4815 if (e->Offsets == NULL) return FALSE;
4817 e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
4818 if (e->Sizes == NULL) {
4820 _cmsFree(ContextID, e -> Offsets);
4824 e ->ContextID = ContextID;
4828 // Free an array element
4830 void FreeElem(_cmsDICelem* e)
4832 if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets);
4833 if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes);
4834 e->Offsets = e ->Sizes = NULL;
4837 // Get rid of whole array
4839 void FreeArray( _cmsDICarray* a)
4841 if (a ->Name.Offsets != NULL) FreeElem(&a->Name);
4842 if (a ->Value.Offsets != NULL) FreeElem(&a ->Value);
4843 if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName);
4844 if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue);
4848 // Allocate whole array
4850 cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
4853 memset(a, 0, sizeof(_cmsDICarray));
4855 // On depending on record size, create column arrays
4856 if (!AllocElem(ContextID, &a ->Name, Count)) goto Error;
4857 if (!AllocElem(ContextID, &a ->Value, Count)) goto Error;
4860 if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error;
4864 if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error;
4875 cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset)
4877 if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE;
4878 if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE;
4880 // An offset of zero has special meaning and shal be preserved
4881 if (e ->Offsets[i] > 0)
4882 e ->Offsets[i] += BaseOffset;
4888 cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset)
4892 // Read column arrays
4893 for (i=0; i < Count; i++) {
4895 if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE;
4896 if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE;
4900 if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE;
4906 if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE;
4913 // Write one element
4915 cmsBool WriteOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i)
4917 if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE;
4918 if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE;
4924 cmsBool WriteOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
4928 for (i=0; i < Count; i++) {
4930 if (!WriteOneElem(io, &a -> Name, i)) return FALSE;
4931 if (!WriteOneElem(io, &a -> Value, i)) return FALSE;
4935 if (!WriteOneElem(io, &a -> DisplayName, i)) return FALSE;
4940 if (!WriteOneElem(io, &a -> DisplayValue, i)) return FALSE;
4948 cmsBool ReadOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr)
4951 cmsUInt32Number nChars;
4953 // Special case for undefined strings (see ICC Votable
4954 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
4955 if (e -> Offsets[i] == 0) {
4961 if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
4963 nChars = e ->Sizes[i] / sizeof(cmsUInt16Number);
4966 *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t));
4967 if (*wcstr == NULL) return FALSE;
4969 if (!_cmsReadWCharArray(io, nChars, *wcstr)) {
4970 _cmsFree(e ->ContextID, *wcstr);
4974 // End of string marker
4975 (*wcstr)[nChars] = 0;
4980 cmsUInt32Number mywcslen(const wchar_t *s)
4988 return (cmsUInt32Number)(p - s);
4992 cmsBool WriteOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset)
4994 cmsUInt32Number Before = io ->Tell(io);
4997 e ->Offsets[i] = Before - BaseOffset;
4999 if (wcstr == NULL) {
5005 n = mywcslen(wcstr);
5006 if (!_cmsWriteWCharArray(io, n, wcstr)) return FALSE;
5008 e ->Sizes[i] = io ->Tell(io) - Before;
5013 cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu)
5015 cmsUInt32Number nItems = 0;
5017 // A way to get null MLUCs
5018 if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) {
5024 if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
5026 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]);
5027 return *mlu != NULL;
5031 cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset)
5033 cmsUInt32Number Before;
5035 // Special case for undefined strings (see ICC Votable
5036 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
5043 Before = io ->Tell(io);
5044 e ->Offsets[i] = Before - BaseOffset;
5046 if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE;
5048 e ->Sizes[i] = io ->Tell(io) - Before;
5054 void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
5057 cmsUInt32Number i, Count, Length;
5058 cmsUInt32Number BaseOffset;
5060 wchar_t *NameWCS = NULL, *ValueWCS = NULL;
5061 cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL;
5066 // Get actual position as a basis for element offsets
5067 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
5069 // Get name-value record count
5070 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
5071 SizeOfTag -= sizeof(cmsUInt32Number);
5074 if (!_cmsReadUInt32Number(io, &Length)) return NULL;
5075 SizeOfTag -= sizeof(cmsUInt32Number);
5077 // Check for valid lengths
5078 if (Length != 16 && Length != 24 && Length != 32) {
5079 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length);
5083 // Creates an empty dictionary
5084 hDict = cmsDictAlloc(self -> ContextID);
5085 if (hDict == NULL) return NULL;
5087 // On depending on record size, create column arrays
5088 if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error;
5090 // Read column arrays
5091 if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error;
5093 // Seek to each element and read it
5094 for (i=0; i < Count; i++) {
5096 if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error;
5097 if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error;
5100 if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error;
5104 if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error;
5107 if (NameWCS == NULL || ValueWCS == NULL) {
5109 cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value");
5114 rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
5117 if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS);
5118 if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS);
5119 if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU);
5120 if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU);
5122 if (!rc) goto Error;
5127 return (void*) hDict;
5137 cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
5139 cmsHANDLE hDict = (cmsHANDLE) Ptr;
5140 const cmsDICTentry* p;
5141 cmsBool AnyName, AnyValue;
5142 cmsUInt32Number i, Count, Length;
5143 cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset;
5146 if (hDict == NULL) return FALSE;
5148 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
5150 // Let's inspect the dictionary
5151 Count = 0; AnyName = FALSE; AnyValue = FALSE;
5152 for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) {
5154 if (p ->DisplayName != NULL) AnyName = TRUE;
5155 if (p ->DisplayValue != NULL) AnyValue = TRUE;
5160 if (AnyName) Length += 8;
5161 if (AnyValue) Length += 8;
5163 if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
5164 if (!_cmsWriteUInt32Number(io, Length)) return FALSE;
5166 // Keep starting position of offsets table
5167 DirectoryPos = io ->Tell(io);
5169 // Allocate offsets array
5170 if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error;
5172 // Write a fake directory to be filled latter on
5173 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5175 // Write each element. Keep track of the size as well.
5176 p = cmsDictGetEntryList(hDict);
5177 for (i=0; i < Count; i++) {
5179 if (!WriteOneWChar(io, &a.Name, i, p ->Name, BaseOffset)) goto Error;
5180 if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error;
5182 if (p ->DisplayName != NULL) {
5183 if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error;
5186 if (p ->DisplayValue != NULL) {
5187 if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error;
5190 p = cmsDictNextEntry(p);
5193 // Write the directory
5194 CurrentPos = io ->Tell(io);
5195 if (!io ->Seek(io, DirectoryPos)) goto Error;
5197 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5199 if (!io ->Seek(io, CurrentPos)) goto Error;
5208 cmsUNUSED_PARAMETER(nItems);
5213 void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
5215 return (void*) cmsDictDup((cmsHANDLE) Ptr);
5217 cmsUNUSED_PARAMETER(n);
5218 cmsUNUSED_PARAMETER(self);
5223 void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr)
5225 cmsDictFree((cmsHANDLE) Ptr);
5226 cmsUNUSED_PARAMETER(self);
5230 // ********************************************************************************
5231 // Type support main routines
5232 // ********************************************************************************
5235 // This is the list of built-in types
5236 static _cmsTagTypeLinkedList SupportedTagTypes[] = {
5238 {TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] },
5239 {TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), &SupportedTagTypes[2] },
5240 {TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), &SupportedTagTypes[3] },
5241 {TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), &SupportedTagTypes[4] },
5242 {TYPE_HANDLER(cmsSigTextType, Text), &SupportedTagTypes[5] },
5243 {TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), &SupportedTagTypes[6] },
5244 {TYPE_HANDLER(cmsSigCurveType, Curve), &SupportedTagTypes[7] },
5245 {TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), &SupportedTagTypes[8] },
5246 {TYPE_HANDLER(cmsSigDateTimeType, DateTime), &SupportedTagTypes[9] },
5247 {TYPE_HANDLER(cmsSigLut8Type, LUT8), &SupportedTagTypes[10] },
5248 {TYPE_HANDLER(cmsSigLut16Type, LUT16), &SupportedTagTypes[11] },
5249 {TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), &SupportedTagTypes[12] },
5250 {TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), &SupportedTagTypes[13] },
5251 {TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), &SupportedTagTypes[14] },
5252 {TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc), &SupportedTagTypes[15] },
5253 {TYPE_HANDLER(cmsSigSignatureType, Signature), &SupportedTagTypes[16] },
5254 {TYPE_HANDLER(cmsSigMeasurementType, Measurement), &SupportedTagTypes[17] },
5255 {TYPE_HANDLER(cmsSigDataType, Data), &SupportedTagTypes[18] },
5256 {TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), &SupportedTagTypes[19] },
5257 {TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), &SupportedTagTypes[20] },
5258 {TYPE_HANDLER(cmsSigUcrBgType, UcrBg), &SupportedTagTypes[21] },
5259 {TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), &SupportedTagTypes[22] },
5260 {TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), &SupportedTagTypes[23] },
5261 {TYPE_HANDLER(cmsSigScreeningType, Screening), &SupportedTagTypes[24] },
5262 {TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), &SupportedTagTypes[25] },
5263 {TYPE_HANDLER(cmsSigXYZType, XYZ), &SupportedTagTypes[26] },
5264 {TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] },
5265 {TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] },
5266 {TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] },
5267 {TYPE_HANDLER(cmsSigDictType, Dictionary), &SupportedTagTypes[30] },
5268 {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL }
5272 _cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL };
5276 // Duplicates the zone of memory used by the plug-in in the new context
5278 void DupTagTypeList(struct _cmsContext_struct* ctx,
5279 const struct _cmsContext_struct* src,
5282 _cmsTagTypePluginChunkType newHead = { NULL };
5283 _cmsTagTypeLinkedList* entry;
5284 _cmsTagTypeLinkedList* Anterior = NULL;
5285 _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc];
5287 // Walk the list copying all nodes
5288 for (entry = head->TagTypes;
5290 entry = entry ->Next) {
5292 _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList));
5294 if (newEntry == NULL)
5297 // We want to keep the linked list order, so this is a little bit tricky
5298 newEntry -> Next = NULL;
5300 Anterior -> Next = newEntry;
5302 Anterior = newEntry;
5304 if (newHead.TagTypes == NULL)
5305 newHead.TagTypes = newEntry;
5308 ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType));
5312 void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx,
5313 const struct _cmsContext_struct* src)
5317 // Duplicate the LIST
5318 DupTagTypeList(ctx, src, TagTypePlugin);
5321 static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
5322 ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
5326 void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx,
5327 const struct _cmsContext_struct* src)
5331 // Duplicate the LIST
5332 DupTagTypeList(ctx, src, MPEPlugin);
5335 static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
5336 ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
5342 // Both kind of plug-ins share same structure
5343 cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data)
5345 return RegisterTypesPlugin(id, Data, TagTypePlugin);
5348 cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data)
5350 return RegisterTypesPlugin(id, Data,MPEPlugin);
5354 // Wrapper for tag types
5355 cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig)
5357 _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin);
5359 return GetHandler(sig, ctx->TagTypes, SupportedTagTypes);
5362 // ********************************************************************************
5363 // Tag support main routines
5364 // ********************************************************************************
5366 typedef struct _cmsTagLinkedList_st {
5368 cmsTagSignature Signature;
5369 cmsTagDescriptor Descriptor;
5370 struct _cmsTagLinkedList_st* Next;
5372 } _cmsTagLinkedList;
5374 // This is the list of built-in tags
5375 static _cmsTagLinkedList SupportedTags[] = {
5377 { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]},
5378 { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]},
5379 { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]},
5380 { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]},
5381 { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]},
5382 { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]},
5384 // Allow corbis and its broken XYZ type
5385 { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]},
5386 { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]},
5387 { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]},
5389 { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]},
5390 { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]},
5391 { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]},
5393 { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]},
5394 { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]},
5396 { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]},
5397 { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]},
5398 { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]},
5399 { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]},
5400 { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]},
5402 { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]},
5403 { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]},
5405 { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]},
5406 { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]},
5408 { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]},
5410 { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]},
5411 { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]},
5413 { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]},
5414 { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]},
5416 { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]},
5418 { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]},
5419 { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]},
5420 { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]},
5422 { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]},
5423 { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]},
5424 { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]},
5426 { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]},
5427 { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]},
5428 { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]},
5430 { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]},
5432 { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]},
5433 { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]},
5434 { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]},
5435 { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]},
5436 { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]},
5437 { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]},
5439 { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]},
5441 { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]},
5442 { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]},
5444 { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]},
5445 { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]},
5446 { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]},
5447 { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]},
5448 { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]},
5449 { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]},
5450 { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]},
5451 { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]},
5453 { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]},
5454 { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]},
5456 { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]},
5457 { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]},
5458 { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]},
5459 { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]},
5460 { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]},
5461 { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL}
5468 ======================= =========================================
5469 cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
5470 cmsSigNamedColorTag ==> Deprecated
5471 cmsSigDataTag ==> Ancient, unused
5472 cmsSigDeviceSettingsTag ==> Deprecated, useless
5476 _cmsTagPluginChunkType _cmsTagPluginChunk = { NULL };
5479 // Duplicates the zone of memory used by the plug-in in the new context
5481 void DupTagList(struct _cmsContext_struct* ctx,
5482 const struct _cmsContext_struct* src)
5484 _cmsTagPluginChunkType newHead = { NULL };
5485 _cmsTagLinkedList* entry;
5486 _cmsTagLinkedList* Anterior = NULL;
5487 _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin];
5489 // Walk the list copying all nodes
5490 for (entry = head->Tag;
5492 entry = entry ->Next) {
5494 _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList));
5496 if (newEntry == NULL)
5499 // We want to keep the linked list order, so this is a little bit tricky
5500 newEntry -> Next = NULL;
5502 Anterior -> Next = newEntry;
5504 Anterior = newEntry;
5506 if (newHead.Tag == NULL)
5507 newHead.Tag = newEntry;
5510 ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType));
5513 void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx,
5514 const struct _cmsContext_struct* src)
5518 DupTagList(ctx, src);
5521 static _cmsTagPluginChunkType TagPluginChunk = { NULL };
5522 ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType));
5527 cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data)
5529 cmsPluginTag* Plugin = (cmsPluginTag*) Data;
5530 _cmsTagLinkedList *pt;
5531 _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin);
5535 TagPluginChunk->Tag = NULL;
5539 pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList));
5540 if (pt == NULL) return FALSE;
5542 pt ->Signature = Plugin ->Signature;
5543 pt ->Descriptor = Plugin ->Descriptor;
5544 pt ->Next = TagPluginChunk ->Tag;
5546 TagPluginChunk ->Tag = pt;
5551 // Return a descriptor for a given tag or NULL
5552 cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig)
5554 _cmsTagLinkedList* pt;
5555 _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin);
5557 for (pt = TagPluginChunk->Tag;
5561 if (sig == pt -> Signature) return &pt ->Descriptor;
5564 for (pt = SupportedTags;
5568 if (sig == pt -> Signature) return &pt ->Descriptor;