1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2023 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 appropriate 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 }
64 #define MINUS_INF (-1E22F)
65 #define PLUS_INF (+1E22F)
68 // Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head
70 cmsBool
RegisterTypesPlugin(cmsContext id
, cmsPluginBase
* Data
, _cmsMemoryClient pos
)
72 cmsPluginTagType
* Plugin
= (cmsPluginTagType
*) Data
;
73 _cmsTagTypePluginChunkType
* ctx
= ( _cmsTagTypePluginChunkType
*) _cmsContextGetClientChunk(id
, pos
);
74 _cmsTagTypeLinkedList
*pt
;
76 // Calling the function with NULL as plug-in would unregister the plug in.
79 // There is no need to set free the memory, as pool is destroyed as a whole.
80 ctx
->TagTypes
= NULL
;
84 // Registering happens in plug-in memory pool.
85 pt
= (_cmsTagTypeLinkedList
*) _cmsPluginMalloc(id
, sizeof(_cmsTagTypeLinkedList
));
86 if (pt
== NULL
) return FALSE
;
88 pt
->Handler
= Plugin
->Handler
;
89 pt
->Next
= ctx
->TagTypes
;
96 // Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons
97 // made by plug-ins and then the built-in defaults.
99 cmsTagTypeHandler
* GetHandler(cmsTagTypeSignature sig
, _cmsTagTypeLinkedList
* PluginLinkedList
, _cmsTagTypeLinkedList
* DefaultLinkedList
)
101 _cmsTagTypeLinkedList
* pt
;
103 for (pt
= PluginLinkedList
;
107 if (sig
== pt
-> Handler
.Signature
) return &pt
->Handler
;
110 for (pt
= DefaultLinkedList
;
114 if (sig
== pt
-> Handler
.Signature
) return &pt
->Handler
;
121 // Auxiliary to convert UTF-32 to UTF-16 in some cases
123 cmsBool
_cmsWriteWCharArray(cmsIOHANDLER
* io
, cmsUInt32Number n
, const wchar_t* Array
)
127 _cmsAssert(io
!= NULL
);
128 _cmsAssert(!(Array
== NULL
&& n
> 0));
130 for (i
=0; i
< n
; i
++) {
131 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) Array
[i
])) return FALSE
;
137 // Try to promote correctly to wchar_t when 32 bits
138 cmsINLINE cmsBool
is_surrogate(cmsUInt32Number uc
) { return (uc
- 0xd800u
) < 2048u; }
139 cmsINLINE cmsBool
is_high_surrogate(cmsUInt32Number uc
) { return (uc
& 0xfffffc00) == 0xd800; }
140 cmsINLINE cmsBool
is_low_surrogate(cmsUInt32Number uc
) { return (uc
& 0xfffffc00) == 0xdc00; }
142 cmsINLINE cmsUInt32Number
surrogate_to_utf32(cmsUInt32Number high
, cmsUInt32Number low
)
144 return (high
<< 10) + low
- 0x35fdc00;
147 cmsINLINE cmsBool
convert_utf16_to_utf32(cmsIOHANDLER
* io
, cmsInt32Number n
, wchar_t* output
)
153 if (!_cmsReadUInt16Number(io
, &uc
)) return FALSE
;
156 if (!is_surrogate(uc
))
158 *output
++ = (wchar_t)uc
;
164 if (!_cmsReadUInt16Number(io
, &low
)) return FALSE
;
167 if (is_high_surrogate(uc
) && is_low_surrogate(low
))
168 *output
++ = (wchar_t)surrogate_to_utf32(uc
, low
);
170 return FALSE
; // Corrupted string, just ignore
178 // Auxiliary to read an array of wchar_t
180 cmsBool
_cmsReadWCharArray(cmsIOHANDLER
* io
, cmsUInt32Number n
, wchar_t* Array
)
184 cmsBool is32
= sizeof(wchar_t) > sizeof(cmsUInt16Number
);
186 _cmsAssert(io
!= NULL
);
188 if (is32
&& Array
!= NULL
)
190 return convert_utf16_to_utf32(io
, n
, Array
);
193 for (i
=0; i
< n
; i
++) {
197 if (!_cmsReadUInt16Number(io
, &tmp
)) return FALSE
;
198 Array
[i
] = (wchar_t) tmp
;
201 if (!_cmsReadUInt16Number(io
, NULL
)) return FALSE
;
208 // To deal with position tables
209 typedef cmsBool (* PositionTableEntryFn
)(struct _cms_typehandler_struct
* self
,
213 cmsUInt32Number SizeOfTag
);
215 // Helper function to deal with position tables as described in ICC spec 4.3
216 // A table of n elements is read, where first comes n records containing offsets and sizes and
217 // then a block containing the data itself. This allows to reuse same data in more than one entry
219 cmsBool
ReadPositionTable(struct _cms_typehandler_struct
* self
,
221 cmsUInt32Number Count
,
222 cmsUInt32Number BaseOffset
,
224 PositionTableEntryFn ElementFn
)
227 cmsUInt32Number
*ElementOffsets
= NULL
, *ElementSizes
= NULL
;
228 cmsUInt32Number currentPosition
;
230 currentPosition
= io
->Tell(io
);
232 // Verify there is enough space left to read at least two cmsUInt32Number items for Count items.
233 if (((io
->ReportedSize
- currentPosition
) / (2 * sizeof(cmsUInt32Number
))) < Count
)
236 // Let's take the offsets to each element
237 ElementOffsets
= (cmsUInt32Number
*) _cmsCalloc(io
->ContextID
, Count
, sizeof(cmsUInt32Number
));
238 if (ElementOffsets
== NULL
) goto Error
;
240 ElementSizes
= (cmsUInt32Number
*) _cmsCalloc(io
->ContextID
, Count
, sizeof(cmsUInt32Number
));
241 if (ElementSizes
== NULL
) goto Error
;
243 for (i
=0; i
< Count
; i
++) {
245 if (!_cmsReadUInt32Number(io
, &ElementOffsets
[i
])) goto Error
;
246 if (!_cmsReadUInt32Number(io
, &ElementSizes
[i
])) goto Error
;
248 ElementOffsets
[i
] += BaseOffset
;
251 // Seek to each element and read it
252 for (i
=0; i
< Count
; i
++) {
254 if (!io
-> Seek(io
, ElementOffsets
[i
])) goto Error
;
256 // This is the reader callback
257 if (!ElementFn(self
, io
, Cargo
, i
, ElementSizes
[i
])) goto Error
;
261 if (ElementOffsets
!= NULL
) _cmsFree(io
->ContextID
, ElementOffsets
);
262 if (ElementSizes
!= NULL
) _cmsFree(io
->ContextID
, ElementSizes
);
266 if (ElementOffsets
!= NULL
) _cmsFree(io
->ContextID
, ElementOffsets
);
267 if (ElementSizes
!= NULL
) _cmsFree(io
->ContextID
, ElementSizes
);
271 // Same as anterior, but for write position tables
273 cmsBool
WritePositionTable(struct _cms_typehandler_struct
* self
,
275 cmsUInt32Number SizeOfTag
,
276 cmsUInt32Number Count
,
277 cmsUInt32Number BaseOffset
,
279 PositionTableEntryFn ElementFn
)
282 cmsUInt32Number DirectoryPos
, CurrentPos
, Before
;
283 cmsUInt32Number
*ElementOffsets
= NULL
, *ElementSizes
= NULL
;
286 ElementOffsets
= (cmsUInt32Number
*) _cmsCalloc(io
->ContextID
, Count
, sizeof(cmsUInt32Number
));
287 if (ElementOffsets
== NULL
) goto Error
;
289 ElementSizes
= (cmsUInt32Number
*) _cmsCalloc(io
->ContextID
, Count
, sizeof(cmsUInt32Number
));
290 if (ElementSizes
== NULL
) goto Error
;
292 // Keep starting position of curve offsets
293 DirectoryPos
= io
->Tell(io
);
295 // Write a fake directory to be filled latter on
296 for (i
=0; i
< Count
; i
++) {
298 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
; // Offset
299 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
; // size
302 // Write each element. Keep track of the size as well.
303 for (i
=0; i
< Count
; i
++) {
305 Before
= io
->Tell(io
);
306 ElementOffsets
[i
] = Before
- BaseOffset
;
308 // Callback to write...
309 if (!ElementFn(self
, io
, Cargo
, i
, SizeOfTag
)) goto Error
;
312 ElementSizes
[i
] = io
->Tell(io
) - Before
;
315 // Write the directory
316 CurrentPos
= io
->Tell(io
);
317 if (!io
->Seek(io
, DirectoryPos
)) goto Error
;
319 for (i
=0; i
< Count
; i
++) {
320 if (!_cmsWriteUInt32Number(io
, ElementOffsets
[i
])) goto Error
;
321 if (!_cmsWriteUInt32Number(io
, ElementSizes
[i
])) goto Error
;
324 if (!io
->Seek(io
, CurrentPos
)) goto Error
;
326 if (ElementOffsets
!= NULL
) _cmsFree(io
->ContextID
, ElementOffsets
);
327 if (ElementSizes
!= NULL
) _cmsFree(io
->ContextID
, ElementSizes
);
331 if (ElementOffsets
!= NULL
) _cmsFree(io
->ContextID
, ElementOffsets
);
332 if (ElementSizes
!= NULL
) _cmsFree(io
->ContextID
, ElementSizes
);
337 // ********************************************************************************
338 // Type XYZ. Only one value is allowed
339 // ********************************************************************************
341 //The XYZType contains an array of three encoded values for the XYZ tristimulus
342 //values. Tristimulus values must be non-negative. The signed encoding allows for
343 //implementation optimizations by minimizing the number of fixed formats.
347 void *Type_XYZ_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
352 xyz
= (cmsCIEXYZ
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsCIEXYZ
));
353 if (xyz
== NULL
) return NULL
;
355 if (!_cmsReadXYZNumber(io
, xyz
)) {
356 _cmsFree(self
->ContextID
, xyz
);
363 cmsUNUSED_PARAMETER(SizeOfTag
);
367 cmsBool
Type_XYZ_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
369 return _cmsWriteXYZNumber(io
, (cmsCIEXYZ
*) Ptr
);
371 cmsUNUSED_PARAMETER(nItems
);
372 cmsUNUSED_PARAMETER(self
);
376 void* Type_XYZ_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
378 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsCIEXYZ
));
380 cmsUNUSED_PARAMETER(n
);
384 void Type_XYZ_Free(struct _cms_typehandler_struct
* self
, void *Ptr
)
386 _cmsFree(self
->ContextID
, Ptr
);
391 cmsTagTypeSignature
DecideXYZtype(cmsFloat64Number ICCVersion
, const void *Data
)
393 return cmsSigXYZType
;
395 cmsUNUSED_PARAMETER(ICCVersion
);
396 cmsUNUSED_PARAMETER(Data
);
400 // ********************************************************************************
401 // Type chromaticity. Only one value is allowed
402 // ********************************************************************************
403 // The chromaticity tag type provides basic chromaticity data and type of
404 // phosphors or colorants of a monitor to applications and utilities.
407 void *Type_Chromaticity_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
409 cmsCIExyYTRIPLE
* chrm
;
410 cmsUInt16Number nChans
, Table
;
413 chrm
= (cmsCIExyYTRIPLE
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsCIExyYTRIPLE
));
414 if (chrm
== NULL
) return NULL
;
416 if (!_cmsReadUInt16Number(io
, &nChans
)) goto Error
;
418 // Let's recover from a bug introduced in early versions of lcms1
419 if (nChans
== 0 && SizeOfTag
== 32) {
421 if (!_cmsReadUInt16Number(io
, NULL
)) goto Error
;
422 if (!_cmsReadUInt16Number(io
, &nChans
)) goto Error
;
425 if (nChans
!= 3) goto Error
;
427 if (!_cmsReadUInt16Number(io
, &Table
)) goto Error
;
429 if (!_cmsRead15Fixed16Number(io
, &chrm
->Red
.x
)) goto Error
;
430 if (!_cmsRead15Fixed16Number(io
, &chrm
->Red
.y
)) goto Error
;
434 if (!_cmsRead15Fixed16Number(io
, &chrm
->Green
.x
)) goto Error
;
435 if (!_cmsRead15Fixed16Number(io
, &chrm
->Green
.y
)) goto Error
;
437 chrm
->Green
.Y
= 1.0;
439 if (!_cmsRead15Fixed16Number(io
, &chrm
->Blue
.x
)) goto Error
;
440 if (!_cmsRead15Fixed16Number(io
, &chrm
->Blue
.y
)) goto Error
;
448 _cmsFree(self
->ContextID
, (void*) chrm
);
451 cmsUNUSED_PARAMETER(SizeOfTag
);
455 cmsBool
SaveOneChromaticity(cmsFloat64Number x
, cmsFloat64Number y
, cmsIOHANDLER
* io
)
457 if (!_cmsWriteUInt32Number(io
, (cmsUInt32Number
) _cmsDoubleTo15Fixed16(x
))) return FALSE
;
458 if (!_cmsWriteUInt32Number(io
, (cmsUInt32Number
) _cmsDoubleTo15Fixed16(y
))) return FALSE
;
464 cmsBool
Type_Chromaticity_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
466 cmsCIExyYTRIPLE
* chrm
= (cmsCIExyYTRIPLE
*) Ptr
;
468 if (!_cmsWriteUInt16Number(io
, 3)) return FALSE
; // nChannels
469 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
; // Table
471 if (!SaveOneChromaticity(chrm
-> Red
.x
, chrm
-> Red
.y
, io
)) return FALSE
;
472 if (!SaveOneChromaticity(chrm
-> Green
.x
, chrm
-> Green
.y
, io
)) return FALSE
;
473 if (!SaveOneChromaticity(chrm
-> Blue
.x
, chrm
-> Blue
.y
, io
)) return FALSE
;
477 cmsUNUSED_PARAMETER(nItems
);
478 cmsUNUSED_PARAMETER(self
);
482 void* Type_Chromaticity_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
484 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsCIExyYTRIPLE
));
486 cmsUNUSED_PARAMETER(n
);
490 void Type_Chromaticity_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
492 _cmsFree(self
->ContextID
, Ptr
);
496 // ********************************************************************************
497 // Type cmsSigColorantOrderType
498 // ********************************************************************************
500 // This is an optional tag which specifies the laydown order in which colorants will
501 // be printed on an n-colorant device. The laydown order may be the same as the
502 // channel generation order listed in the colorantTableTag or the channel order of a
503 // colour space such as CMYK, in which case this tag is not needed. When this is not
504 // the case (for example, ink-towers sometimes use the order KCMY), this tag may be
505 // used to specify the laydown order of the colorants.
509 void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
511 cmsUInt8Number
* ColorantOrder
;
512 cmsUInt32Number Count
;
515 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
516 if (Count
> cmsMAXCHANNELS
) return NULL
;
518 ColorantOrder
= (cmsUInt8Number
*) _cmsCalloc(self
->ContextID
, cmsMAXCHANNELS
, sizeof(cmsUInt8Number
));
519 if (ColorantOrder
== NULL
) return NULL
;
521 // We use FF as end marker
522 memset(ColorantOrder
, 0xFF, cmsMAXCHANNELS
* sizeof(cmsUInt8Number
));
524 if (io
->Read(io
, ColorantOrder
, sizeof(cmsUInt8Number
), Count
) != Count
) {
526 _cmsFree(self
->ContextID
, (void*) ColorantOrder
);
531 return (void*) ColorantOrder
;
533 cmsUNUSED_PARAMETER(SizeOfTag
);
537 cmsBool
Type_ColorantOrderType_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
539 cmsUInt8Number
* ColorantOrder
= (cmsUInt8Number
*) Ptr
;
540 cmsUInt32Number i
, sz
, Count
;
543 for (Count
=i
=0; i
< cmsMAXCHANNELS
; i
++) {
544 if (ColorantOrder
[i
] != 0xFF) Count
++;
547 if (!_cmsWriteUInt32Number(io
, Count
)) return FALSE
;
549 sz
= Count
* sizeof(cmsUInt8Number
);
550 if (!io
-> Write(io
, sz
, ColorantOrder
)) return FALSE
;
554 cmsUNUSED_PARAMETER(nItems
);
555 cmsUNUSED_PARAMETER(self
);
559 void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
561 return _cmsDupMem(self
->ContextID
, Ptr
, cmsMAXCHANNELS
* sizeof(cmsUInt8Number
));
563 cmsUNUSED_PARAMETER(n
);
568 void Type_ColorantOrderType_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
570 _cmsFree(self
->ContextID
, Ptr
);
573 // ********************************************************************************
574 // Type cmsSigS15Fixed16ArrayType
575 // ********************************************************************************
576 // This type represents an array of generic 4-byte/32-bit fixed point quantity.
577 // The number of values is determined from the size of the tag.
580 void *Type_S15Fixed16_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
582 cmsFloat64Number
* array_double
;
583 cmsUInt32Number i
, n
;
586 n
= SizeOfTag
/ sizeof(cmsUInt32Number
);
587 array_double
= (cmsFloat64Number
*) _cmsCalloc(self
->ContextID
, n
, sizeof(cmsFloat64Number
));
588 if (array_double
== NULL
) return NULL
;
590 for (i
=0; i
< n
; i
++) {
592 if (!_cmsRead15Fixed16Number(io
, &array_double
[i
])) {
594 _cmsFree(self
->ContextID
, array_double
);
600 return (void*) array_double
;
604 cmsBool
Type_S15Fixed16_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
606 cmsFloat64Number
* Value
= (cmsFloat64Number
*) Ptr
;
609 for (i
=0; i
< nItems
; i
++) {
611 if (!_cmsWrite15Fixed16Number(io
, Value
[i
])) return FALSE
;
616 cmsUNUSED_PARAMETER(self
);
620 void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
622 return _cmsDupMem(self
->ContextID
, Ptr
, n
* sizeof(cmsFloat64Number
));
627 void Type_S15Fixed16_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
629 _cmsFree(self
->ContextID
, Ptr
);
632 // ********************************************************************************
633 // Type cmsSigU16Fixed16ArrayType
634 // ********************************************************************************
635 // This type represents an array of generic 4-byte/32-bit quantity.
636 // The number of values is determined from the size of the tag.
640 void *Type_U16Fixed16_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
642 cmsFloat64Number
* array_double
;
644 cmsUInt32Number i
, n
;
647 n
= SizeOfTag
/ sizeof(cmsUInt32Number
);
648 array_double
= (cmsFloat64Number
*) _cmsCalloc(self
->ContextID
, n
, sizeof(cmsFloat64Number
));
649 if (array_double
== NULL
) return NULL
;
651 for (i
=0; i
< n
; i
++) {
653 if (!_cmsReadUInt32Number(io
, &v
)) {
654 _cmsFree(self
->ContextID
, (void*) array_double
);
658 // Convert to cmsFloat64Number
659 array_double
[i
] = (cmsFloat64Number
) (v
/ 65536.0);
663 return (void*) array_double
;
667 cmsBool
Type_U16Fixed16_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
669 cmsFloat64Number
* Value
= (cmsFloat64Number
*) Ptr
;
672 for (i
=0; i
< nItems
; i
++) {
674 cmsUInt32Number v
= (cmsUInt32Number
) floor(Value
[i
]*65536.0 + 0.5);
676 if (!_cmsWriteUInt32Number(io
, v
)) return FALSE
;
681 cmsUNUSED_PARAMETER(self
);
686 void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
688 return _cmsDupMem(self
->ContextID
, Ptr
, n
* sizeof(cmsFloat64Number
));
692 void Type_U16Fixed16_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
694 _cmsFree(self
->ContextID
, Ptr
);
697 // ********************************************************************************
698 // Type cmsSigSignatureType
699 // ********************************************************************************
701 // The signatureType contains a four-byte sequence, Sequences of less than four
702 // characters are padded at the end with spaces, 20h.
703 // Typically this type is used for registered tags that can be displayed on many
704 // development systems as a sequence of four characters.
707 void *Type_Signature_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
709 cmsSignature
* SigPtr
= (cmsSignature
*) _cmsMalloc(self
->ContextID
, sizeof(cmsSignature
));
710 if (SigPtr
== NULL
) return NULL
;
712 if (!_cmsReadUInt32Number(io
, SigPtr
)) return NULL
;
717 cmsUNUSED_PARAMETER(SizeOfTag
);
721 cmsBool
Type_Signature_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
723 cmsSignature
* SigPtr
= (cmsSignature
*) Ptr
;
725 return _cmsWriteUInt32Number(io
, *SigPtr
);
727 cmsUNUSED_PARAMETER(nItems
);
728 cmsUNUSED_PARAMETER(self
);
732 void* Type_Signature_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
734 return _cmsDupMem(self
->ContextID
, Ptr
, n
* sizeof(cmsSignature
));
738 void Type_Signature_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
740 _cmsFree(self
->ContextID
, Ptr
);
744 // ********************************************************************************
745 // Type cmsSigTextType
746 // ********************************************************************************
748 // The textType is a simple text structure that contains a 7-bit ASCII text string.
749 // The length of the string is obtained by subtracting 8 from the element size portion
750 // of the tag itself. This string must be terminated with a 00h byte.
753 void *Type_Text_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
758 // Create a container
759 mlu
= cmsMLUalloc(self
->ContextID
, 1);
760 if (mlu
== NULL
) return NULL
;
764 // We need to store the "\0" at the end, so +1
765 if (SizeOfTag
== UINT_MAX
) goto Error
;
767 Text
= (char*) _cmsMalloc(self
->ContextID
, SizeOfTag
+ 1);
768 if (Text
== NULL
) goto Error
;
770 if (io
-> Read(io
, Text
, sizeof(char), SizeOfTag
) != SizeOfTag
) goto Error
;
772 // Make sure text is properly ended
777 if (!cmsMLUsetASCII(mlu
, cmsNoLanguage
, cmsNoCountry
, Text
)) goto Error
;
779 _cmsFree(self
->ContextID
, Text
);
786 _cmsFree(self
->ContextID
, Text
);
791 // The conversion implies to choose a language. So, we choose the actual language.
793 cmsBool
Type_Text_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
795 cmsMLU
* mlu
= (cmsMLU
*) Ptr
;
796 cmsUInt32Number size
;
800 // Get the size of the string. Note there is an extra "\0" at the end
801 size
= cmsMLUgetASCII(mlu
, cmsNoLanguage
, cmsNoCountry
, NULL
, 0);
802 if (size
== 0) return FALSE
; // Cannot be zero!
805 Text
= (char*) _cmsMalloc(self
->ContextID
, size
);
806 if (Text
== NULL
) return FALSE
;
808 cmsMLUgetASCII(mlu
, cmsNoLanguage
, cmsNoCountry
, Text
, size
);
810 // Write it, including separator
811 rc
= io
->Write(io
, size
, Text
);
813 _cmsFree(self
->ContextID
, Text
);
816 cmsUNUSED_PARAMETER(nItems
);
820 void* Type_Text_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
822 return (void*) cmsMLUdup((cmsMLU
*) Ptr
);
824 cmsUNUSED_PARAMETER(n
);
825 cmsUNUSED_PARAMETER(self
);
830 void Type_Text_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
832 cmsMLU
* mlu
= (cmsMLU
*) Ptr
;
836 cmsUNUSED_PARAMETER(self
);
840 cmsTagTypeSignature
DecideTextType(cmsFloat64Number ICCVersion
, const void *Data
)
842 if (ICCVersion
>= 4.0)
843 return cmsSigMultiLocalizedUnicodeType
;
845 return cmsSigTextType
;
847 cmsUNUSED_PARAMETER(Data
);
851 // ********************************************************************************
852 // Type cmsSigDataType
853 // ********************************************************************************
855 // General purpose data type
857 void *Type_Data_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
860 cmsUInt32Number LenOfData
;
864 if (SizeOfTag
< sizeof(cmsUInt32Number
)) return NULL
;
866 LenOfData
= SizeOfTag
- sizeof(cmsUInt32Number
);
867 if (LenOfData
> INT_MAX
) return NULL
;
869 BinData
= (cmsICCData
*) _cmsMalloc(self
->ContextID
, sizeof(cmsICCData
) + LenOfData
- 1);
870 if (BinData
== NULL
) return NULL
;
872 BinData
->len
= LenOfData
;
873 if (!_cmsReadUInt32Number(io
, &BinData
->flag
)) {
874 _cmsFree(self
->ContextID
, BinData
);
878 if (io
-> Read(io
, BinData
->data
, sizeof(cmsUInt8Number
), LenOfData
) != LenOfData
) {
880 _cmsFree(self
->ContextID
, BinData
);
886 return (void*) BinData
;
891 cmsBool
Type_Data_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
893 cmsICCData
* BinData
= (cmsICCData
*) Ptr
;
895 if (!_cmsWriteUInt32Number(io
, BinData
->flag
)) return FALSE
;
897 return io
->Write(io
, BinData
->len
, BinData
->data
);
899 cmsUNUSED_PARAMETER(nItems
);
900 cmsUNUSED_PARAMETER(self
);
905 void* Type_Data_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
907 cmsICCData
* BinData
= (cmsICCData
*) Ptr
;
909 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsICCData
) + BinData
->len
- 1);
911 cmsUNUSED_PARAMETER(n
);
915 void Type_Data_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
917 _cmsFree(self
->ContextID
, Ptr
);
920 // ********************************************************************************
921 // Type cmsSigTextDescriptionType
922 // ********************************************************************************
925 void *Type_Text_Description_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
929 cmsUInt32Number AsciiCount
;
930 cmsUInt32Number i
, UnicodeCode
, UnicodeCount
;
931 cmsUInt16Number ScriptCodeCode
, Dummy
;
932 cmsUInt8Number ScriptCodeCount
;
936 // One dword should be there
937 if (SizeOfTag
< sizeof(cmsUInt32Number
)) return NULL
;
940 if (!_cmsReadUInt32Number(io
, &AsciiCount
)) return NULL
;
941 SizeOfTag
-= sizeof(cmsUInt32Number
);
944 if (SizeOfTag
< AsciiCount
) return NULL
;
946 // All seems Ok, allocate the container
947 mlu
= cmsMLUalloc(self
->ContextID
, 1);
948 if (mlu
== NULL
) return NULL
;
950 // As many memory as size of tag
951 Text
= (char*) _cmsMalloc(self
->ContextID
, AsciiCount
+ 1);
952 if (Text
== NULL
) goto Error
;
955 if (io
->Read(io
, Text
, sizeof(char), AsciiCount
) != AsciiCount
) goto Error
;
956 SizeOfTag
-= AsciiCount
;
958 // Make sure there is a terminator
959 Text
[AsciiCount
] = 0;
961 // Set the MLU entry. From here we can be tolerant to wrong types
962 if (!cmsMLUsetASCII(mlu
, cmsNoLanguage
, cmsNoCountry
, Text
)) goto Error
;
963 _cmsFree(self
->ContextID
, (void*) Text
);
967 if (SizeOfTag
< 2* sizeof(cmsUInt32Number
)) goto Done
;
968 if (!_cmsReadUInt32Number(io
, &UnicodeCode
)) goto Done
;
969 if (!_cmsReadUInt32Number(io
, &UnicodeCount
)) goto Done
;
970 SizeOfTag
-= 2* sizeof(cmsUInt32Number
);
972 if (SizeOfTag
< UnicodeCount
*sizeof(cmsUInt16Number
)) goto Done
;
974 for (i
=0; i
< UnicodeCount
; i
++) {
975 if (!io
->Read(io
, &Dummy
, sizeof(cmsUInt16Number
), 1)) goto Done
;
977 SizeOfTag
-= UnicodeCount
*sizeof(cmsUInt16Number
);
979 // Skip ScriptCode code if present. Some buggy profiles does have less
980 // data that stricttly required. We need to skip it as this type may come
981 // embedded in other types.
983 if (SizeOfTag
>= sizeof(cmsUInt16Number
) + sizeof(cmsUInt8Number
) + 67) {
985 if (!_cmsReadUInt16Number(io
, &ScriptCodeCode
)) goto Done
;
986 if (!_cmsReadUInt8Number(io
, &ScriptCodeCount
)) goto Done
;
989 for (i
=0; i
< 67; i
++) {
990 if (!io
->Read(io
, &Dummy
, sizeof(cmsUInt8Number
), 1)) goto Error
;
1000 if (Text
) _cmsFree(self
->ContextID
, (void*) Text
);
1001 if (mlu
) cmsMLUfree(mlu
);
1006 // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
1008 cmsBool
Type_Text_Description_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
1010 cmsMLU
* mlu
= (cmsMLU
*) Ptr
;
1012 wchar_t *Wide
= NULL
;
1013 cmsUInt32Number len
, len_text
, len_tag_requirement
, len_aligned
;
1017 // Used below for writing zeroes
1018 memset(Filler
, 0, sizeof(Filler
));
1020 // Get the len of string
1021 len
= cmsMLUgetASCII(mlu
, cmsNoLanguage
, cmsNoCountry
, NULL
, 0);
1023 // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data
1024 //(see clause 4.1 for the definition of 'aligned'). Because the Unicode language
1025 // code and Unicode count immediately follow the ASCII description, their
1026 // alignment is not correct if the ASCII count is not a multiple of four. The
1027 // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
1028 // writing software must be written carefully in order to handle these alignment
1031 // The above last sentence suggest to handle alignment issues in the
1032 // parser. The provided example (Table 69 on Page 60) makes this clear.
1033 // The padding only in the ASCII count is not sufficient for a aligned tag
1034 // size, with the same text size in ASCII and Unicode.
1039 Text
= (char*) _cmsDupMem(self
->ContextID
, "", sizeof(char));
1040 Wide
= (wchar_t*) _cmsDupMem(self
->ContextID
, L
"", sizeof(wchar_t));
1043 // Create independent buffers
1044 Text
= (char*) _cmsCalloc(self
->ContextID
, len
, sizeof(char));
1045 if (Text
== NULL
) goto Error
;
1047 Wide
= (wchar_t*) _cmsCalloc(self
->ContextID
, len
, sizeof(wchar_t));
1048 if (Wide
== NULL
) goto Error
;
1050 // Get both representations.
1051 cmsMLUgetASCII(mlu
, cmsNoLanguage
, cmsNoCountry
, Text
, len
* sizeof(char));
1052 cmsMLUgetWide(mlu
, cmsNoLanguage
, cmsNoCountry
, Wide
, len
* sizeof(wchar_t));
1055 // Tell the real text len including the null terminator and padding
1056 len_text
= (cmsUInt32Number
) strlen(Text
) + 1;
1057 // Compute an total tag size requirement
1058 len_tag_requirement
= (8+4+len_text
+4+4+2*len_text
+2+1+67);
1059 len_aligned
= _cmsALIGNLONG(len_tag_requirement
);
1061 // * cmsUInt32Number count; * Description length
1062 // * cmsInt8Number desc[count] * NULL terminated ascii string
1063 // * cmsUInt32Number ucLangCode; * UniCode language code
1064 // * cmsUInt32Number ucCount; * UniCode description length
1065 // * cmsInt16Number ucDesc[ucCount];* The UniCode description
1066 // * cmsUInt16Number scCode; * ScriptCode code
1067 // * cmsUInt8Number scCount; * ScriptCode count
1068 // * cmsInt8Number scDesc[67]; * ScriptCode Description
1070 if (!_cmsWriteUInt32Number(io
, len_text
)) goto Error
;
1071 if (!io
->Write(io
, len_text
, Text
)) goto Error
;
1073 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
; // ucLanguageCode
1075 if (!_cmsWriteUInt32Number(io
, len_text
)) goto Error
;
1076 // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
1077 if (!_cmsWriteWCharArray(io
, len_text
, Wide
)) goto Error
;
1079 // ScriptCode Code & count (unused)
1080 if (!_cmsWriteUInt16Number(io
, 0)) goto Error
;
1081 if (!_cmsWriteUInt8Number(io
, 0)) goto Error
;
1083 if (!io
->Write(io
, 67, Filler
)) goto Error
;
1085 // possibly add pad at the end of tag
1086 if(len_aligned
- len_tag_requirement
> 0)
1087 if (!io
->Write(io
, len_aligned
- len_tag_requirement
, Filler
)) goto Error
;
1092 if (Text
) _cmsFree(self
->ContextID
, Text
);
1093 if (Wide
) _cmsFree(self
->ContextID
, Wide
);
1097 cmsUNUSED_PARAMETER(nItems
);
1102 void* Type_Text_Description_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
1104 return (void*) cmsMLUdup((cmsMLU
*) Ptr
);
1106 cmsUNUSED_PARAMETER(n
);
1107 cmsUNUSED_PARAMETER(self
);
1111 void Type_Text_Description_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
1113 cmsMLU
* mlu
= (cmsMLU
*) Ptr
;
1118 cmsUNUSED_PARAMETER(self
);
1123 cmsTagTypeSignature
DecideTextDescType(cmsFloat64Number ICCVersion
, const void *Data
)
1125 if (ICCVersion
>= 4.0)
1126 return cmsSigMultiLocalizedUnicodeType
;
1128 return cmsSigTextDescriptionType
;
1130 cmsUNUSED_PARAMETER(Data
);
1134 // ********************************************************************************
1135 // Type cmsSigCurveType
1136 // ********************************************************************************
1139 void *Type_Curve_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
1141 cmsUInt32Number Count
;
1142 cmsToneCurve
* NewGamma
;
1145 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
1151 cmsFloat64Number SingleGamma
= 1.0;
1153 NewGamma
= cmsBuildParametricToneCurve(self
->ContextID
, 1, &SingleGamma
);
1154 if (!NewGamma
) return NULL
;
1159 case 1: // Specified as the exponent of gamma function
1161 cmsUInt16Number SingleGammaFixed
;
1162 cmsFloat64Number SingleGamma
;
1164 if (!_cmsReadUInt16Number(io
, &SingleGammaFixed
)) return NULL
;
1165 SingleGamma
= _cms8Fixed8toDouble(SingleGammaFixed
);
1168 return cmsBuildParametricToneCurve(self
->ContextID
, 1, &SingleGamma
);
1174 return NULL
; // This is to prevent bad guys for doing bad things
1176 NewGamma
= cmsBuildTabulatedToneCurve16(self
->ContextID
, Count
, NULL
);
1177 if (!NewGamma
) return NULL
;
1179 if (!_cmsReadUInt16Array(io
, Count
, NewGamma
-> Table16
)) {
1180 cmsFreeToneCurve(NewGamma
);
1188 cmsUNUSED_PARAMETER(SizeOfTag
);
1193 cmsBool
Type_Curve_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
1195 cmsToneCurve
* Curve
= (cmsToneCurve
*) Ptr
;
1197 if (Curve
->nSegments
== 1 && Curve
->Segments
[0].Type
== 1) {
1199 // Single gamma, preserve number
1200 cmsUInt16Number SingleGammaFixed
= _cmsDoubleTo8Fixed8(Curve
->Segments
[0].Params
[0]);
1202 if (!_cmsWriteUInt32Number(io
, 1)) return FALSE
;
1203 if (!_cmsWriteUInt16Number(io
, SingleGammaFixed
)) return FALSE
;
1208 if (!_cmsWriteUInt32Number(io
, Curve
->nEntries
)) return FALSE
;
1209 return _cmsWriteUInt16Array(io
, Curve
->nEntries
, Curve
->Table16
);
1211 cmsUNUSED_PARAMETER(nItems
);
1212 cmsUNUSED_PARAMETER(self
);
1217 void* Type_Curve_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
1219 return (void*) cmsDupToneCurve((cmsToneCurve
*) Ptr
);
1221 cmsUNUSED_PARAMETER(n
);
1222 cmsUNUSED_PARAMETER(self
);
1226 void Type_Curve_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
1228 cmsToneCurve
* gamma
= (cmsToneCurve
*) Ptr
;
1230 cmsFreeToneCurve(gamma
);
1233 cmsUNUSED_PARAMETER(self
);
1237 // ********************************************************************************
1238 // Type cmsSigParametricCurveType
1239 // ********************************************************************************
1242 // Decide which curve type to use on writing
1244 cmsTagTypeSignature
DecideCurveType(cmsFloat64Number ICCVersion
, const void *Data
)
1246 cmsToneCurve
* Curve
= (cmsToneCurve
*) Data
;
1248 if (ICCVersion
< 4.0) return cmsSigCurveType
;
1249 if (Curve
->nSegments
!= 1) return cmsSigCurveType
; // Only 1-segment curves can be saved as parametric
1250 if (Curve
->Segments
[0].Type
< 0) return cmsSigCurveType
; // Only non-inverted curves
1251 if (Curve
->Segments
[0].Type
> 5) return cmsSigCurveType
; // Only ICC parametric curves
1253 return cmsSigParametricCurveType
;
1257 void *Type_ParametricCurve_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
1259 static const int ParamsByType
[] = { 1, 3, 4, 5, 7 };
1260 cmsFloat64Number Params
[10];
1261 cmsUInt16Number Type
;
1263 cmsToneCurve
* NewGamma
;
1265 if (!_cmsReadUInt16Number(io
, &Type
)) return NULL
;
1266 if (!_cmsReadUInt16Number(io
, NULL
)) return NULL
; // Reserved
1270 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown parametric curve type '%d'", Type
);
1274 memset(Params
, 0, sizeof(Params
));
1275 n
= ParamsByType
[Type
];
1277 for (i
=0; i
< n
; i
++) {
1279 if (!_cmsRead15Fixed16Number(io
, &Params
[i
])) return NULL
;
1282 NewGamma
= cmsBuildParametricToneCurve(self
->ContextID
, Type
+1, Params
);
1287 cmsUNUSED_PARAMETER(SizeOfTag
);
1292 cmsBool
Type_ParametricCurve_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
1294 cmsToneCurve
* Curve
= (cmsToneCurve
*) Ptr
;
1295 int i
, nParams
, typen
;
1296 static const int ParamsByType
[] = { 0, 1, 3, 4, 5, 7 };
1298 typen
= Curve
-> Segments
[0].Type
;
1300 if (Curve
->nSegments
> 1 || typen
< 1) {
1302 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Multisegment or Inverted parametric curves cannot be written");
1307 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unsupported parametric curve");
1311 nParams
= ParamsByType
[typen
];
1313 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) (Curve
->Segments
[0].Type
- 1))) return FALSE
;
1314 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
; // Reserved
1316 for (i
=0; i
< nParams
; i
++) {
1318 if (!_cmsWrite15Fixed16Number(io
, Curve
-> Segments
[0].Params
[i
])) return FALSE
;
1323 cmsUNUSED_PARAMETER(nItems
);
1327 void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
1329 return (void*) cmsDupToneCurve((cmsToneCurve
*) Ptr
);
1331 cmsUNUSED_PARAMETER(n
);
1332 cmsUNUSED_PARAMETER(self
);
1336 void Type_ParametricCurve_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
1338 cmsToneCurve
* gamma
= (cmsToneCurve
*) Ptr
;
1340 cmsFreeToneCurve(gamma
);
1343 cmsUNUSED_PARAMETER(self
);
1347 // ********************************************************************************
1348 // Type cmsSigDateTimeType
1349 // ********************************************************************************
1351 // A 12-byte value representation of the time and date, where the byte usage is assigned
1352 // as specified in table 1. The actual values are encoded as 16-bit unsigned integers
1353 // (uInt16Number - see 5.1.6).
1355 // All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
1356 // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
1357 // time to UTC when setting these values. Programs that display these values may show
1358 // the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
1359 // display both UTC and local versions of the dateTimeNumber.
1362 void *Type_DateTime_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
1364 cmsDateTimeNumber timestamp
;
1365 struct tm
* NewDateTime
;
1368 NewDateTime
= (struct tm
*) _cmsMalloc(self
->ContextID
, sizeof(struct tm
));
1369 if (NewDateTime
== NULL
) return NULL
;
1371 if (io
->Read(io
, ×tamp
, sizeof(cmsDateTimeNumber
), 1) != 1) return NULL
;
1373 _cmsDecodeDateTimeNumber(×tamp
, NewDateTime
);
1378 cmsUNUSED_PARAMETER(SizeOfTag
);
1383 cmsBool
Type_DateTime_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
1385 struct tm
* DateTime
= (struct tm
*) Ptr
;
1386 cmsDateTimeNumber timestamp
;
1388 _cmsEncodeDateTimeNumber(×tamp
, DateTime
);
1389 if (!io
->Write(io
, sizeof(cmsDateTimeNumber
), ×tamp
)) return FALSE
;
1393 cmsUNUSED_PARAMETER(nItems
);
1394 cmsUNUSED_PARAMETER(self
);
1398 void* Type_DateTime_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
1400 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(struct tm
));
1402 cmsUNUSED_PARAMETER(n
);
1406 void Type_DateTime_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
1408 _cmsFree(self
->ContextID
, Ptr
);
1413 // ********************************************************************************
1414 // Type icMeasurementType
1415 // ********************************************************************************
1418 The measurementType information refers only to the internal profile data and is
1419 meant to provide profile makers an alternative to the default measurement
1424 void *Type_Measurement_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
1426 cmsICCMeasurementConditions mc
;
1429 memset(&mc
, 0, sizeof(mc
));
1431 if (!_cmsReadUInt32Number(io
, &mc
.Observer
)) return NULL
;
1432 if (!_cmsReadXYZNumber(io
, &mc
.Backing
)) return NULL
;
1433 if (!_cmsReadUInt32Number(io
, &mc
.Geometry
)) return NULL
;
1434 if (!_cmsRead15Fixed16Number(io
, &mc
.Flare
)) return NULL
;
1435 if (!_cmsReadUInt32Number(io
, &mc
.IlluminantType
)) return NULL
;
1438 return _cmsDupMem(self
->ContextID
, &mc
, sizeof(cmsICCMeasurementConditions
));
1440 cmsUNUSED_PARAMETER(SizeOfTag
);
1445 cmsBool
Type_Measurement_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
1447 cmsICCMeasurementConditions
* mc
=(cmsICCMeasurementConditions
*) Ptr
;
1449 if (!_cmsWriteUInt32Number(io
, mc
->Observer
)) return FALSE
;
1450 if (!_cmsWriteXYZNumber(io
, &mc
->Backing
)) return FALSE
;
1451 if (!_cmsWriteUInt32Number(io
, mc
->Geometry
)) return FALSE
;
1452 if (!_cmsWrite15Fixed16Number(io
, mc
->Flare
)) return FALSE
;
1453 if (!_cmsWriteUInt32Number(io
, mc
->IlluminantType
)) return FALSE
;
1457 cmsUNUSED_PARAMETER(nItems
);
1458 cmsUNUSED_PARAMETER(self
);
1462 void* Type_Measurement_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
1464 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsICCMeasurementConditions
));
1466 cmsUNUSED_PARAMETER(n
);
1470 void Type_Measurement_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
1472 _cmsFree(self
->ContextID
, Ptr
);
1476 // ********************************************************************************
1477 // Type cmsSigMultiLocalizedUnicodeType
1478 // ********************************************************************************
1480 // Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
1481 // Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
1482 // taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
1486 void *Type_MLU_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
1489 cmsUInt32Number Count
, RecLen
, NumOfWchar
;
1490 cmsUInt32Number SizeOfHeader
;
1491 cmsUInt32Number Len
, Offset
;
1494 cmsUInt32Number BeginOfThisString
, EndOfThisString
, LargestPosition
;
1497 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
1498 if (!_cmsReadUInt32Number(io
, &RecLen
)) return NULL
;
1502 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "multiLocalizedUnicodeType of len != 12 is not supported.");
1506 mlu
= cmsMLUalloc(self
->ContextID
, Count
);
1507 if (mlu
== NULL
) return NULL
;
1509 mlu
->UsedEntries
= Count
;
1511 SizeOfHeader
= 12 * Count
+ sizeof(_cmsTagBase
);
1512 LargestPosition
= 0;
1514 for (i
=0; i
< Count
; i
++) {
1516 if (!_cmsReadUInt16Number(io
, &mlu
->Entries
[i
].Language
)) goto Error
;
1517 if (!_cmsReadUInt16Number(io
, &mlu
->Entries
[i
].Country
)) goto Error
;
1519 // Now deal with Len and offset.
1520 if (!_cmsReadUInt32Number(io
, &Len
)) goto Error
;
1521 if (!_cmsReadUInt32Number(io
, &Offset
)) goto Error
;
1523 // Offset MUST be even because it indexes a block of utf16 chars.
1524 // Tricky profiles that uses odd positions will not work anyway
1525 // because the whole utf16 block is previously converted to wchar_t
1526 // and sizeof this type may be of 4 bytes. On Linux systems, for example.
1527 if (Offset
& 1) goto Error
;
1529 // Check for overflow
1530 if (Offset
< (SizeOfHeader
+ 8)) goto Error
;
1531 if (((Offset
+ Len
) < Len
) || ((Offset
+ Len
) > SizeOfTag
+ 8)) goto Error
;
1533 // True begin of the string
1534 BeginOfThisString
= Offset
- SizeOfHeader
- 8;
1536 // Adjust to wchar_t elements
1537 mlu
->Entries
[i
].Len
= (Len
* sizeof(wchar_t)) / sizeof(cmsUInt16Number
);
1538 mlu
->Entries
[i
].StrW
= (BeginOfThisString
* sizeof(wchar_t)) / sizeof(cmsUInt16Number
);
1540 // To guess maximum size, add offset + len
1541 EndOfThisString
= BeginOfThisString
+ Len
;
1542 if (EndOfThisString
> LargestPosition
)
1543 LargestPosition
= EndOfThisString
;
1546 // Now read the remaining of tag and fill all strings. Subtract the directory
1547 SizeOfTag
= (LargestPosition
* sizeof(wchar_t)) / sizeof(cmsUInt16Number
);
1556 // Make sure this is an even utf16 size.
1557 if (SizeOfTag
& 1) goto Error
;
1559 Block
= (wchar_t*) _cmsCalloc(self
->ContextID
, 1, SizeOfTag
);
1560 if (Block
== NULL
) goto Error
;
1562 NumOfWchar
= SizeOfTag
/ sizeof(wchar_t);
1563 if (!_cmsReadWCharArray(io
, NumOfWchar
, Block
)) {
1564 _cmsFree(self
->ContextID
, Block
);
1569 mlu
->MemPool
= Block
;
1570 mlu
->PoolSize
= SizeOfTag
;
1571 mlu
->PoolUsed
= SizeOfTag
;
1577 if (mlu
) cmsMLUfree(mlu
);
1582 cmsBool
Type_MLU_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
1584 cmsMLU
* mlu
=(cmsMLU
*) Ptr
;
1585 cmsUInt32Number HeaderSize
;
1586 cmsUInt32Number Len
, Offset
;
1591 // Empty placeholder
1592 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
1593 if (!_cmsWriteUInt32Number(io
, 12)) return FALSE
;
1597 if (!_cmsWriteUInt32Number(io
, mlu
->UsedEntries
)) return FALSE
;
1598 if (!_cmsWriteUInt32Number(io
, 12)) return FALSE
;
1600 HeaderSize
= 12 * mlu
->UsedEntries
+ sizeof(_cmsTagBase
);
1602 for (i
=0; i
< mlu
->UsedEntries
; i
++) {
1604 Len
= mlu
->Entries
[i
].Len
;
1605 Offset
= mlu
->Entries
[i
].StrW
;
1607 Len
= (Len
* sizeof(cmsUInt16Number
)) / sizeof(wchar_t);
1608 Offset
= (Offset
* sizeof(cmsUInt16Number
)) / sizeof(wchar_t) + HeaderSize
+ 8;
1610 if (!_cmsWriteUInt16Number(io
, mlu
->Entries
[i
].Language
)) return FALSE
;
1611 if (!_cmsWriteUInt16Number(io
, mlu
->Entries
[i
].Country
)) return FALSE
;
1612 if (!_cmsWriteUInt32Number(io
, Len
)) return FALSE
;
1613 if (!_cmsWriteUInt32Number(io
, Offset
)) return FALSE
;
1616 if (!_cmsWriteWCharArray(io
, mlu
->PoolUsed
/ sizeof(wchar_t), (wchar_t*) mlu
->MemPool
)) return FALSE
;
1620 cmsUNUSED_PARAMETER(nItems
);
1621 cmsUNUSED_PARAMETER(self
);
1626 void* Type_MLU_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
1628 return (void*) cmsMLUdup((cmsMLU
*) Ptr
);
1630 cmsUNUSED_PARAMETER(n
);
1631 cmsUNUSED_PARAMETER(self
);
1635 void Type_MLU_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
1637 cmsMLUfree((cmsMLU
*) Ptr
);
1640 cmsUNUSED_PARAMETER(self
);
1644 // ********************************************************************************
1645 // Type cmsSigLut8Type
1646 // ********************************************************************************
1648 // Decide which LUT type to use on writing
1650 cmsTagTypeSignature
DecideLUTtypeA2B(cmsFloat64Number ICCVersion
, const void *Data
)
1652 cmsPipeline
* Lut
= (cmsPipeline
*) Data
;
1654 if (ICCVersion
< 4.0) {
1655 if (Lut
->SaveAs8Bits
) return cmsSigLut8Type
;
1656 return cmsSigLut16Type
;
1659 return cmsSigLutAtoBType
;
1664 cmsTagTypeSignature
DecideLUTtypeB2A(cmsFloat64Number ICCVersion
, const void *Data
)
1666 cmsPipeline
* Lut
= (cmsPipeline
*) Data
;
1668 if (ICCVersion
< 4.0) {
1669 if (Lut
->SaveAs8Bits
) return cmsSigLut8Type
;
1670 return cmsSigLut16Type
;
1673 return cmsSigLutBtoAType
;
1678 This structure represents a colour transform using tables of 8-bit precision.
1679 This type contains four processing elements: a 3 by 3 matrix (which shall be
1680 the identity matrix unless the input colour space is XYZ), a set of one dimensional
1681 input tables, a multidimensional lookup table, and a set of one dimensional output
1682 tables. Data is processed using these elements via the following sequence:
1683 (matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables)
1685 Byte Position Field Length (bytes) Content Encoded as...
1686 8 1 Number of Input Channels (i) uInt8Number
1687 9 1 Number of Output Channels (o) uInt8Number
1688 10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number
1689 11 1 Reserved for padding (fill with 00h)
1691 12..15 4 Encoded e00 parameter s15Fixed16Number
1695 // Read 8 bit tables as gamma functions
1697 cmsBool
Read8bitTables(cmsContext ContextID
, cmsIOHANDLER
* io
, cmsPipeline
* lut
, cmsUInt32Number nChannels
)
1699 cmsUInt8Number
* Temp
= NULL
;
1700 cmsUInt32Number i
, j
;
1701 cmsToneCurve
* Tables
[cmsMAXCHANNELS
];
1703 if (nChannels
> cmsMAXCHANNELS
) return FALSE
;
1704 if (nChannels
<= 0) return FALSE
;
1706 memset(Tables
, 0, sizeof(Tables
));
1708 Temp
= (cmsUInt8Number
*) _cmsMalloc(ContextID
, 256);
1709 if (Temp
== NULL
) return FALSE
;
1711 for (i
=0; i
< nChannels
; i
++) {
1712 Tables
[i
] = cmsBuildTabulatedToneCurve16(ContextID
, 256, NULL
);
1713 if (Tables
[i
] == NULL
) goto Error
;
1716 for (i
=0; i
< nChannels
; i
++) {
1718 if (io
->Read(io
, Temp
, 256, 1) != 1) goto Error
;
1720 for (j
=0; j
< 256; j
++)
1721 Tables
[i
]->Table16
[j
] = (cmsUInt16Number
) FROM_8_TO_16(Temp
[j
]);
1724 _cmsFree(ContextID
, Temp
);
1727 if (!cmsPipelineInsertStage(lut
, cmsAT_END
, cmsStageAllocToneCurves(ContextID
, nChannels
, Tables
)))
1730 for (i
=0; i
< nChannels
; i
++)
1731 cmsFreeToneCurve(Tables
[i
]);
1736 for (i
=0; i
< nChannels
; i
++) {
1737 if (Tables
[i
]) cmsFreeToneCurve(Tables
[i
]);
1740 if (Temp
) _cmsFree(ContextID
, Temp
);
1746 cmsBool
Write8bitTables(cmsContext ContextID
, cmsIOHANDLER
* io
, cmsUInt32Number n
, _cmsStageToneCurvesData
* Tables
)
1752 for (i
=0; i
< n
; i
++) {
1756 // Usual case of identity curves
1757 if ((Tables
->TheCurves
[i
]->nEntries
== 2) &&
1758 (Tables
->TheCurves
[i
]->Table16
[0] == 0) &&
1759 (Tables
->TheCurves
[i
]->Table16
[1] == 65535)) {
1761 for (j
=0; j
< 256; j
++) {
1762 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) j
)) return FALSE
;
1766 if (Tables
->TheCurves
[i
]->nEntries
!= 256) {
1767 cmsSignalError(ContextID
, cmsERROR_RANGE
, "LUT8 needs 256 entries on prelinearization");
1771 for (j
=0; j
< 256; j
++) {
1773 val
= (cmsUInt8Number
) FROM_16_TO_8(Tables
->TheCurves
[i
]->Table16
[j
]);
1775 if (!_cmsWriteUInt8Number(io
, val
)) return FALSE
;
1785 cmsUInt32Number
uipow(cmsUInt32Number n
, cmsUInt32Number a
, cmsUInt32Number b
)
1787 cmsUInt32Number rv
= 1, rc
;
1789 if (a
== 0) return 0;
1790 if (n
== 0) return 0;
1792 for (; b
> 0; b
--) {
1796 // Check for overflow
1797 if (rv
> UINT_MAX
/ a
) return (cmsUInt32Number
) -1;
1803 if (rv
!= rc
/ n
) return (cmsUInt32Number
) -1;
1808 // That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
1809 // 8 bit lut may be scaled easily to v4 PCS, but we need also to properly adjust
1810 // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
1813 void *Type_LUT8_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
1815 cmsUInt8Number InputChannels
, OutputChannels
, CLUTpoints
;
1816 cmsUInt8Number
* Temp
= NULL
;
1817 cmsPipeline
* NewLUT
= NULL
;
1818 cmsUInt32Number nTabSize
, i
;
1819 cmsFloat64Number Matrix
[3*3];
1823 if (!_cmsReadUInt8Number(io
, &InputChannels
)) goto Error
;
1824 if (!_cmsReadUInt8Number(io
, &OutputChannels
)) goto Error
;
1825 if (!_cmsReadUInt8Number(io
, &CLUTpoints
)) goto Error
;
1827 if (CLUTpoints
== 1) goto Error
; // Impossible value, 0 for no CLUT and then 2 at least
1830 if (!_cmsReadUInt8Number(io
, NULL
)) goto Error
;
1833 if (InputChannels
== 0 || InputChannels
> cmsMAXCHANNELS
) goto Error
;
1834 if (OutputChannels
== 0 || OutputChannels
> cmsMAXCHANNELS
) goto Error
;
1836 // Allocates an empty Pipeline
1837 NewLUT
= cmsPipelineAlloc(self
->ContextID
, InputChannels
, OutputChannels
);
1838 if (NewLUT
== NULL
) goto Error
;
1841 if (!_cmsRead15Fixed16Number(io
, &Matrix
[0])) goto Error
;
1842 if (!_cmsRead15Fixed16Number(io
, &Matrix
[1])) goto Error
;
1843 if (!_cmsRead15Fixed16Number(io
, &Matrix
[2])) goto Error
;
1844 if (!_cmsRead15Fixed16Number(io
, &Matrix
[3])) goto Error
;
1845 if (!_cmsRead15Fixed16Number(io
, &Matrix
[4])) goto Error
;
1846 if (!_cmsRead15Fixed16Number(io
, &Matrix
[5])) goto Error
;
1847 if (!_cmsRead15Fixed16Number(io
, &Matrix
[6])) goto Error
;
1848 if (!_cmsRead15Fixed16Number(io
, &Matrix
[7])) goto Error
;
1849 if (!_cmsRead15Fixed16Number(io
, &Matrix
[8])) goto Error
;
1852 // Only operates if not identity...
1853 if ((InputChannels
== 3) && !_cmsMAT3isIdentity((cmsMAT3
*) Matrix
)) {
1855 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_BEGIN
, cmsStageAllocMatrix(self
->ContextID
, 3, 3, Matrix
, NULL
)))
1860 if (!Read8bitTables(self
->ContextID
, io
, NewLUT
, InputChannels
)) goto Error
;
1862 // Get 3D CLUT. Check the overflow....
1863 nTabSize
= uipow(OutputChannels
, CLUTpoints
, InputChannels
);
1864 if (nTabSize
== (cmsUInt32Number
) -1) goto Error
;
1867 cmsUInt16Number
*PtrW
, *T
;
1869 PtrW
= T
= (cmsUInt16Number
*) _cmsCalloc(self
->ContextID
, nTabSize
, sizeof(cmsUInt16Number
));
1870 if (T
== NULL
) goto Error
;
1872 Temp
= (cmsUInt8Number
*) _cmsMalloc(self
->ContextID
, nTabSize
);
1874 _cmsFree(self
->ContextID
, T
);
1878 if (io
->Read(io
, Temp
, nTabSize
, 1) != 1) {
1879 _cmsFree(self
->ContextID
, T
);
1880 _cmsFree(self
->ContextID
, Temp
);
1884 for (i
= 0; i
< nTabSize
; i
++) {
1886 *PtrW
++ = FROM_8_TO_16(Temp
[i
]);
1888 _cmsFree(self
->ContextID
, Temp
);
1891 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, cmsStageAllocCLut16bit(self
->ContextID
, CLUTpoints
, InputChannels
, OutputChannels
, T
))) {
1892 _cmsFree(self
->ContextID
, T
);
1895 _cmsFree(self
->ContextID
, T
);
1899 // Get output tables
1900 if (!Read8bitTables(self
->ContextID
, io
, NewLUT
, OutputChannels
)) goto Error
;
1906 if (NewLUT
!= NULL
) cmsPipelineFree(NewLUT
);
1909 cmsUNUSED_PARAMETER(SizeOfTag
);
1912 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1914 cmsBool
Type_LUT8_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
1916 cmsUInt32Number j
, nTabSize
, i
;
1918 cmsPipeline
* NewLUT
= (cmsPipeline
*) Ptr
;
1920 _cmsStageToneCurvesData
* PreMPE
= NULL
, *PostMPE
= NULL
;
1921 _cmsStageMatrixData
* MatMPE
= NULL
;
1922 _cmsStageCLutData
* clut
= NULL
;
1923 cmsUInt32Number clutPoints
;
1925 // Disassemble the LUT into components.
1926 mpe
= NewLUT
-> Elements
;
1927 if (mpe
->Type
== cmsSigMatrixElemType
) {
1929 if (mpe
->InputChannels
!= 3 || mpe
->OutputChannels
!= 3) return FALSE
;
1930 MatMPE
= (_cmsStageMatrixData
*) mpe
->Data
;
1934 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCurveSetElemType
) {
1935 PreMPE
= (_cmsStageToneCurvesData
*) mpe
->Data
;
1939 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCLutElemType
) {
1940 clut
= (_cmsStageCLutData
*) mpe
-> Data
;
1944 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCurveSetElemType
) {
1945 PostMPE
= (_cmsStageToneCurvesData
*) mpe
->Data
;
1949 // That should be all
1951 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "LUT is not suitable to be saved as LUT8");
1958 // Lut8 only allows same CLUT points in all dimensions
1959 clutPoints
= clut
->Params
->nSamples
[0];
1960 for (i
= 1; i
< cmsPipelineInputChannels(NewLUT
); i
++) {
1961 if (clut
->Params
->nSamples
[i
] != clutPoints
) {
1962 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "LUT with different samples per dimension not suitable to be saved as LUT16");
1968 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
)cmsPipelineInputChannels(NewLUT
))) return FALSE
;
1969 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
)cmsPipelineOutputChannels(NewLUT
))) return FALSE
;
1970 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) clutPoints
)) return FALSE
;
1971 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
; // Padding
1973 if (MatMPE
!= NULL
) {
1975 for (i
= 0; i
< 9; i
++)
1977 if (!_cmsWrite15Fixed16Number(io
, MatMPE
->Double
[i
])) return FALSE
;
1982 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
1983 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1984 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1985 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1986 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
1987 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1988 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1989 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1990 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
1993 // The prelinearization table
1994 if (!Write8bitTables(self
->ContextID
, io
, NewLUT
->InputChannels
, PreMPE
)) return FALSE
;
1996 nTabSize
= uipow(NewLUT
->OutputChannels
, clutPoints
, NewLUT
->InputChannels
);
1997 if (nTabSize
== (cmsUInt32Number
) -1) return FALSE
;
2003 for (j
=0; j
< nTabSize
; j
++) {
2005 val
= (cmsUInt8Number
) FROM_16_TO_8(clut
->Tab
.T
[j
]);
2006 if (!_cmsWriteUInt8Number(io
, val
)) return FALSE
;
2011 // The postlinearization table
2012 if (!Write8bitTables(self
->ContextID
, io
, NewLUT
->OutputChannels
, PostMPE
)) return FALSE
;
2016 cmsUNUSED_PARAMETER(nItems
);
2021 void* Type_LUT8_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
2023 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
2025 cmsUNUSED_PARAMETER(n
);
2026 cmsUNUSED_PARAMETER(self
);
2030 void Type_LUT8_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
2032 cmsPipelineFree((cmsPipeline
*) Ptr
);
2035 cmsUNUSED_PARAMETER(self
);
2038 // ********************************************************************************
2039 // Type cmsSigLut16Type
2040 // ********************************************************************************
2042 // Read 16 bit tables as gamma functions
2044 cmsBool
Read16bitTables(cmsContext ContextID
, cmsIOHANDLER
* io
, cmsPipeline
* lut
,
2045 cmsUInt32Number nChannels
, cmsUInt32Number nEntries
)
2048 cmsToneCurve
* Tables
[cmsMAXCHANNELS
];
2050 // Maybe an empty table? (this is a lcms extension)
2051 if (nEntries
<= 0) return TRUE
;
2053 // Check for malicious profiles
2054 if (nEntries
< 2) return FALSE
;
2055 if (nChannels
> cmsMAXCHANNELS
) return FALSE
;
2057 // Init table to zero
2058 memset(Tables
, 0, sizeof(Tables
));
2060 for (i
=0; i
< nChannels
; i
++) {
2062 Tables
[i
] = cmsBuildTabulatedToneCurve16(ContextID
, nEntries
, NULL
);
2063 if (Tables
[i
] == NULL
) goto Error
;
2065 if (!_cmsReadUInt16Array(io
, nEntries
, Tables
[i
]->Table16
)) goto Error
;
2069 // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code)
2070 if (!cmsPipelineInsertStage(lut
, cmsAT_END
, cmsStageAllocToneCurves(ContextID
, nChannels
, Tables
)))
2073 for (i
=0; i
< nChannels
; i
++)
2074 cmsFreeToneCurve(Tables
[i
]);
2079 for (i
=0; i
< nChannels
; i
++) {
2080 if (Tables
[i
]) cmsFreeToneCurve(Tables
[i
]);
2087 cmsBool
Write16bitTables(cmsContext ContextID
, cmsIOHANDLER
* io
, _cmsStageToneCurvesData
* Tables
)
2091 cmsUInt16Number val
;
2092 cmsUInt32Number nEntries
;
2094 _cmsAssert(Tables
!= NULL
);
2096 for (i
=0; i
< Tables
->nCurves
; i
++) {
2098 nEntries
= Tables
->TheCurves
[i
]->nEntries
;
2100 for (j
=0; j
< nEntries
; j
++) {
2102 val
= Tables
->TheCurves
[i
]->Table16
[j
];
2103 if (!_cmsWriteUInt16Number(io
, val
)) return FALSE
;
2108 cmsUNUSED_PARAMETER(ContextID
);
2112 void *Type_LUT16_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
2114 cmsUInt8Number InputChannels
, OutputChannels
, CLUTpoints
;
2115 cmsPipeline
* NewLUT
= NULL
;
2116 cmsUInt32Number nTabSize
;
2117 cmsFloat64Number Matrix
[3*3];
2118 cmsUInt16Number InputEntries
, OutputEntries
;
2122 if (!_cmsReadUInt8Number(io
, &InputChannels
)) return NULL
;
2123 if (!_cmsReadUInt8Number(io
, &OutputChannels
)) return NULL
;
2124 if (!_cmsReadUInt8Number(io
, &CLUTpoints
)) return NULL
; // 255 maximum
2127 if (!_cmsReadUInt8Number(io
, NULL
)) return NULL
;
2130 if (InputChannels
== 0 || InputChannels
> cmsMAXCHANNELS
) goto Error
;
2131 if (OutputChannels
== 0 || OutputChannels
> cmsMAXCHANNELS
) goto Error
;
2133 // Allocates an empty LUT
2134 NewLUT
= cmsPipelineAlloc(self
->ContextID
, InputChannels
, OutputChannels
);
2135 if (NewLUT
== NULL
) goto Error
;
2138 if (!_cmsRead15Fixed16Number(io
, &Matrix
[0])) goto Error
;
2139 if (!_cmsRead15Fixed16Number(io
, &Matrix
[1])) goto Error
;
2140 if (!_cmsRead15Fixed16Number(io
, &Matrix
[2])) goto Error
;
2141 if (!_cmsRead15Fixed16Number(io
, &Matrix
[3])) goto Error
;
2142 if (!_cmsRead15Fixed16Number(io
, &Matrix
[4])) goto Error
;
2143 if (!_cmsRead15Fixed16Number(io
, &Matrix
[5])) goto Error
;
2144 if (!_cmsRead15Fixed16Number(io
, &Matrix
[6])) goto Error
;
2145 if (!_cmsRead15Fixed16Number(io
, &Matrix
[7])) goto Error
;
2146 if (!_cmsRead15Fixed16Number(io
, &Matrix
[8])) goto Error
;
2149 // Only operates on 3 channels
2150 if ((InputChannels
== 3) && !_cmsMAT3isIdentity((cmsMAT3
*) Matrix
)) {
2152 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, cmsStageAllocMatrix(self
->ContextID
, 3, 3, Matrix
, NULL
)))
2156 if (!_cmsReadUInt16Number(io
, &InputEntries
)) goto Error
;
2157 if (!_cmsReadUInt16Number(io
, &OutputEntries
)) goto Error
;
2159 if (InputEntries
> 0x7FFF || OutputEntries
> 0x7FFF) goto Error
;
2160 if (CLUTpoints
== 1) goto Error
; // Impossible value, 0 for no CLUT and then 2 at least
2163 if (!Read16bitTables(self
->ContextID
, io
, NewLUT
, InputChannels
, InputEntries
)) goto Error
;
2166 nTabSize
= uipow(OutputChannels
, CLUTpoints
, InputChannels
);
2167 if (nTabSize
== (cmsUInt32Number
) -1) goto Error
;
2172 T
= (cmsUInt16Number
*) _cmsCalloc(self
->ContextID
, nTabSize
, sizeof(cmsUInt16Number
));
2173 if (T
== NULL
) goto Error
;
2175 if (!_cmsReadUInt16Array(io
, nTabSize
, T
)) {
2176 _cmsFree(self
->ContextID
, T
);
2180 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, cmsStageAllocCLut16bit(self
->ContextID
, CLUTpoints
, InputChannels
, OutputChannels
, T
))) {
2181 _cmsFree(self
->ContextID
, T
);
2184 _cmsFree(self
->ContextID
, T
);
2188 // Get output tables
2189 if (!Read16bitTables(self
->ContextID
, io
, NewLUT
, OutputChannels
, OutputEntries
)) goto Error
;
2195 if (NewLUT
!= NULL
) cmsPipelineFree(NewLUT
);
2198 cmsUNUSED_PARAMETER(SizeOfTag
);
2201 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
2202 // Some empty defaults are created for missing parts
2205 cmsBool
Type_LUT16_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
2207 cmsUInt32Number nTabSize
;
2208 cmsPipeline
* NewLUT
= (cmsPipeline
*) Ptr
;
2210 _cmsStageToneCurvesData
* PreMPE
= NULL
, *PostMPE
= NULL
;
2211 _cmsStageMatrixData
* MatMPE
= NULL
;
2212 _cmsStageCLutData
* clut
= NULL
;
2213 cmsUInt32Number i
, InputChannels
, OutputChannels
, clutPoints
;
2215 // Disassemble the LUT into components.
2216 mpe
= NewLUT
-> Elements
;
2217 if (mpe
!= NULL
&& mpe
->Type
== cmsSigMatrixElemType
) {
2219 MatMPE
= (_cmsStageMatrixData
*) mpe
->Data
;
2220 if (mpe
->InputChannels
!= 3 || mpe
->OutputChannels
!= 3) return FALSE
;
2225 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCurveSetElemType
) {
2226 PreMPE
= (_cmsStageToneCurvesData
*) mpe
->Data
;
2230 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCLutElemType
) {
2231 clut
= (_cmsStageCLutData
*) mpe
-> Data
;
2235 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCurveSetElemType
) {
2236 PostMPE
= (_cmsStageToneCurvesData
*) mpe
->Data
;
2240 // That should be all
2242 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "LUT is not suitable to be saved as LUT16");
2246 InputChannels
= cmsPipelineInputChannels(NewLUT
);
2247 OutputChannels
= cmsPipelineOutputChannels(NewLUT
);
2252 // Lut16 only allows same CLUT points in all dimensions
2253 clutPoints
= clut
->Params
->nSamples
[0];
2254 for (i
= 1; i
< InputChannels
; i
++) {
2255 if (clut
->Params
->nSamples
[i
] != clutPoints
) {
2256 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "LUT with different samples per dimension not suitable to be saved as LUT16");
2262 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) InputChannels
)) return FALSE
;
2263 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) OutputChannels
)) return FALSE
;
2264 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) clutPoints
)) return FALSE
;
2265 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
; // Padding
2267 if (MatMPE
!= NULL
) {
2269 for (i
= 0; i
< 9; i
++)
2271 if (!_cmsWrite15Fixed16Number(io
, MatMPE
->Double
[i
])) return FALSE
;
2277 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
2278 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2279 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2280 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2281 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
2282 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2283 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2284 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2285 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
2289 if (PreMPE
!= NULL
) {
2290 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) PreMPE
->TheCurves
[0]->nEntries
)) return FALSE
;
2292 if (!_cmsWriteUInt16Number(io
, 2)) return FALSE
;
2295 if (PostMPE
!= NULL
) {
2296 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) PostMPE
->TheCurves
[0]->nEntries
)) return FALSE
;
2298 if (!_cmsWriteUInt16Number(io
, 2)) return FALSE
;
2302 // The prelinearization table
2304 if (PreMPE
!= NULL
) {
2305 if (!Write16bitTables(self
->ContextID
, io
, PreMPE
)) return FALSE
;
2308 for (i
=0; i
< InputChannels
; i
++) {
2310 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
;
2311 if (!_cmsWriteUInt16Number(io
, 0xffff)) return FALSE
;
2315 nTabSize
= uipow(OutputChannels
, clutPoints
, InputChannels
);
2316 if (nTabSize
== (cmsUInt32Number
) -1) return FALSE
;
2320 if (!_cmsWriteUInt16Array(io
, nTabSize
, clut
->Tab
.T
)) return FALSE
;
2324 // The postlinearization table
2325 if (PostMPE
!= NULL
) {
2326 if (!Write16bitTables(self
->ContextID
, io
, PostMPE
)) return FALSE
;
2329 for (i
=0; i
< OutputChannels
; i
++) {
2331 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
;
2332 if (!_cmsWriteUInt16Number(io
, 0xffff)) return FALSE
;
2338 cmsUNUSED_PARAMETER(nItems
);
2342 void* Type_LUT16_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
2344 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
2346 cmsUNUSED_PARAMETER(n
);
2347 cmsUNUSED_PARAMETER(self
);
2351 void Type_LUT16_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
2353 cmsPipelineFree((cmsPipeline
*) Ptr
);
2356 cmsUNUSED_PARAMETER(self
);
2360 // ********************************************************************************
2361 // Type cmsSigLutAToBType
2362 // ********************************************************************************
2365 // V4 stuff. Read matrix for LutAtoB and LutBtoA
2368 cmsStage
* ReadMatrix(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number Offset
)
2370 cmsFloat64Number dMat
[3*3];
2371 cmsFloat64Number dOff
[3];
2375 if (!io
-> Seek(io
, Offset
)) return NULL
;
2378 if (!_cmsRead15Fixed16Number(io
, &dMat
[0])) return NULL
;
2379 if (!_cmsRead15Fixed16Number(io
, &dMat
[1])) return NULL
;
2380 if (!_cmsRead15Fixed16Number(io
, &dMat
[2])) return NULL
;
2381 if (!_cmsRead15Fixed16Number(io
, &dMat
[3])) return NULL
;
2382 if (!_cmsRead15Fixed16Number(io
, &dMat
[4])) return NULL
;
2383 if (!_cmsRead15Fixed16Number(io
, &dMat
[5])) return NULL
;
2384 if (!_cmsRead15Fixed16Number(io
, &dMat
[6])) return NULL
;
2385 if (!_cmsRead15Fixed16Number(io
, &dMat
[7])) return NULL
;
2386 if (!_cmsRead15Fixed16Number(io
, &dMat
[8])) return NULL
;
2388 if (!_cmsRead15Fixed16Number(io
, &dOff
[0])) return NULL
;
2389 if (!_cmsRead15Fixed16Number(io
, &dOff
[1])) return NULL
;
2390 if (!_cmsRead15Fixed16Number(io
, &dOff
[2])) return NULL
;
2392 Mat
= cmsStageAllocMatrix(self
->ContextID
, 3, 3, dMat
, dOff
);
2400 // V4 stuff. Read CLUT part for LutAtoB and LutBtoA
2403 cmsStage
* ReadCLUT(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
,
2404 cmsUInt32Number Offset
, cmsUInt32Number InputChannels
, cmsUInt32Number OutputChannels
)
2406 cmsUInt8Number gridPoints8
[cmsMAXCHANNELS
]; // Number of grid points in each dimension.
2407 cmsUInt32Number GridPoints
[cmsMAXCHANNELS
], i
;
2408 cmsUInt8Number Precision
;
2410 _cmsStageCLutData
* Data
;
2412 if (!io
-> Seek(io
, Offset
)) return NULL
;
2413 if (io
-> Read(io
, gridPoints8
, cmsMAXCHANNELS
, 1) != 1) return NULL
;
2416 for (i
=0; i
< cmsMAXCHANNELS
; i
++) {
2418 if (gridPoints8
[i
] == 1) return NULL
; // Impossible value, 0 for no CLUT and then 2 at least
2419 GridPoints
[i
] = gridPoints8
[i
];
2422 if (!_cmsReadUInt8Number(io
, &Precision
)) return NULL
;
2424 if (!_cmsReadUInt8Number(io
, NULL
)) return NULL
;
2425 if (!_cmsReadUInt8Number(io
, NULL
)) return NULL
;
2426 if (!_cmsReadUInt8Number(io
, NULL
)) return NULL
;
2428 CLUT
= cmsStageAllocCLut16bitGranular(self
->ContextID
, GridPoints
, InputChannels
, OutputChannels
, NULL
);
2429 if (CLUT
== NULL
) return NULL
;
2431 Data
= (_cmsStageCLutData
*) CLUT
->Data
;
2433 // Precision can be 1 or 2 bytes
2434 if (Precision
== 1) {
2438 for (i
=0; i
< Data
->nEntries
; i
++) {
2440 if (io
->Read(io
, &v
, sizeof(cmsUInt8Number
), 1) != 1) {
2444 Data
->Tab
.T
[i
] = FROM_8_TO_16(v
);
2449 if (Precision
== 2) {
2451 if (!_cmsReadUInt16Array(io
, Data
->nEntries
, Data
->Tab
.T
)) {
2458 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown precision of '%d'", Precision
);
2466 cmsToneCurve
* ReadEmbeddedCurve(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
)
2468 cmsTagTypeSignature BaseType
;
2469 cmsUInt32Number nItems
;
2471 BaseType
= _cmsReadTypeBase(io
);
2474 case cmsSigCurveType
:
2475 return (cmsToneCurve
*) Type_Curve_Read(self
, io
, &nItems
, 0);
2477 case cmsSigParametricCurveType
:
2478 return (cmsToneCurve
*) Type_ParametricCurve_Read(self
, io
, &nItems
, 0);
2484 _cmsTagSignature2String(String
, (cmsTagSignature
) BaseType
);
2485 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown curve type '%s'", String
);
2492 // Read a set of curves from specific offset
2494 cmsStage
* ReadSetOfCurves(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number Offset
, cmsUInt32Number nCurves
)
2496 cmsToneCurve
* Curves
[cmsMAXCHANNELS
];
2498 cmsStage
* Lin
= NULL
;
2500 if (nCurves
> cmsMAXCHANNELS
) return FALSE
;
2502 if (!io
-> Seek(io
, Offset
)) return FALSE
;
2504 for (i
=0; i
< nCurves
; i
++)
2507 for (i
=0; i
< nCurves
; i
++) {
2509 Curves
[i
] = ReadEmbeddedCurve(self
, io
);
2510 if (Curves
[i
] == NULL
) goto Error
;
2511 if (!_cmsReadAlignment(io
)) goto Error
;
2515 Lin
= cmsStageAllocToneCurves(self
->ContextID
, nCurves
, Curves
);
2518 for (i
=0; i
< nCurves
; i
++)
2519 cmsFreeToneCurve(Curves
[i
]);
2527 // This structure represents a colour transform. The type contains up to five processing
2528 // elements which are stored in the AtoBTag tag in the following order: a set of one
2529 // dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves,
2530 // a multidimensional lookup table, and a set of one dimensional output curves.
2531 // Data are processed using these elements via the following sequence:
2533 //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves).
2536 It is possible to use any or all of these processing elements. At least one processing element
2537 must be included.Only the following combinations are allowed:
2542 A - CLUT - M - Matrix - B
2547 void* Type_LUTA2B_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
2549 cmsUInt32Number BaseOffset
;
2550 cmsUInt8Number inputChan
; // Number of input channels
2551 cmsUInt8Number outputChan
; // Number of output channels
2552 cmsUInt32Number offsetB
; // Offset to first "B" curve
2553 cmsUInt32Number offsetMat
; // Offset to matrix
2554 cmsUInt32Number offsetM
; // Offset to first "M" curve
2555 cmsUInt32Number offsetC
; // Offset to CLUT
2556 cmsUInt32Number offsetA
; // Offset to first "A" curve
2557 cmsPipeline
* NewLUT
= NULL
;
2560 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
2562 if (!_cmsReadUInt8Number(io
, &inputChan
)) return NULL
;
2563 if (!_cmsReadUInt8Number(io
, &outputChan
)) return NULL
;
2565 if (!_cmsReadUInt16Number(io
, NULL
)) return NULL
;
2567 if (!_cmsReadUInt32Number(io
, &offsetB
)) return NULL
;
2568 if (!_cmsReadUInt32Number(io
, &offsetMat
)) return NULL
;
2569 if (!_cmsReadUInt32Number(io
, &offsetM
)) return NULL
;
2570 if (!_cmsReadUInt32Number(io
, &offsetC
)) return NULL
;
2571 if (!_cmsReadUInt32Number(io
, &offsetA
)) return NULL
;
2573 if (inputChan
== 0 || inputChan
>= cmsMAXCHANNELS
) return NULL
;
2574 if (outputChan
== 0 || outputChan
>= cmsMAXCHANNELS
) return NULL
;
2576 // Allocates an empty LUT
2577 NewLUT
= cmsPipelineAlloc(self
->ContextID
, inputChan
, outputChan
);
2578 if (NewLUT
== NULL
) return NULL
;
2581 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetA
, inputChan
)))
2586 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadCLUT(self
, io
, BaseOffset
+ offsetC
, inputChan
, outputChan
)))
2591 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetM
, outputChan
)))
2595 if (offsetMat
!= 0) {
2596 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadMatrix(self
, io
, BaseOffset
+ offsetMat
)))
2601 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetB
, outputChan
)))
2608 cmsPipelineFree(NewLUT
);
2611 cmsUNUSED_PARAMETER(SizeOfTag
);
2614 // Write a set of curves
2616 cmsBool
WriteMatrix(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsStage
* mpe
)
2618 cmsUInt32Number i
, n
;
2620 _cmsStageMatrixData
* m
= (_cmsStageMatrixData
*) mpe
-> Data
;
2622 n
= mpe
->InputChannels
* mpe
->OutputChannels
;
2625 for (i
= 0; i
< n
; i
++)
2627 if (!_cmsWrite15Fixed16Number(io
, m
->Double
[i
])) return FALSE
;
2630 if (m
->Offset
!= NULL
) {
2632 for (i
= 0; i
< mpe
->OutputChannels
; i
++)
2634 if (!_cmsWrite15Fixed16Number(io
, m
->Offset
[i
])) return FALSE
;
2638 for (i
= 0; i
< mpe
->OutputChannels
; i
++)
2640 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2647 cmsUNUSED_PARAMETER(self
);
2651 // Write a set of curves
2653 cmsBool
WriteSetOfCurves(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsTagTypeSignature Type
, cmsStage
* mpe
)
2655 cmsUInt32Number i
, n
;
2656 cmsTagTypeSignature CurrentType
;
2657 cmsToneCurve
** Curves
;
2660 n
= cmsStageOutputChannels(mpe
);
2661 Curves
= _cmsStageGetPtrToCurveSet(mpe
);
2663 for (i
=0; i
< n
; i
++) {
2665 // If this is a table-based curve, use curve type even on V4
2668 if ((Curves
[i
] ->nSegments
== 0)||
2669 ((Curves
[i
]->nSegments
== 2) && (Curves
[i
] ->Segments
[1].Type
== 0)) )
2670 CurrentType
= cmsSigCurveType
;
2672 if (Curves
[i
] ->Segments
[0].Type
< 0)
2673 CurrentType
= cmsSigCurveType
;
2675 if (!_cmsWriteTypeBase(io
, CurrentType
)) return FALSE
;
2677 switch (CurrentType
) {
2679 case cmsSigCurveType
:
2680 if (!Type_Curve_Write(self
, io
, Curves
[i
], 1)) return FALSE
;
2683 case cmsSigParametricCurveType
:
2684 if (!Type_ParametricCurve_Write(self
, io
, Curves
[i
], 1)) return FALSE
;
2691 _cmsTagSignature2String(String
, (cmsTagSignature
) Type
);
2692 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown curve type '%s'", String
);
2697 if (!_cmsWriteAlignment(io
)) return FALSE
;
2706 cmsBool
WriteCLUT(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt8Number Precision
, cmsStage
* mpe
)
2708 cmsUInt8Number gridPoints
[cmsMAXCHANNELS
]; // Number of grid points in each dimension.
2710 _cmsStageCLutData
* CLUT
= ( _cmsStageCLutData
*) mpe
-> Data
;
2712 if (CLUT
->HasFloatValues
) {
2713 cmsSignalError(self
->ContextID
, cmsERROR_NOT_SUITABLE
, "Cannot save floating point data, CLUT are 8 or 16 bit only");
2717 memset(gridPoints
, 0, sizeof(gridPoints
));
2718 for (i
=0; i
< (cmsUInt32Number
) CLUT
->Params
->nInputs
; i
++)
2719 gridPoints
[i
] = (cmsUInt8Number
) CLUT
->Params
->nSamples
[i
];
2721 if (!io
-> Write(io
, cmsMAXCHANNELS
*sizeof(cmsUInt8Number
), gridPoints
)) return FALSE
;
2723 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) Precision
)) return FALSE
;
2724 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
;
2725 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
;
2726 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
;
2728 // Precision can be 1 or 2 bytes
2729 if (Precision
== 1) {
2731 for (i
=0; i
< CLUT
->nEntries
; i
++) {
2733 if (!_cmsWriteUInt8Number(io
, FROM_16_TO_8(CLUT
->Tab
.T
[i
]))) return FALSE
;
2737 if (Precision
== 2) {
2739 if (!_cmsWriteUInt16Array(io
, CLUT
->nEntries
, CLUT
->Tab
.T
)) return FALSE
;
2742 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown precision of '%d'", Precision
);
2746 if (!_cmsWriteAlignment(io
)) return FALSE
;
2755 cmsBool
Type_LUTA2B_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
2757 cmsPipeline
* Lut
= (cmsPipeline
*) Ptr
;
2758 cmsUInt32Number inputChan
, outputChan
;
2759 cmsStage
*A
= NULL
, *B
= NULL
, *M
= NULL
;
2760 cmsStage
* Matrix
= NULL
;
2761 cmsStage
* CLUT
= NULL
;
2762 cmsUInt32Number offsetB
= 0, offsetMat
= 0, offsetM
= 0, offsetC
= 0, offsetA
= 0;
2763 cmsUInt32Number BaseOffset
, DirectoryPos
, CurrentPos
;
2765 // Get the base for all offsets
2766 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
2768 if (Lut
->Elements
!= NULL
)
2769 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 1, cmsSigCurveSetElemType
, &B
))
2770 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 3, cmsSigCurveSetElemType
, cmsSigMatrixElemType
, cmsSigCurveSetElemType
, &M
, &Matrix
, &B
))
2771 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 3, cmsSigCurveSetElemType
, cmsSigCLutElemType
, cmsSigCurveSetElemType
, &A
, &CLUT
, &B
))
2772 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 5, cmsSigCurveSetElemType
, cmsSigCLutElemType
, cmsSigCurveSetElemType
,
2773 cmsSigMatrixElemType
, cmsSigCurveSetElemType
, &A
, &CLUT
, &M
, &Matrix
, &B
)) {
2775 cmsSignalError(self
->ContextID
, cmsERROR_NOT_SUITABLE
, "LUT is not suitable to be saved as LutAToB");
2779 // Get input, output channels
2780 inputChan
= cmsPipelineInputChannels(Lut
);
2781 outputChan
= cmsPipelineOutputChannels(Lut
);
2783 // Write channel count
2784 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) inputChan
)) return FALSE
;
2785 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) outputChan
)) return FALSE
;
2786 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
;
2788 // Keep directory to be filled latter
2789 DirectoryPos
= io
->Tell(io
);
2791 // Write the directory
2792 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2793 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2794 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2795 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2796 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2800 offsetA
= io
->Tell(io
) - BaseOffset
;
2801 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, A
)) return FALSE
;
2805 offsetC
= io
->Tell(io
) - BaseOffset
;
2806 if (!WriteCLUT(self
, io
, (Lut
->SaveAs8Bits
? 1U : 2U), CLUT
)) return FALSE
;
2811 offsetM
= io
->Tell(io
) - BaseOffset
;
2812 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, M
)) return FALSE
;
2815 if (Matrix
!= NULL
) {
2816 offsetMat
= io
->Tell(io
) - BaseOffset
;
2817 if (!WriteMatrix(self
, io
, Matrix
)) return FALSE
;
2822 offsetB
= io
->Tell(io
) - BaseOffset
;
2823 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, B
)) return FALSE
;
2826 CurrentPos
= io
->Tell(io
);
2828 if (!io
->Seek(io
, DirectoryPos
)) return FALSE
;
2830 if (!_cmsWriteUInt32Number(io
, offsetB
)) return FALSE
;
2831 if (!_cmsWriteUInt32Number(io
, offsetMat
)) return FALSE
;
2832 if (!_cmsWriteUInt32Number(io
, offsetM
)) return FALSE
;
2833 if (!_cmsWriteUInt32Number(io
, offsetC
)) return FALSE
;
2834 if (!_cmsWriteUInt32Number(io
, offsetA
)) return FALSE
;
2836 if (!io
->Seek(io
, CurrentPos
)) return FALSE
;
2840 cmsUNUSED_PARAMETER(nItems
);
2845 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
2847 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
2849 cmsUNUSED_PARAMETER(n
);
2850 cmsUNUSED_PARAMETER(self
);
2854 void Type_LUTA2B_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
2856 cmsPipelineFree((cmsPipeline
*) Ptr
);
2859 cmsUNUSED_PARAMETER(self
);
2866 void* Type_LUTB2A_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
2868 cmsUInt8Number inputChan
; // Number of input channels
2869 cmsUInt8Number outputChan
; // Number of output channels
2870 cmsUInt32Number BaseOffset
; // Actual position in file
2871 cmsUInt32Number offsetB
; // Offset to first "B" curve
2872 cmsUInt32Number offsetMat
; // Offset to matrix
2873 cmsUInt32Number offsetM
; // Offset to first "M" curve
2874 cmsUInt32Number offsetC
; // Offset to CLUT
2875 cmsUInt32Number offsetA
; // Offset to first "A" curve
2876 cmsPipeline
* NewLUT
= NULL
;
2879 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
2881 if (!_cmsReadUInt8Number(io
, &inputChan
)) return NULL
;
2882 if (!_cmsReadUInt8Number(io
, &outputChan
)) return NULL
;
2884 if (inputChan
== 0 || inputChan
>= cmsMAXCHANNELS
) return NULL
;
2885 if (outputChan
== 0 || outputChan
>= cmsMAXCHANNELS
) return NULL
;
2888 if (!_cmsReadUInt16Number(io
, NULL
)) return NULL
;
2890 if (!_cmsReadUInt32Number(io
, &offsetB
)) return NULL
;
2891 if (!_cmsReadUInt32Number(io
, &offsetMat
)) return NULL
;
2892 if (!_cmsReadUInt32Number(io
, &offsetM
)) return NULL
;
2893 if (!_cmsReadUInt32Number(io
, &offsetC
)) return NULL
;
2894 if (!_cmsReadUInt32Number(io
, &offsetA
)) return NULL
;
2896 // Allocates an empty LUT
2897 NewLUT
= cmsPipelineAlloc(self
->ContextID
, inputChan
, outputChan
);
2898 if (NewLUT
== NULL
) return NULL
;
2901 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetB
, inputChan
)))
2905 if (offsetMat
!= 0) {
2906 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadMatrix(self
, io
, BaseOffset
+ offsetMat
)))
2911 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetM
, inputChan
)))
2916 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadCLUT(self
, io
, BaseOffset
+ offsetC
, inputChan
, outputChan
)))
2921 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetA
, outputChan
)))
2928 cmsPipelineFree(NewLUT
);
2931 cmsUNUSED_PARAMETER(SizeOfTag
);
2939 B - Matrix - M - CLUT - A
2943 cmsBool
Type_LUTB2A_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
2945 cmsPipeline
* Lut
= (cmsPipeline
*) Ptr
;
2946 cmsUInt32Number inputChan
, outputChan
;
2947 cmsStage
*A
= NULL
, *B
= NULL
, *M
= NULL
;
2948 cmsStage
*Matrix
= NULL
;
2949 cmsStage
*CLUT
= NULL
;
2950 cmsUInt32Number offsetB
= 0, offsetMat
= 0, offsetM
= 0, offsetC
= 0, offsetA
= 0;
2951 cmsUInt32Number BaseOffset
, DirectoryPos
, CurrentPos
;
2954 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
2956 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 1, cmsSigCurveSetElemType
, &B
))
2957 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 3, cmsSigCurveSetElemType
, cmsSigMatrixElemType
, cmsSigCurveSetElemType
, &B
, &Matrix
, &M
))
2958 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 3, cmsSigCurveSetElemType
, cmsSigCLutElemType
, cmsSigCurveSetElemType
, &B
, &CLUT
, &A
))
2959 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 5, cmsSigCurveSetElemType
, cmsSigMatrixElemType
, cmsSigCurveSetElemType
,
2960 cmsSigCLutElemType
, cmsSigCurveSetElemType
, &B
, &Matrix
, &M
, &CLUT
, &A
)) {
2961 cmsSignalError(self
->ContextID
, cmsERROR_NOT_SUITABLE
, "LUT is not suitable to be saved as LutBToA");
2965 inputChan
= cmsPipelineInputChannels(Lut
);
2966 outputChan
= cmsPipelineOutputChannels(Lut
);
2968 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) inputChan
)) return FALSE
;
2969 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) outputChan
)) return FALSE
;
2970 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
;
2972 DirectoryPos
= io
->Tell(io
);
2974 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2975 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2976 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2977 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2978 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2982 offsetA
= io
->Tell(io
) - BaseOffset
;
2983 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, A
)) return FALSE
;
2987 offsetC
= io
->Tell(io
) - BaseOffset
;
2988 if (!WriteCLUT(self
, io
, (Lut
->SaveAs8Bits
? 1U : 2U), CLUT
)) return FALSE
;
2993 offsetM
= io
->Tell(io
) - BaseOffset
;
2994 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, M
)) return FALSE
;
2997 if (Matrix
!= NULL
) {
2998 offsetMat
= io
->Tell(io
) - BaseOffset
;
2999 if (!WriteMatrix(self
, io
, Matrix
)) return FALSE
;
3004 offsetB
= io
->Tell(io
) - BaseOffset
;
3005 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, B
)) return FALSE
;
3008 CurrentPos
= io
->Tell(io
);
3010 if (!io
->Seek(io
, DirectoryPos
)) return FALSE
;
3012 if (!_cmsWriteUInt32Number(io
, offsetB
)) return FALSE
;
3013 if (!_cmsWriteUInt32Number(io
, offsetMat
)) return FALSE
;
3014 if (!_cmsWriteUInt32Number(io
, offsetM
)) return FALSE
;
3015 if (!_cmsWriteUInt32Number(io
, offsetC
)) return FALSE
;
3016 if (!_cmsWriteUInt32Number(io
, offsetA
)) return FALSE
;
3018 if (!io
->Seek(io
, CurrentPos
)) return FALSE
;
3022 cmsUNUSED_PARAMETER(nItems
);
3028 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3030 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
3032 cmsUNUSED_PARAMETER(n
);
3033 cmsUNUSED_PARAMETER(self
);
3037 void Type_LUTB2A_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3039 cmsPipelineFree((cmsPipeline
*) Ptr
);
3042 cmsUNUSED_PARAMETER(self
);
3047 // ********************************************************************************
3048 // Type cmsSigColorantTableType
3049 // ********************************************************************************
3051 The purpose of this tag is to identify the colorants used in the profile by a
3052 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
3053 value. The first colorant listed is the colorant of the first device channel of
3054 a lut tag. The second colorant listed is the colorant of the second device channel
3055 of a lut tag, and so on.
3059 void *Type_ColorantTable_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3061 cmsUInt32Number i
, Count
;
3062 cmsNAMEDCOLORLIST
* List
;
3064 cmsUInt16Number PCS
[3];
3067 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
3069 if (Count
> cmsMAXCHANNELS
) {
3070 cmsSignalError(self
->ContextID
, cmsERROR_RANGE
, "Too many colorants '%d'", Count
);
3074 List
= cmsAllocNamedColorList(self
->ContextID
, Count
, 0, "", "");
3078 for (i
=0; i
< Count
; i
++) {
3080 if (io
->Read(io
, Name
, 32, 1) != 1) goto Error
;
3083 if (!_cmsReadUInt16Array(io
, 3, PCS
)) goto Error
;
3085 if (!cmsAppendNamedColor(List
, Name
, PCS
, NULL
)) goto Error
;
3094 cmsFreeNamedColorList(List
);
3097 cmsUNUSED_PARAMETER(SizeOfTag
);
3102 // Saves a colorant table. It is using the named color structure for simplicity sake
3104 cmsBool
Type_ColorantTable_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3106 cmsNAMEDCOLORLIST
* NamedColorList
= (cmsNAMEDCOLORLIST
*) Ptr
;
3107 cmsUInt32Number i
, nColors
;
3109 nColors
= cmsNamedColorCount(NamedColorList
);
3111 if (!_cmsWriteUInt32Number(io
, nColors
)) return FALSE
;
3113 for (i
=0; i
< nColors
; i
++) {
3115 char root
[cmsMAX_PATH
];
3116 cmsUInt16Number PCS
[3];
3118 memset(root
, 0, sizeof(root
));
3120 if (!cmsNamedColorInfo(NamedColorList
, i
, root
, NULL
, NULL
, PCS
, NULL
)) return 0;
3123 if (!io
->Write(io
, 32, root
)) return FALSE
;
3124 if (!_cmsWriteUInt16Array(io
, 3, PCS
)) return FALSE
;
3129 cmsUNUSED_PARAMETER(nItems
);
3130 cmsUNUSED_PARAMETER(self
);
3135 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
3137 cmsNAMEDCOLORLIST
* nc
= (cmsNAMEDCOLORLIST
*) Ptr
;
3138 return (void*) cmsDupNamedColorList(nc
);
3140 cmsUNUSED_PARAMETER(n
);
3141 cmsUNUSED_PARAMETER(self
);
3146 void Type_ColorantTable_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3148 cmsFreeNamedColorList((cmsNAMEDCOLORLIST
*) Ptr
);
3151 cmsUNUSED_PARAMETER(self
);
3155 // ********************************************************************************
3156 // Type cmsSigNamedColor2Type
3157 // ********************************************************************************
3159 //The namedColor2Type is a count value and array of structures that provide color
3160 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3161 //device representation of the color are given. Both representations are 16-bit values.
3162 //The device representation corresponds to the header's 'color space of data' field.
3163 //This representation should be consistent with the 'number of device components'
3164 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3165 //The PCS representation corresponds to the header's PCS field. The PCS representation
3166 //is always provided. Color names are fixed-length, 32-byte fields including null
3167 //termination. In order to maintain maximum portability, it is strongly recommended
3168 //that special characters of the 7-bit ASCII set not be used.
3171 void *Type_NamedColor_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3173 cmsUInt32Number vendorFlag
; // Bottom 16 bits for ICC use
3174 cmsUInt32Number count
; // Count of named colors
3175 cmsUInt32Number nDeviceCoords
; // Num of device coordinates
3176 char prefix
[32]; // Prefix for each color name
3177 char suffix
[32]; // Suffix for each color name
3178 cmsNAMEDCOLORLIST
* v
;
3183 if (!_cmsReadUInt32Number(io
, &vendorFlag
)) return NULL
;
3184 if (!_cmsReadUInt32Number(io
, &count
)) return NULL
;
3185 if (!_cmsReadUInt32Number(io
, &nDeviceCoords
)) return NULL
;
3187 if (io
-> Read(io
, prefix
, 32, 1) != 1) return NULL
;
3188 if (io
-> Read(io
, suffix
, 32, 1) != 1) return NULL
;
3190 prefix
[31] = suffix
[31] = 0;
3192 v
= cmsAllocNamedColorList(self
->ContextID
, count
, nDeviceCoords
, prefix
, suffix
);
3194 cmsSignalError(self
->ContextID
, cmsERROR_RANGE
, "Too many named colors '%d'", count
);
3198 if (nDeviceCoords
> cmsMAXCHANNELS
) {
3199 cmsSignalError(self
->ContextID
, cmsERROR_RANGE
, "Too many device coordinates '%d'", nDeviceCoords
);
3202 for (i
=0; i
< count
; i
++) {
3204 cmsUInt16Number PCS
[3];
3205 cmsUInt16Number Colorant
[cmsMAXCHANNELS
];
3208 memset(Colorant
, 0, sizeof(Colorant
));
3209 if (io
-> Read(io
, Root
, 32, 1) != 1) goto Error
;
3210 Root
[32] = 0; // To prevent exploits
3212 if (!_cmsReadUInt16Array(io
, 3, PCS
)) goto Error
;
3213 if (!_cmsReadUInt16Array(io
, nDeviceCoords
, Colorant
)) goto Error
;
3215 if (!cmsAppendNamedColor(v
, Root
, PCS
, Colorant
)) goto Error
;
3222 cmsFreeNamedColorList(v
);
3225 cmsUNUSED_PARAMETER(SizeOfTag
);
3229 // Saves a named color list into a named color profile
3231 cmsBool
Type_NamedColor_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3233 cmsNAMEDCOLORLIST
* NamedColorList
= (cmsNAMEDCOLORLIST
*) Ptr
;
3234 char prefix
[33]; // Prefix for each color name
3235 char suffix
[33]; // Suffix for each color name
3236 cmsUInt32Number i
, nColors
;
3238 nColors
= cmsNamedColorCount(NamedColorList
);
3240 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
3241 if (!_cmsWriteUInt32Number(io
, nColors
)) return FALSE
;
3242 if (!_cmsWriteUInt32Number(io
, NamedColorList
->ColorantCount
)) return FALSE
;
3244 memcpy(prefix
, (const char*) NamedColorList
->Prefix
, sizeof(prefix
));
3245 memcpy(suffix
, (const char*) NamedColorList
->Suffix
, sizeof(suffix
));
3247 suffix
[32] = prefix
[32] = 0;
3249 if (!io
->Write(io
, 32, prefix
)) return FALSE
;
3250 if (!io
->Write(io
, 32, suffix
)) return FALSE
;
3252 for (i
=0; i
< nColors
; i
++) {
3254 cmsUInt16Number PCS
[3];
3255 cmsUInt16Number Colorant
[cmsMAXCHANNELS
];
3256 char Root
[cmsMAX_PATH
];
3258 memset(Root
, 0, sizeof(Root
));
3259 memset(PCS
, 0, sizeof(PCS
));
3260 memset(Colorant
, 0, sizeof(Colorant
));
3262 if (!cmsNamedColorInfo(NamedColorList
, i
, Root
, NULL
, NULL
, PCS
, Colorant
)) return 0;
3264 if (!io
->Write(io
, 32 , Root
)) return FALSE
;
3265 if (!_cmsWriteUInt16Array(io
, 3, PCS
)) return FALSE
;
3266 if (!_cmsWriteUInt16Array(io
, NamedColorList
->ColorantCount
, Colorant
)) return FALSE
;
3271 cmsUNUSED_PARAMETER(nItems
);
3272 cmsUNUSED_PARAMETER(self
);
3276 void* Type_NamedColor_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
3278 cmsNAMEDCOLORLIST
* nc
= (cmsNAMEDCOLORLIST
*) Ptr
;
3280 return (void*) cmsDupNamedColorList(nc
);
3282 cmsUNUSED_PARAMETER(n
);
3283 cmsUNUSED_PARAMETER(self
);
3288 void Type_NamedColor_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3290 cmsFreeNamedColorList((cmsNAMEDCOLORLIST
*) Ptr
);
3293 cmsUNUSED_PARAMETER(self
);
3297 // ********************************************************************************
3298 // Type cmsSigProfileSequenceDescType
3299 // ********************************************************************************
3301 // This type is an array of structures, each of which contains information from the
3302 // header fields and tags from the original profiles which were combined to create
3303 // the final profile. The order of the structures is the order in which the profiles
3304 // were combined and includes a structure for the final profile. This provides a
3305 // description of the profile sequence from source to destination,
3306 // typically used with the DeviceLink profile.
3309 cmsBool
ReadEmbeddedText(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsMLU
** mlu
, cmsUInt32Number SizeOfTag
)
3311 cmsTagTypeSignature BaseType
;
3312 cmsUInt32Number nItems
;
3314 BaseType
= _cmsReadTypeBase(io
);
3318 case cmsSigTextType
:
3319 if (*mlu
) cmsMLUfree(*mlu
);
3320 *mlu
= (cmsMLU
*)Type_Text_Read(self
, io
, &nItems
, SizeOfTag
);
3321 return (*mlu
!= NULL
);
3323 case cmsSigTextDescriptionType
:
3324 if (*mlu
) cmsMLUfree(*mlu
);
3325 *mlu
= (cmsMLU
*) Type_Text_Description_Read(self
, io
, &nItems
, SizeOfTag
);
3326 return (*mlu
!= NULL
);
3329 TBD: Size is needed for MLU, and we have no idea on which is the available size
3332 case cmsSigMultiLocalizedUnicodeType
:
3333 if (*mlu
) cmsMLUfree(*mlu
);
3334 *mlu
= (cmsMLU
*) Type_MLU_Read(self
, io
, &nItems
, SizeOfTag
);
3335 return (*mlu
!= NULL
);
3337 default: return FALSE
;
3343 void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3346 cmsUInt32Number i
, Count
;
3350 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
3352 if (SizeOfTag
< sizeof(cmsUInt32Number
)) return NULL
;
3353 SizeOfTag
-= sizeof(cmsUInt32Number
);
3356 OutSeq
= cmsAllocProfileSequenceDescription(self
->ContextID
, Count
);
3357 if (OutSeq
== NULL
) return NULL
;
3361 // Get structures as well
3363 for (i
=0; i
< Count
; i
++) {
3365 cmsPSEQDESC
* sec
= &OutSeq
-> seq
[i
];
3367 if (!_cmsReadUInt32Number(io
, &sec
->deviceMfg
)) goto Error
;
3368 if (SizeOfTag
< sizeof(cmsUInt32Number
)) goto Error
;
3369 SizeOfTag
-= sizeof(cmsUInt32Number
);
3371 if (!_cmsReadUInt32Number(io
, &sec
->deviceModel
)) goto Error
;
3372 if (SizeOfTag
< sizeof(cmsUInt32Number
)) goto Error
;
3373 SizeOfTag
-= sizeof(cmsUInt32Number
);
3375 if (!_cmsReadUInt64Number(io
, &sec
->attributes
)) goto Error
;
3376 if (SizeOfTag
< sizeof(cmsUInt64Number
)) goto Error
;
3377 SizeOfTag
-= sizeof(cmsUInt64Number
);
3379 if (!_cmsReadUInt32Number(io
, (cmsUInt32Number
*)&sec
->technology
)) goto Error
;
3380 if (SizeOfTag
< sizeof(cmsUInt32Number
)) goto Error
;
3381 SizeOfTag
-= sizeof(cmsUInt32Number
);
3383 if (!ReadEmbeddedText(self
, io
, &sec
->Manufacturer
, SizeOfTag
)) goto Error
;
3384 if (!ReadEmbeddedText(self
, io
, &sec
->Model
, SizeOfTag
)) goto Error
;
3391 cmsFreeProfileSequenceDescription(OutSeq
);
3396 // Aux--Embed a text description type. It can be of type text description or multilocalized unicode
3397 // and it depends of the version number passed on cmsTagDescriptor structure instead of stack
3399 cmsBool
SaveDescription(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsMLU
* Text
)
3401 if (self
->ICCVersion
< 0x4000000) {
3403 if (!_cmsWriteTypeBase(io
, cmsSigTextDescriptionType
)) return FALSE
;
3404 return Type_Text_Description_Write(self
, io
, Text
, 1);
3407 if (!_cmsWriteTypeBase(io
, cmsSigMultiLocalizedUnicodeType
)) return FALSE
;
3408 return Type_MLU_Write(self
, io
, Text
, 1);
3414 cmsBool
Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3416 cmsSEQ
* Seq
= (cmsSEQ
*) Ptr
;
3419 if (!_cmsWriteUInt32Number(io
, Seq
->n
)) return FALSE
;
3421 for (i
=0; i
< Seq
->n
; i
++) {
3423 cmsPSEQDESC
* sec
= &Seq
-> seq
[i
];
3425 if (!_cmsWriteUInt32Number(io
, sec
->deviceMfg
)) return FALSE
;
3426 if (!_cmsWriteUInt32Number(io
, sec
->deviceModel
)) return FALSE
;
3427 if (!_cmsWriteUInt64Number(io
, &sec
->attributes
)) return FALSE
;
3428 if (!_cmsWriteUInt32Number(io
, sec
->technology
)) return FALSE
;
3430 if (!SaveDescription(self
, io
, sec
->Manufacturer
)) return FALSE
;
3431 if (!SaveDescription(self
, io
, sec
->Model
)) return FALSE
;
3436 cmsUNUSED_PARAMETER(nItems
);
3441 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
3443 return (void*) cmsDupProfileSequenceDescription((cmsSEQ
*) Ptr
);
3445 cmsUNUSED_PARAMETER(n
);
3446 cmsUNUSED_PARAMETER(self
);
3450 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3452 cmsFreeProfileSequenceDescription((cmsSEQ
*) Ptr
);
3455 cmsUNUSED_PARAMETER(self
);
3459 // ********************************************************************************
3460 // Type cmsSigProfileSequenceIdType
3461 // ********************************************************************************
3463 In certain workflows using ICC Device Link Profiles, it is necessary to identify the
3464 original profiles that were combined to create the Device Link Profile.
3465 This type is an array of structures, each of which contains information for
3466 identification of a profile used in a sequence
3471 cmsBool
ReadSeqID(struct _cms_typehandler_struct
* self
,
3475 cmsUInt32Number SizeOfTag
)
3477 cmsSEQ
* OutSeq
= (cmsSEQ
*) Cargo
;
3478 cmsPSEQDESC
* seq
= &OutSeq
->seq
[n
];
3480 if (io
-> Read(io
, seq
->ProfileID
.ID8
, 16, 1) != 1) return FALSE
;
3481 if (!ReadEmbeddedText(self
, io
, &seq
->Description
, SizeOfTag
)) return FALSE
;
3489 void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3492 cmsUInt32Number Count
;
3493 cmsUInt32Number BaseOffset
;
3497 // Get actual position as a basis for element offsets
3498 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
3501 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
3503 // Allocate an empty structure
3504 OutSeq
= cmsAllocProfileSequenceDescription(self
->ContextID
, Count
);
3505 if (OutSeq
== NULL
) return NULL
;
3508 // Read the position table
3509 if (!ReadPositionTable(self
, io
, Count
, BaseOffset
, OutSeq
, ReadSeqID
)) {
3511 cmsFreeProfileSequenceDescription(OutSeq
);
3519 cmsUNUSED_PARAMETER(SizeOfTag
);
3524 cmsBool
WriteSeqID(struct _cms_typehandler_struct
* self
,
3528 cmsUInt32Number SizeOfTag
)
3530 cmsSEQ
* Seq
= (cmsSEQ
*) Cargo
;
3532 if (!io
->Write(io
, 16, Seq
->seq
[n
].ProfileID
.ID8
)) return FALSE
;
3534 // Store here the MLU
3535 if (!SaveDescription(self
, io
, Seq
->seq
[n
].Description
)) return FALSE
;
3539 cmsUNUSED_PARAMETER(SizeOfTag
);
3543 cmsBool
Type_ProfileSequenceId_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3545 cmsSEQ
* Seq
= (cmsSEQ
*) Ptr
;
3546 cmsUInt32Number BaseOffset
;
3548 // Keep the base offset
3549 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
3551 // This is the table count
3552 if (!_cmsWriteUInt32Number(io
, Seq
->n
)) return FALSE
;
3554 // This is the position table and content
3555 if (!WritePositionTable(self
, io
, 0, Seq
->n
, BaseOffset
, Seq
, WriteSeqID
)) return FALSE
;
3559 cmsUNUSED_PARAMETER(nItems
);
3563 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
3565 return (void*) cmsDupProfileSequenceDescription((cmsSEQ
*) Ptr
);
3567 cmsUNUSED_PARAMETER(n
);
3568 cmsUNUSED_PARAMETER(self
);
3572 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3574 cmsFreeProfileSequenceDescription((cmsSEQ
*) Ptr
);
3577 cmsUNUSED_PARAMETER(self
);
3581 // ********************************************************************************
3582 // Type cmsSigUcrBgType
3583 // ********************************************************************************
3585 This type contains curves representing the under color removal and black
3586 generation and a text string which is a general description of the method used
3591 void *Type_UcrBg_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3593 cmsUcrBg
* n
= (cmsUcrBg
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsUcrBg
));
3594 cmsUInt32Number CountUcr
, CountBg
;
3595 cmsInt32Number SignedSizeOfTag
= (cmsInt32Number
)SizeOfTag
;
3599 if (n
== NULL
) return NULL
;
3601 // First curve is Under color removal
3603 if (SignedSizeOfTag
< (cmsInt32Number
) sizeof(cmsUInt32Number
)) return NULL
;
3604 if (!_cmsReadUInt32Number(io
, &CountUcr
)) return NULL
;
3605 SignedSizeOfTag
-= sizeof(cmsUInt32Number
);
3607 n
->Ucr
= cmsBuildTabulatedToneCurve16(self
->ContextID
, CountUcr
, NULL
);
3608 if (n
->Ucr
== NULL
) goto error
;
3610 if (SignedSizeOfTag
< (cmsInt32Number
)(CountUcr
* sizeof(cmsUInt16Number
))) goto error
;
3611 if (!_cmsReadUInt16Array(io
, CountUcr
, n
->Ucr
->Table16
)) goto error
;
3613 SignedSizeOfTag
-= CountUcr
* sizeof(cmsUInt16Number
);
3615 // Second curve is Black generation
3617 if (SignedSizeOfTag
< (cmsInt32Number
)sizeof(cmsUInt32Number
)) goto error
;
3618 if (!_cmsReadUInt32Number(io
, &CountBg
)) goto error
;
3619 SignedSizeOfTag
-= sizeof(cmsUInt32Number
);
3621 n
->Bg
= cmsBuildTabulatedToneCurve16(self
->ContextID
, CountBg
, NULL
);
3622 if (n
->Bg
== NULL
) goto error
;
3624 if (SignedSizeOfTag
< (cmsInt32Number
) (CountBg
* sizeof(cmsUInt16Number
))) goto error
;
3625 if (!_cmsReadUInt16Array(io
, CountBg
, n
->Bg
->Table16
)) goto error
;
3626 SignedSizeOfTag
-= CountBg
* sizeof(cmsUInt16Number
);
3628 if (SignedSizeOfTag
< 0 || SignedSizeOfTag
> 32000) goto error
;
3630 // Now comes the text. The length is specified by the tag size
3631 n
->Desc
= cmsMLUalloc(self
->ContextID
, 1);
3632 if (n
->Desc
== NULL
) goto error
;
3634 ASCIIString
= (char*) _cmsMalloc(self
->ContextID
, SignedSizeOfTag
+ 1);
3635 if (io
->Read(io
, ASCIIString
, sizeof(char), SignedSizeOfTag
) != (cmsUInt32Number
)SignedSizeOfTag
)
3637 _cmsFree(self
->ContextID
, ASCIIString
);
3641 ASCIIString
[SignedSizeOfTag
] = 0;
3642 cmsMLUsetASCII(n
->Desc
, cmsNoLanguage
, cmsNoCountry
, ASCIIString
);
3643 _cmsFree(self
->ContextID
, ASCIIString
);
3650 if (n
->Ucr
) cmsFreeToneCurve(n
->Ucr
);
3651 if (n
->Bg
) cmsFreeToneCurve(n
->Bg
);
3652 if (n
->Desc
) cmsMLUfree(n
->Desc
);
3653 _cmsFree(self
->ContextID
, n
);
3660 cmsBool
Type_UcrBg_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3662 cmsUcrBg
* Value
= (cmsUcrBg
*) Ptr
;
3663 cmsUInt32Number TextSize
;
3666 // First curve is Under color removal
3667 if (!_cmsWriteUInt32Number(io
, Value
->Ucr
->nEntries
)) return FALSE
;
3668 if (!_cmsWriteUInt16Array(io
, Value
->Ucr
->nEntries
, Value
->Ucr
->Table16
)) return FALSE
;
3670 // Then black generation
3671 if (!_cmsWriteUInt32Number(io
, Value
->Bg
->nEntries
)) return FALSE
;
3672 if (!_cmsWriteUInt16Array(io
, Value
->Bg
->nEntries
, Value
->Bg
->Table16
)) return FALSE
;
3674 // Now comes the text. The length is specified by the tag size
3675 TextSize
= cmsMLUgetASCII(Value
->Desc
, cmsNoLanguage
, cmsNoCountry
, NULL
, 0);
3676 Text
= (char*) _cmsMalloc(self
->ContextID
, TextSize
);
3677 if (cmsMLUgetASCII(Value
->Desc
, cmsNoLanguage
, cmsNoCountry
, Text
, TextSize
) != TextSize
) return FALSE
;
3679 if (!io
->Write(io
, TextSize
, Text
)) return FALSE
;
3680 _cmsFree(self
->ContextID
, Text
);
3684 cmsUNUSED_PARAMETER(nItems
);
3688 void* Type_UcrBg_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3690 cmsUcrBg
* Src
= (cmsUcrBg
*) Ptr
;
3691 cmsUcrBg
* NewUcrBg
= (cmsUcrBg
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsUcrBg
));
3693 if (NewUcrBg
== NULL
) return NULL
;
3695 NewUcrBg
->Bg
= cmsDupToneCurve(Src
->Bg
);
3696 NewUcrBg
->Ucr
= cmsDupToneCurve(Src
->Ucr
);
3697 NewUcrBg
->Desc
= cmsMLUdup(Src
->Desc
);
3699 return (void*) NewUcrBg
;
3701 cmsUNUSED_PARAMETER(n
);
3705 void Type_UcrBg_Free(struct _cms_typehandler_struct
* self
, void *Ptr
)
3707 cmsUcrBg
* Src
= (cmsUcrBg
*) Ptr
;
3709 if (Src
->Ucr
) cmsFreeToneCurve(Src
->Ucr
);
3710 if (Src
->Bg
) cmsFreeToneCurve(Src
->Bg
);
3711 if (Src
->Desc
) cmsMLUfree(Src
->Desc
);
3713 _cmsFree(self
->ContextID
, Ptr
);
3716 // ********************************************************************************
3717 // Type cmsSigCrdInfoType
3718 // ********************************************************************************
3721 This type contains the PostScript product name to which this profile corresponds
3722 and the names of the companion CRDs. Recall that a single profile can generate
3723 multiple CRDs. It is implemented as a MLU being the language code "PS" and then
3724 country varies for each element:
3726 nm: PostScript product name
3727 #0: Rendering intent 0 CRD name
3728 #1: Rendering intent 1 CRD name
3729 #2: Rendering intent 2 CRD name
3730 #3: Rendering intent 3 CRD name
3735 // Auxiliary, read an string specified as count + string
3737 cmsBool
ReadCountAndString(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsMLU
* mlu
, cmsUInt32Number
* SizeOfTag
, const char* Section
)
3739 cmsUInt32Number Count
;
3742 if (*SizeOfTag
< sizeof(cmsUInt32Number
)) return FALSE
;
3744 if (!_cmsReadUInt32Number(io
, &Count
)) return FALSE
;
3746 if (Count
> UINT_MAX
- sizeof(cmsUInt32Number
)) return FALSE
;
3747 if (*SizeOfTag
< Count
+ sizeof(cmsUInt32Number
)) return FALSE
;
3749 Text
= (char*) _cmsMalloc(self
->ContextID
, Count
+1);
3750 if (Text
== NULL
) return FALSE
;
3752 if (io
->Read(io
, Text
, sizeof(cmsUInt8Number
), Count
) != Count
) {
3753 _cmsFree(self
->ContextID
, Text
);
3759 cmsMLUsetASCII(mlu
, "PS", Section
, Text
);
3760 _cmsFree(self
->ContextID
, Text
);
3762 *SizeOfTag
-= (Count
+ sizeof(cmsUInt32Number
));
3767 cmsBool
WriteCountAndString(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsMLU
* mlu
, const char* Section
)
3769 cmsUInt32Number TextSize
;
3772 TextSize
= cmsMLUgetASCII(mlu
, "PS", Section
, NULL
, 0);
3773 Text
= (char*) _cmsMalloc(self
->ContextID
, TextSize
);
3775 if (!_cmsWriteUInt32Number(io
, TextSize
)) return FALSE
;
3777 if (cmsMLUgetASCII(mlu
, "PS", Section
, Text
, TextSize
) == 0) return FALSE
;
3779 if (!io
->Write(io
, TextSize
, Text
)) return FALSE
;
3780 _cmsFree(self
->ContextID
, Text
);
3786 void *Type_CrdInfo_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3788 cmsMLU
* mlu
= cmsMLUalloc(self
->ContextID
, 5);
3791 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "nm")) goto Error
;
3792 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "#0")) goto Error
;
3793 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "#1")) goto Error
;
3794 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "#2")) goto Error
;
3795 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "#3")) goto Error
;
3807 cmsBool
Type_CrdInfo_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3810 cmsMLU
* mlu
= (cmsMLU
*) Ptr
;
3812 if (!WriteCountAndString(self
, io
, mlu
, "nm")) goto Error
;
3813 if (!WriteCountAndString(self
, io
, mlu
, "#0")) goto Error
;
3814 if (!WriteCountAndString(self
, io
, mlu
, "#1")) goto Error
;
3815 if (!WriteCountAndString(self
, io
, mlu
, "#2")) goto Error
;
3816 if (!WriteCountAndString(self
, io
, mlu
, "#3")) goto Error
;
3823 cmsUNUSED_PARAMETER(nItems
);
3828 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3830 return (void*) cmsMLUdup((cmsMLU
*) Ptr
);
3832 cmsUNUSED_PARAMETER(n
);
3833 cmsUNUSED_PARAMETER(self
);
3837 void Type_CrdInfo_Free(struct _cms_typehandler_struct
* self
, void *Ptr
)
3839 cmsMLUfree((cmsMLU
*) Ptr
);
3842 cmsUNUSED_PARAMETER(self
);
3845 // ********************************************************************************
3846 // Type cmsSigScreeningType
3847 // ********************************************************************************
3849 //The screeningType describes various screening parameters including screen
3850 //frequency, screening angle, and spot shape.
3853 void *Type_Screening_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3855 cmsScreening
* sc
= NULL
;
3858 sc
= (cmsScreening
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsScreening
));
3859 if (sc
== NULL
) return NULL
;
3863 if (!_cmsReadUInt32Number(io
, &sc
->Flag
)) goto Error
;
3864 if (!_cmsReadUInt32Number(io
, &sc
->nChannels
)) goto Error
;
3866 if (sc
->nChannels
> cmsMAXCHANNELS
- 1)
3867 sc
->nChannels
= cmsMAXCHANNELS
- 1;
3869 for (i
=0; i
< sc
->nChannels
; i
++) {
3871 if (!_cmsRead15Fixed16Number(io
, &sc
->Channels
[i
].Frequency
)) goto Error
;
3872 if (!_cmsRead15Fixed16Number(io
, &sc
->Channels
[i
].ScreenAngle
)) goto Error
;
3873 if (!_cmsReadUInt32Number(io
, &sc
->Channels
[i
].SpotShape
)) goto Error
;
3883 _cmsFree(self
->ContextID
, sc
);
3887 cmsUNUSED_PARAMETER(SizeOfTag
);
3892 cmsBool
Type_Screening_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3894 cmsScreening
* sc
= (cmsScreening
* ) Ptr
;
3897 if (!_cmsWriteUInt32Number(io
, sc
->Flag
)) return FALSE
;
3898 if (!_cmsWriteUInt32Number(io
, sc
->nChannels
)) return FALSE
;
3900 for (i
=0; i
< sc
->nChannels
; i
++) {
3902 if (!_cmsWrite15Fixed16Number(io
, sc
->Channels
[i
].Frequency
)) return FALSE
;
3903 if (!_cmsWrite15Fixed16Number(io
, sc
->Channels
[i
].ScreenAngle
)) return FALSE
;
3904 if (!_cmsWriteUInt32Number(io
, sc
->Channels
[i
].SpotShape
)) return FALSE
;
3909 cmsUNUSED_PARAMETER(nItems
);
3910 cmsUNUSED_PARAMETER(self
);
3915 void* Type_Screening_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3917 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsScreening
));
3919 cmsUNUSED_PARAMETER(n
);
3924 void Type_Screening_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3926 _cmsFree(self
->ContextID
, Ptr
);
3929 // ********************************************************************************
3930 // Type cmsSigViewingConditionsType
3931 // ********************************************************************************
3933 //This type represents a set of viewing condition parameters including:
3934 //CIE 'absolute' illuminant white point tristimulus values and CIE 'absolute'
3935 //surround tristimulus values.
3938 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3940 cmsICCViewingConditions
* vc
= NULL
;
3942 vc
= (cmsICCViewingConditions
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsICCViewingConditions
));
3943 if (vc
== NULL
) return NULL
;
3947 if (!_cmsReadXYZNumber(io
, &vc
->IlluminantXYZ
)) goto Error
;
3948 if (!_cmsReadXYZNumber(io
, &vc
->SurroundXYZ
)) goto Error
;
3949 if (!_cmsReadUInt32Number(io
, &vc
->IlluminantType
)) goto Error
;
3957 _cmsFree(self
->ContextID
, vc
);
3961 cmsUNUSED_PARAMETER(SizeOfTag
);
3966 cmsBool
Type_ViewingConditions_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3968 cmsICCViewingConditions
* sc
= (cmsICCViewingConditions
* ) Ptr
;
3970 if (!_cmsWriteXYZNumber(io
, &sc
->IlluminantXYZ
)) return FALSE
;
3971 if (!_cmsWriteXYZNumber(io
, &sc
->SurroundXYZ
)) return FALSE
;
3972 if (!_cmsWriteUInt32Number(io
, sc
->IlluminantType
)) return FALSE
;
3976 cmsUNUSED_PARAMETER(nItems
);
3977 cmsUNUSED_PARAMETER(self
);
3982 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3984 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsICCViewingConditions
));
3986 cmsUNUSED_PARAMETER(n
);
3991 void Type_ViewingConditions_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3993 _cmsFree(self
->ContextID
, Ptr
);
3997 // ********************************************************************************
3998 // Type cmsSigMultiProcessElementType
3999 // ********************************************************************************
4003 void* GenericMPEdup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
4005 return (void*) cmsStageDup((cmsStage
*) Ptr
);
4007 cmsUNUSED_PARAMETER(n
);
4008 cmsUNUSED_PARAMETER(self
);
4012 void GenericMPEfree(struct _cms_typehandler_struct
* self
, void *Ptr
)
4014 cmsStageFree((cmsStage
*) Ptr
);
4017 cmsUNUSED_PARAMETER(self
);
4020 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
4021 // The first curve segment always starts at -Infinity, and the last curve segment always ends at +Infinity. The
4022 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
4023 // specified either in terms of a formula, or by a sampled curve.
4026 // Read an embedded segmented curve
4028 cmsToneCurve
* ReadSegmentedCurve(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
)
4030 cmsCurveSegSignature ElementSig
;
4031 cmsUInt32Number i
, j
;
4032 cmsUInt16Number nSegments
;
4033 cmsCurveSegment
* Segments
;
4034 cmsToneCurve
* Curve
;
4035 cmsFloat32Number PrevBreak
= MINUS_INF
; // - infinite
4037 // Take signature and channels for each element.
4038 if (!_cmsReadUInt32Number(io
, (cmsUInt32Number
*) &ElementSig
)) return NULL
;
4040 // That should be a segmented curve
4041 if (ElementSig
!= cmsSigSegmentedCurve
) return NULL
;
4043 if (!_cmsReadUInt32Number(io
, NULL
)) return NULL
;
4044 if (!_cmsReadUInt16Number(io
, &nSegments
)) return NULL
;
4045 if (!_cmsReadUInt16Number(io
, NULL
)) return NULL
;
4047 if (nSegments
< 1) return NULL
;
4048 Segments
= (cmsCurveSegment
*) _cmsCalloc(self
->ContextID
, nSegments
, sizeof(cmsCurveSegment
));
4049 if (Segments
== NULL
) return NULL
;
4052 for (i
=0; i
< (cmsUInt32Number
) nSegments
- 1; i
++) {
4054 Segments
[i
].x0
= PrevBreak
;
4055 if (!_cmsReadFloat32Number(io
, &Segments
[i
].x1
)) goto Error
;
4056 PrevBreak
= Segments
[i
].x1
;
4059 Segments
[nSegments
-1].x0
= PrevBreak
;
4060 Segments
[nSegments
-1].x1
= PLUS_INF
; // A big cmsFloat32Number number
4063 for (i
=0; i
< nSegments
; i
++) {
4065 if (!_cmsReadUInt32Number(io
, (cmsUInt32Number
*) &ElementSig
)) goto Error
;
4066 if (!_cmsReadUInt32Number(io
, NULL
)) goto Error
;
4068 switch (ElementSig
) {
4070 case cmsSigFormulaCurveSeg
: {
4072 cmsUInt16Number Type
;
4073 cmsUInt32Number ParamsByType
[] = { 4, 5, 5 };
4075 if (!_cmsReadUInt16Number(io
, &Type
)) goto Error
;
4076 if (!_cmsReadUInt16Number(io
, NULL
)) goto Error
;
4078 Segments
[i
].Type
= Type
+ 6;
4079 if (Type
> 2) goto Error
;
4081 for (j
= 0; j
< ParamsByType
[Type
]; j
++) {
4084 if (!_cmsReadFloat32Number(io
, &f
)) goto Error
;
4085 Segments
[i
].Params
[j
] = f
;
4091 case cmsSigSampledCurveSeg
: {
4092 cmsUInt32Number Count
;
4094 if (!_cmsReadUInt32Number(io
, &Count
)) goto Error
;
4096 // The first point is implicit in the last stage, we allocate an extra note to be populated latter on
4098 Segments
[i
].nGridPoints
= Count
;
4099 Segments
[i
].SampledPoints
= (cmsFloat32Number
*)_cmsCalloc(self
->ContextID
, Count
, sizeof(cmsFloat32Number
));
4100 if (Segments
[i
].SampledPoints
== NULL
) goto Error
;
4102 Segments
[i
].SampledPoints
[0] = 0;
4103 for (j
= 1; j
< Count
; j
++) {
4104 if (!_cmsReadFloat32Number(io
, &Segments
[i
].SampledPoints
[j
])) goto Error
;
4113 _cmsTagSignature2String(String
, (cmsTagSignature
) ElementSig
);
4114 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown curve element type '%s' found.", String
);
4121 Curve
= cmsBuildSegmentedToneCurve(self
->ContextID
, nSegments
, Segments
);
4123 for (i
=0; i
< nSegments
; i
++) {
4124 if (Segments
[i
].SampledPoints
) _cmsFree(self
->ContextID
, Segments
[i
].SampledPoints
);
4126 _cmsFree(self
->ContextID
, Segments
);
4128 // Explore for missing implicit points
4129 for (i
= 0; i
< nSegments
; i
++) {
4131 // If sampled curve, fix it
4132 if (Curve
->Segments
[i
].Type
== 0) {
4134 Curve
->Segments
[i
].SampledPoints
[0] = cmsEvalToneCurveFloat(Curve
, Curve
->Segments
[i
].x0
);
4142 for (i
=0; i
< nSegments
; i
++) {
4143 if (Segments
[i
].SampledPoints
) _cmsFree(self
->ContextID
, Segments
[i
].SampledPoints
);
4145 _cmsFree(self
->ContextID
, Segments
);
4152 cmsBool
ReadMPECurve(struct _cms_typehandler_struct
* self
,
4156 cmsUInt32Number SizeOfTag
)
4158 cmsToneCurve
** GammaTables
= ( cmsToneCurve
**) Cargo
;
4160 GammaTables
[n
] = ReadSegmentedCurve(self
, io
);
4161 return (GammaTables
[n
] != NULL
);
4163 cmsUNUSED_PARAMETER(SizeOfTag
);
4167 void *Type_MPEcurve_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
4169 cmsStage
* mpe
= NULL
;
4170 cmsUInt16Number InputChans
, OutputChans
;
4171 cmsUInt32Number i
, BaseOffset
;
4172 cmsToneCurve
** GammaTables
;
4176 // Get actual position as a basis for element offsets
4177 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
4179 if (!_cmsReadUInt16Number(io
, &InputChans
)) return NULL
;
4180 if (!_cmsReadUInt16Number(io
, &OutputChans
)) return NULL
;
4182 if (InputChans
!= OutputChans
) return NULL
;
4184 GammaTables
= (cmsToneCurve
**) _cmsCalloc(self
->ContextID
, InputChans
, sizeof(cmsToneCurve
*));
4185 if (GammaTables
== NULL
) return NULL
;
4187 if (ReadPositionTable(self
, io
, InputChans
, BaseOffset
, GammaTables
, ReadMPECurve
)) {
4189 mpe
= cmsStageAllocToneCurves(self
->ContextID
, InputChans
, GammaTables
);
4195 for (i
=0; i
< InputChans
; i
++) {
4196 if (GammaTables
[i
]) cmsFreeToneCurve(GammaTables
[i
]);
4199 _cmsFree(self
->ContextID
, GammaTables
);
4200 *nItems
= (mpe
!= NULL
) ? 1U : 0;
4203 cmsUNUSED_PARAMETER(SizeOfTag
);
4207 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
4209 cmsBool
WriteSegmentedCurve(cmsIOHANDLER
* io
, cmsToneCurve
* g
)
4211 cmsUInt32Number i
, j
;
4212 cmsCurveSegment
* Segments
= g
->Segments
;
4213 cmsUInt32Number nSegments
= g
->nSegments
;
4215 if (!_cmsWriteUInt32Number(io
, cmsSigSegmentedCurve
)) goto Error
;
4216 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
;
4217 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) nSegments
)) goto Error
;
4218 if (!_cmsWriteUInt16Number(io
, 0)) goto Error
;
4220 // Write the break-points
4221 for (i
=0; i
< nSegments
- 1; i
++) {
4222 if (!_cmsWriteFloat32Number(io
, Segments
[i
].x1
)) goto Error
;
4225 // Write the segments
4226 for (i
=0; i
< g
->nSegments
; i
++) {
4228 cmsCurveSegment
* ActualSeg
= Segments
+ i
;
4230 if (ActualSeg
-> Type
== 0) {
4232 // This is a sampled curve. First point is implicit in the ICC format, but not in our representation
4233 if (!_cmsWriteUInt32Number(io
, (cmsUInt32Number
) cmsSigSampledCurveSeg
)) goto Error
;
4234 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
;
4235 if (!_cmsWriteUInt32Number(io
, ActualSeg
-> nGridPoints
- 1)) goto Error
;
4237 for (j
=1; j
< g
->Segments
[i
].nGridPoints
; j
++) {
4238 if (!_cmsWriteFloat32Number(io
, ActualSeg
-> SampledPoints
[j
])) goto Error
;
4244 cmsUInt32Number ParamsByType
[] = { 4, 5, 5 };
4246 // This is a formula-based
4247 if (!_cmsWriteUInt32Number(io
, (cmsUInt32Number
) cmsSigFormulaCurveSeg
)) goto Error
;
4248 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
;
4250 // We only allow 1, 2 and 3 as types
4251 Type
= ActualSeg
->Type
- 6;
4252 if (Type
> 2 || Type
< 0) goto Error
;
4254 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) Type
)) goto Error
;
4255 if (!_cmsWriteUInt16Number(io
, 0)) goto Error
;
4257 for (j
=0; j
< ParamsByType
[Type
]; j
++) {
4258 if (!_cmsWriteFloat32Number(io
, (cmsFloat32Number
) ActualSeg
->Params
[j
])) goto Error
;
4262 // It seems there is no need to align. Code is here, and for safety commented out
4263 // if (!_cmsWriteAlignment(io)) goto Error;
4274 cmsBool
WriteMPECurve(struct _cms_typehandler_struct
* self
,
4278 cmsUInt32Number SizeOfTag
)
4280 _cmsStageToneCurvesData
* Curves
= (_cmsStageToneCurvesData
*) Cargo
;
4282 return WriteSegmentedCurve(io
, Curves
->TheCurves
[n
]);
4284 cmsUNUSED_PARAMETER(SizeOfTag
);
4285 cmsUNUSED_PARAMETER(self
);
4288 // Write a curve, checking first for validity
4290 cmsBool
Type_MPEcurve_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4292 cmsUInt32Number BaseOffset
;
4293 cmsStage
* mpe
= (cmsStage
*) Ptr
;
4294 _cmsStageToneCurvesData
* Curves
= (_cmsStageToneCurvesData
*) mpe
->Data
;
4296 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
4298 // Write the header. Since those are curves, input and output channels are same
4299 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->InputChannels
)) return FALSE
;
4300 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->InputChannels
)) return FALSE
;
4302 if (!WritePositionTable(self
, io
, 0,
4303 mpe
->InputChannels
, BaseOffset
, Curves
, WriteMPECurve
)) return FALSE
;
4308 cmsUNUSED_PARAMETER(nItems
);
4313 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4314 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4315 // is organized as follows:
4316 // array = [e11, e12, ..., e1P, e21, e22, ..., e2P, ..., eQ1, eQ2, ..., eQP, e1, e2, ..., eQ]
4319 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
4322 cmsUInt16Number InputChans
, OutputChans
;
4323 cmsUInt32Number nElems
, i
;
4324 cmsFloat64Number
* Matrix
;
4325 cmsFloat64Number
* Offsets
;
4327 if (!_cmsReadUInt16Number(io
, &InputChans
)) return NULL
;
4328 if (!_cmsReadUInt16Number(io
, &OutputChans
)) return NULL
;
4331 // Input and output chans may be ANY (up to 0xffff),
4332 // but we choose to limit to 16 channels for now
4333 if (InputChans
>= cmsMAXCHANNELS
) return NULL
;
4334 if (OutputChans
>= cmsMAXCHANNELS
) return NULL
;
4336 nElems
= (cmsUInt32Number
) InputChans
* OutputChans
;
4338 Matrix
= (cmsFloat64Number
*) _cmsCalloc(self
->ContextID
, nElems
, sizeof(cmsFloat64Number
));
4339 if (Matrix
== NULL
) return NULL
;
4341 Offsets
= (cmsFloat64Number
*) _cmsCalloc(self
->ContextID
, OutputChans
, sizeof(cmsFloat64Number
));
4342 if (Offsets
== NULL
) {
4344 _cmsFree(self
->ContextID
, Matrix
);
4348 for (i
=0; i
< nElems
; i
++) {
4352 if (!_cmsReadFloat32Number(io
, &v
)) {
4353 _cmsFree(self
->ContextID
, Matrix
);
4354 _cmsFree(self
->ContextID
, Offsets
);
4361 for (i
=0; i
< OutputChans
; i
++) {
4365 if (!_cmsReadFloat32Number(io
, &v
)) {
4366 _cmsFree(self
->ContextID
, Matrix
);
4367 _cmsFree(self
->ContextID
, Offsets
);
4374 mpe
= cmsStageAllocMatrix(self
->ContextID
, OutputChans
, InputChans
, Matrix
, Offsets
);
4375 _cmsFree(self
->ContextID
, Matrix
);
4376 _cmsFree(self
->ContextID
, Offsets
);
4382 cmsUNUSED_PARAMETER(SizeOfTag
);
4386 cmsBool
Type_MPEmatrix_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4388 cmsUInt32Number i
, nElems
;
4389 cmsStage
* mpe
= (cmsStage
*) Ptr
;
4390 _cmsStageMatrixData
* Matrix
= (_cmsStageMatrixData
*) mpe
->Data
;
4392 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->InputChannels
)) return FALSE
;
4393 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->OutputChannels
)) return FALSE
;
4395 nElems
= mpe
->InputChannels
* mpe
->OutputChannels
;
4397 for (i
=0; i
< nElems
; i
++) {
4398 if (!_cmsWriteFloat32Number(io
, (cmsFloat32Number
) Matrix
->Double
[i
])) return FALSE
;
4402 for (i
=0; i
< mpe
->OutputChannels
; i
++) {
4404 if (Matrix
->Offset
== NULL
) {
4406 if (!_cmsWriteFloat32Number(io
, 0)) return FALSE
;
4409 if (!_cmsWriteFloat32Number(io
, (cmsFloat32Number
) Matrix
->Offset
[i
])) return FALSE
;
4415 cmsUNUSED_PARAMETER(nItems
);
4416 cmsUNUSED_PARAMETER(self
);
4422 void *Type_MPEclut_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
4424 cmsStage
* mpe
= NULL
;
4425 cmsUInt16Number InputChans
, OutputChans
;
4426 cmsUInt8Number Dimensions8
[16];
4427 cmsUInt32Number i
, nMaxGrids
, GridPoints
[MAX_INPUT_DIMENSIONS
];
4428 _cmsStageCLutData
* clut
;
4430 if (!_cmsReadUInt16Number(io
, &InputChans
)) return NULL
;
4431 if (!_cmsReadUInt16Number(io
, &OutputChans
)) return NULL
;
4433 if (InputChans
== 0) goto Error
;
4434 if (OutputChans
== 0) goto Error
;
4436 if (io
->Read(io
, Dimensions8
, sizeof(cmsUInt8Number
), 16) != 16)
4439 // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
4440 nMaxGrids
= InputChans
> MAX_INPUT_DIMENSIONS
? (cmsUInt32Number
) MAX_INPUT_DIMENSIONS
: InputChans
;
4442 for (i
= 0; i
< nMaxGrids
; i
++) {
4443 if (Dimensions8
[i
] == 1) goto Error
; // Impossible value, 0 for no CLUT and then 2 at least
4444 GridPoints
[i
] = (cmsUInt32Number
)Dimensions8
[i
];
4447 // Allocate the true CLUT
4448 mpe
= cmsStageAllocCLutFloatGranular(self
->ContextID
, GridPoints
, InputChans
, OutputChans
, NULL
);
4449 if (mpe
== NULL
) goto Error
;
4451 // Read and sanitize the data
4452 clut
= (_cmsStageCLutData
*) mpe
->Data
;
4453 for (i
=0; i
< clut
->nEntries
; i
++) {
4455 if (!_cmsReadFloat32Number(io
, &clut
->Tab
.TFloat
[i
])) goto Error
;
4463 if (mpe
!= NULL
) cmsStageFree(mpe
);
4466 cmsUNUSED_PARAMETER(SizeOfTag
);
4469 // Write a CLUT in floating point
4471 cmsBool
Type_MPEclut_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4473 cmsUInt8Number Dimensions8
[16]; // 16 because the spec says 16 and not max number of channels
4475 cmsStage
* mpe
= (cmsStage
*) Ptr
;
4476 _cmsStageCLutData
* clut
= (_cmsStageCLutData
*) mpe
->Data
;
4478 // Check for maximum number of channels supported by lcms
4479 if (mpe
-> InputChannels
> MAX_INPUT_DIMENSIONS
) return FALSE
;
4481 // Only floats are supported in MPE
4482 if (clut
->HasFloatValues
== FALSE
) return FALSE
;
4484 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->InputChannels
)) return FALSE
;
4485 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->OutputChannels
)) return FALSE
;
4487 memset(Dimensions8
, 0, sizeof(Dimensions8
));
4489 for (i
=0; i
< mpe
->InputChannels
; i
++)
4490 Dimensions8
[i
] = (cmsUInt8Number
) clut
->Params
->nSamples
[i
];
4492 if (!io
->Write(io
, 16, Dimensions8
)) return FALSE
;
4494 for (i
=0; i
< clut
->nEntries
; i
++) {
4496 if (!_cmsWriteFloat32Number(io
, clut
->Tab
.TFloat
[i
])) return FALSE
;
4501 cmsUNUSED_PARAMETER(nItems
);
4502 cmsUNUSED_PARAMETER(self
);
4507 // This is the list of built-in MPE types
4508 static _cmsTagTypeLinkedList SupportedMPEtypes
[] = {
4510 {{ (cmsTagTypeSignature
) cmsSigBAcsElemType
, NULL
, NULL
, NULL
, NULL
, NULL
, 0 }, &SupportedMPEtypes
[1] }, // Ignore those elements for now
4511 {{ (cmsTagTypeSignature
) cmsSigEAcsElemType
, NULL
, NULL
, NULL
, NULL
, NULL
, 0 }, &SupportedMPEtypes
[2] }, // (That's what the spec says)
4513 {TYPE_MPE_HANDLER((cmsTagTypeSignature
) cmsSigCurveSetElemType
, MPEcurve
), &SupportedMPEtypes
[3] },
4514 {TYPE_MPE_HANDLER((cmsTagTypeSignature
) cmsSigMatrixElemType
, MPEmatrix
), &SupportedMPEtypes
[4] },
4515 {TYPE_MPE_HANDLER((cmsTagTypeSignature
) cmsSigCLutElemType
, MPEclut
), NULL
},
4518 _cmsTagTypePluginChunkType _cmsMPETypePluginChunk
= { NULL
};
4521 cmsBool
ReadMPEElem(struct _cms_typehandler_struct
* self
,
4525 cmsUInt32Number SizeOfTag
)
4527 cmsStageSignature ElementSig
;
4528 cmsTagTypeHandler
* TypeHandler
;
4529 cmsUInt32Number nItems
;
4530 cmsPipeline
*NewLUT
= (cmsPipeline
*) Cargo
;
4531 _cmsTagTypePluginChunkType
* MPETypePluginChunk
= ( _cmsTagTypePluginChunkType
*) _cmsContextGetClientChunk(self
->ContextID
, MPEPlugin
);
4534 // Take signature and channels for each element.
4535 if (!_cmsReadUInt32Number(io
, (cmsUInt32Number
*) &ElementSig
)) return FALSE
;
4537 // The reserved placeholder
4538 if (!_cmsReadUInt32Number(io
, NULL
)) return FALSE
;
4540 // Read diverse MPE types
4541 TypeHandler
= GetHandler((cmsTagTypeSignature
) ElementSig
, MPETypePluginChunk
->TagTypes
, SupportedMPEtypes
);
4542 if (TypeHandler
== NULL
) {
4546 _cmsTagSignature2String(String
, (cmsTagSignature
) ElementSig
);
4548 // An unknown element was found.
4549 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown MPE type '%s' found.", String
);
4553 // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
4554 // Read the MPE. No size is given
4555 if (TypeHandler
->ReadPtr
!= NULL
) {
4557 // This is a real element which should be read and processed
4558 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, (cmsStage
*) TypeHandler
->ReadPtr(self
, io
, &nItems
, SizeOfTag
)))
4564 cmsUNUSED_PARAMETER(SizeOfTag
);
4565 cmsUNUSED_PARAMETER(n
);
4569 // This is the main dispatcher for MPE
4571 void *Type_MPE_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
4573 cmsUInt16Number InputChans
, OutputChans
;
4574 cmsUInt32Number ElementCount
;
4575 cmsPipeline
*NewLUT
= NULL
;
4576 cmsUInt32Number BaseOffset
;
4578 // Get actual position as a basis for element offsets
4579 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
4581 // Read channels and element count
4582 if (!_cmsReadUInt16Number(io
, &InputChans
)) return NULL
;
4583 if (!_cmsReadUInt16Number(io
, &OutputChans
)) return NULL
;
4585 if (InputChans
== 0 || InputChans
>= cmsMAXCHANNELS
) return NULL
;
4586 if (OutputChans
== 0 || OutputChans
>= cmsMAXCHANNELS
) return NULL
;
4588 // Allocates an empty LUT
4589 NewLUT
= cmsPipelineAlloc(self
->ContextID
, InputChans
, OutputChans
);
4590 if (NewLUT
== NULL
) return NULL
;
4592 if (!_cmsReadUInt32Number(io
, &ElementCount
)) goto Error
;
4593 if (!ReadPositionTable(self
, io
, ElementCount
, BaseOffset
, NewLUT
, ReadMPEElem
)) goto Error
;
4595 // Check channel count
4596 if (InputChans
!= NewLUT
->InputChannels
||
4597 OutputChans
!= NewLUT
->OutputChannels
) goto Error
;
4605 if (NewLUT
!= NULL
) cmsPipelineFree(NewLUT
);
4609 cmsUNUSED_PARAMETER(SizeOfTag
);
4614 // This one is a little bit more complex, so we don't use position tables this time.
4616 cmsBool
Type_MPE_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4618 cmsUInt32Number i
, BaseOffset
, DirectoryPos
, CurrentPos
;
4619 cmsUInt32Number inputChan
, outputChan
;
4620 cmsUInt32Number ElemCount
;
4621 cmsUInt32Number
*ElementOffsets
= NULL
, *ElementSizes
= NULL
, Before
;
4622 cmsStageSignature ElementSig
;
4623 cmsPipeline
* Lut
= (cmsPipeline
*) Ptr
;
4624 cmsStage
* Elem
= Lut
->Elements
;
4625 cmsTagTypeHandler
* TypeHandler
;
4626 _cmsTagTypePluginChunkType
* MPETypePluginChunk
= ( _cmsTagTypePluginChunkType
*) _cmsContextGetClientChunk(self
->ContextID
, MPEPlugin
);
4628 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
4630 inputChan
= cmsPipelineInputChannels(Lut
);
4631 outputChan
= cmsPipelineOutputChannels(Lut
);
4632 ElemCount
= cmsPipelineStageCount(Lut
);
4634 ElementOffsets
= (cmsUInt32Number
*) _cmsCalloc(self
->ContextID
, ElemCount
, sizeof(cmsUInt32Number
));
4635 if (ElementOffsets
== NULL
) goto Error
;
4637 ElementSizes
= (cmsUInt32Number
*) _cmsCalloc(self
->ContextID
, ElemCount
, sizeof(cmsUInt32Number
));
4638 if (ElementSizes
== NULL
) goto Error
;
4641 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) inputChan
)) goto Error
;
4642 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) outputChan
)) goto Error
;
4643 if (!_cmsWriteUInt32Number(io
, (cmsUInt16Number
) ElemCount
)) goto Error
;
4645 DirectoryPos
= io
->Tell(io
);
4647 // Write a fake directory to be filled latter on
4648 for (i
=0; i
< ElemCount
; i
++) {
4649 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
; // Offset
4650 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
; // size
4653 // Write each single tag. Keep track of the size as well.
4654 for (i
=0; i
< ElemCount
; i
++) {
4656 ElementOffsets
[i
] = io
->Tell(io
) - BaseOffset
;
4658 ElementSig
= Elem
->Type
;
4660 TypeHandler
= GetHandler((cmsTagTypeSignature
) ElementSig
, MPETypePluginChunk
->TagTypes
, SupportedMPEtypes
);
4661 if (TypeHandler
== NULL
) {
4665 _cmsTagSignature2String(String
, (cmsTagSignature
) ElementSig
);
4667 // An unknown element was found.
4668 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Found unknown MPE type '%s'", String
);
4672 if (!_cmsWriteUInt32Number(io
, ElementSig
)) goto Error
;
4673 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
;
4674 Before
= io
->Tell(io
);
4675 if (!TypeHandler
->WritePtr(self
, io
, Elem
, 1)) goto Error
;
4676 if (!_cmsWriteAlignment(io
)) goto Error
;
4678 ElementSizes
[i
] = io
->Tell(io
) - Before
;
4683 // Write the directory
4684 CurrentPos
= io
->Tell(io
);
4686 if (!io
->Seek(io
, DirectoryPos
)) goto Error
;
4688 for (i
=0; i
< ElemCount
; i
++) {
4689 if (!_cmsWriteUInt32Number(io
, ElementOffsets
[i
])) goto Error
;
4690 if (!_cmsWriteUInt32Number(io
, ElementSizes
[i
])) goto Error
;
4693 if (!io
->Seek(io
, CurrentPos
)) goto Error
;
4695 if (ElementOffsets
!= NULL
) _cmsFree(self
->ContextID
, ElementOffsets
);
4696 if (ElementSizes
!= NULL
) _cmsFree(self
->ContextID
, ElementSizes
);
4700 if (ElementOffsets
!= NULL
) _cmsFree(self
->ContextID
, ElementOffsets
);
4701 if (ElementSizes
!= NULL
) _cmsFree(self
->ContextID
, ElementSizes
);
4704 cmsUNUSED_PARAMETER(nItems
);
4709 void* Type_MPE_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
4711 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
4713 cmsUNUSED_PARAMETER(n
);
4714 cmsUNUSED_PARAMETER(self
);
4718 void Type_MPE_Free(struct _cms_typehandler_struct
* self
, void *Ptr
)
4720 cmsPipelineFree((cmsPipeline
*) Ptr
);
4723 cmsUNUSED_PARAMETER(self
);
4727 // ********************************************************************************
4728 // Type cmsSigVcgtType
4729 // ********************************************************************************
4732 #define cmsVideoCardGammaTableType 0
4733 #define cmsVideoCardGammaFormulaType 1
4744 void *Type_vcgt_Read(struct _cms_typehandler_struct
* self
,
4746 cmsUInt32Number
* nItems
,
4747 cmsUInt32Number SizeOfTag
)
4749 cmsUInt32Number TagType
, n
, i
;
4750 cmsToneCurve
** Curves
;
4755 if (!_cmsReadUInt32Number(io
, &TagType
)) return NULL
;
4757 // Allocate space for the array
4758 Curves
= ( cmsToneCurve
**) _cmsCalloc(self
->ContextID
, 3, sizeof(cmsToneCurve
*));
4759 if (Curves
== NULL
) return NULL
;
4761 // There are two possible flavors
4764 // Gamma is stored as a table
4765 case cmsVideoCardGammaTableType
:
4767 cmsUInt16Number nChannels
, nElems
, nBytes
;
4769 // Check channel count, which should be 3 (we don't support monochrome this time)
4770 if (!_cmsReadUInt16Number(io
, &nChannels
)) goto Error
;
4772 if (nChannels
!= 3) {
4773 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unsupported number of channels for VCGT '%d'", nChannels
);
4777 // Get Table element count and bytes per element
4778 if (!_cmsReadUInt16Number(io
, &nElems
)) goto Error
;
4779 if (!_cmsReadUInt16Number(io
, &nBytes
)) goto Error
;
4781 // Adobe's quirk fixup. Fixing broken profiles...
4782 if (nElems
== 256 && nBytes
== 1 && SizeOfTag
== 1576)
4786 // Populate tone curves
4787 for (n
=0; n
< 3; n
++) {
4789 Curves
[n
] = cmsBuildTabulatedToneCurve16(self
->ContextID
, nElems
, NULL
);
4790 if (Curves
[n
] == NULL
) goto Error
;
4792 // On depending on byte depth
4797 for (i
=0; i
< nElems
; i
++) {
4801 if (!_cmsReadUInt8Number(io
, &v
)) goto Error
;
4802 Curves
[n
] ->Table16
[i
] = FROM_8_TO_16(v
);
4806 // One word 0..65535
4808 if (!_cmsReadUInt16Array(io
, nElems
, Curves
[n
]->Table16
)) goto Error
;
4813 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unsupported bit depth for VCGT '%d'", nBytes
* 8);
4816 } // For all 3 channels
4820 // In this case, gamma is stored as a formula
4821 case cmsVideoCardGammaFormulaType
:
4823 _cmsVCGTGAMMA Colorant
[3];
4825 // Populate tone curves
4826 for (n
=0; n
< 3; n
++) {
4830 if (!_cmsRead15Fixed16Number(io
, &Colorant
[n
].Gamma
)) goto Error
;
4831 if (!_cmsRead15Fixed16Number(io
, &Colorant
[n
].Min
)) goto Error
;
4832 if (!_cmsRead15Fixed16Number(io
, &Colorant
[n
].Max
)) goto Error
;
4834 // Parametric curve type 5 is:
4835 // Y = (aX + b)^Gamma + e | X >= d
4836 // Y = cX + f | X < d
4839 // Y = (Max - Min) * (X ^ Gamma) + Min
4841 // So, the translation is
4842 // a = (Max - Min) ^ ( 1 / Gamma)
4846 Params
[0] = Colorant
[n
].Gamma
;
4847 Params
[1] = pow((Colorant
[n
].Max
- Colorant
[n
].Min
), (1.0 / Colorant
[n
].Gamma
));
4851 Params
[5] = Colorant
[n
].Min
;
4854 Curves
[n
] = cmsBuildParametricToneCurve(self
->ContextID
, 5, Params
);
4855 if (Curves
[n
] == NULL
) goto Error
;
4862 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unsupported tag type for VCGT '%d'", TagType
);
4867 return (void*) Curves
;
4869 // Regret, free all resources
4872 cmsFreeToneCurveTriple(Curves
);
4873 _cmsFree(self
->ContextID
, Curves
);
4876 cmsUNUSED_PARAMETER(SizeOfTag
);
4880 // We don't support all flavors, only 16bits tables and formula
4882 cmsBool
Type_vcgt_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4884 cmsToneCurve
** Curves
= (cmsToneCurve
**) Ptr
;
4885 cmsUInt32Number i
, j
;
4887 if (cmsGetToneCurveParametricType(Curves
[0]) == 5 &&
4888 cmsGetToneCurveParametricType(Curves
[1]) == 5 &&
4889 cmsGetToneCurveParametricType(Curves
[2]) == 5) {
4891 if (!_cmsWriteUInt32Number(io
, cmsVideoCardGammaFormulaType
)) return FALSE
;
4894 for (i
=0; i
< 3; i
++) {
4898 v
.Gamma
= Curves
[i
] ->Segments
[0].Params
[0];
4899 v
.Min
= Curves
[i
] ->Segments
[0].Params
[5];
4900 v
.Max
= pow(Curves
[i
] ->Segments
[0].Params
[1], v
.Gamma
) + v
.Min
;
4902 if (!_cmsWrite15Fixed16Number(io
, v
.Gamma
)) return FALSE
;
4903 if (!_cmsWrite15Fixed16Number(io
, v
.Min
)) return FALSE
;
4904 if (!_cmsWrite15Fixed16Number(io
, v
.Max
)) return FALSE
;
4910 // Always store as a table of 256 words
4911 if (!_cmsWriteUInt32Number(io
, cmsVideoCardGammaTableType
)) return FALSE
;
4912 if (!_cmsWriteUInt16Number(io
, 3)) return FALSE
;
4913 if (!_cmsWriteUInt16Number(io
, 256)) return FALSE
;
4914 if (!_cmsWriteUInt16Number(io
, 2)) return FALSE
;
4916 for (i
=0; i
< 3; i
++) {
4917 for (j
=0; j
< 256; j
++) {
4919 cmsFloat32Number v
= cmsEvalToneCurveFloat(Curves
[i
], (cmsFloat32Number
) (j
/ 255.0));
4920 cmsUInt16Number n
= _cmsQuickSaturateWord(v
* 65535.0);
4922 if (!_cmsWriteUInt16Number(io
, n
)) return FALSE
;
4929 cmsUNUSED_PARAMETER(self
);
4930 cmsUNUSED_PARAMETER(nItems
);
4934 void* Type_vcgt_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
4936 cmsToneCurve
** OldCurves
= (cmsToneCurve
**) Ptr
;
4937 cmsToneCurve
** NewCurves
;
4939 NewCurves
= ( cmsToneCurve
**) _cmsCalloc(self
->ContextID
, 3, sizeof(cmsToneCurve
*));
4940 if (NewCurves
== NULL
) return NULL
;
4942 NewCurves
[0] = cmsDupToneCurve(OldCurves
[0]);
4943 NewCurves
[1] = cmsDupToneCurve(OldCurves
[1]);
4944 NewCurves
[2] = cmsDupToneCurve(OldCurves
[2]);
4946 return (void*) NewCurves
;
4948 cmsUNUSED_PARAMETER(n
);
4953 void Type_vcgt_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
4955 cmsFreeToneCurveTriple((cmsToneCurve
**) Ptr
);
4956 _cmsFree(self
->ContextID
, Ptr
);
4960 // ********************************************************************************
4961 // Type cmsSigDictType
4962 // ********************************************************************************
4964 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data
4966 cmsContext ContextID
;
4967 cmsUInt32Number
*Offsets
;
4968 cmsUInt32Number
*Sizes
;
4972 _cmsDICelem Name
, Value
, DisplayName
, DisplayValue
;
4976 // Allocate an empty array element
4978 cmsBool
AllocElem(cmsContext ContextID
, _cmsDICelem
* e
, cmsUInt32Number Count
)
4980 e
->Offsets
= (cmsUInt32Number
*) _cmsCalloc(ContextID
, Count
, sizeof(cmsUInt32Number
));
4981 if (e
->Offsets
== NULL
) return FALSE
;
4983 e
->Sizes
= (cmsUInt32Number
*) _cmsCalloc(ContextID
, Count
, sizeof(cmsUInt32Number
));
4984 if (e
->Sizes
== NULL
) {
4986 _cmsFree(ContextID
, e
-> Offsets
);
4990 e
->ContextID
= ContextID
;
4994 // Free an array element
4996 void FreeElem(_cmsDICelem
* e
)
4998 if (e
->Offsets
!= NULL
) _cmsFree(e
-> ContextID
, e
-> Offsets
);
4999 if (e
->Sizes
!= NULL
) _cmsFree(e
-> ContextID
, e
-> Sizes
);
5000 e
->Offsets
= e
->Sizes
= NULL
;
5003 // Get rid of whole array
5005 void FreeArray( _cmsDICarray
* a
)
5007 if (a
->Name
.Offsets
!= NULL
) FreeElem(&a
->Name
);
5008 if (a
->Value
.Offsets
!= NULL
) FreeElem(&a
->Value
);
5009 if (a
->DisplayName
.Offsets
!= NULL
) FreeElem(&a
->DisplayName
);
5010 if (a
->DisplayValue
.Offsets
!= NULL
) FreeElem(&a
->DisplayValue
);
5014 // Allocate whole array
5016 cmsBool
AllocArray(cmsContext ContextID
, _cmsDICarray
* a
, cmsUInt32Number Count
, cmsUInt32Number Length
)
5019 memset(a
, 0, sizeof(_cmsDICarray
));
5021 // On depending on record size, create column arrays
5022 if (!AllocElem(ContextID
, &a
->Name
, Count
)) goto Error
;
5023 if (!AllocElem(ContextID
, &a
->Value
, Count
)) goto Error
;
5026 if (!AllocElem(ContextID
, &a
-> DisplayName
, Count
)) goto Error
;
5030 if (!AllocElem(ContextID
, &a
->DisplayValue
, Count
)) goto Error
;
5041 cmsBool
ReadOneElem(cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, cmsUInt32Number BaseOffset
)
5043 if (!_cmsReadUInt32Number(io
, &e
->Offsets
[i
])) return FALSE
;
5044 if (!_cmsReadUInt32Number(io
, &e
->Sizes
[i
])) return FALSE
;
5046 // An offset of zero has special meaning and shall be preserved
5047 if (e
->Offsets
[i
] > 0)
5048 e
->Offsets
[i
] += BaseOffset
;
5054 cmsBool
ReadOffsetArray(cmsIOHANDLER
* io
, _cmsDICarray
* a
,
5055 cmsUInt32Number Count
, cmsUInt32Number Length
, cmsUInt32Number BaseOffset
,
5056 cmsInt32Number
* SignedSizeOfTagPtr
)
5059 cmsInt32Number SignedSizeOfTag
= *SignedSizeOfTagPtr
;
5061 // Read column arrays
5062 for (i
=0; i
< Count
; i
++) {
5064 if (SignedSizeOfTag
< 4 * (cmsInt32Number
) sizeof(cmsUInt32Number
)) return FALSE
;
5065 SignedSizeOfTag
-= 4 * sizeof(cmsUInt32Number
);
5067 if (!ReadOneElem(io
, &a
-> Name
, i
, BaseOffset
)) return FALSE
;
5068 if (!ReadOneElem(io
, &a
-> Value
, i
, BaseOffset
)) return FALSE
;
5072 if (SignedSizeOfTag
< 2 * (cmsInt32Number
) sizeof(cmsUInt32Number
)) return FALSE
;
5073 SignedSizeOfTag
-= 2 * sizeof(cmsUInt32Number
);
5075 if (!ReadOneElem(io
, &a
->DisplayName
, i
, BaseOffset
)) return FALSE
;
5081 if (SignedSizeOfTag
< 2 * (cmsInt32Number
) sizeof(cmsUInt32Number
)) return FALSE
;
5082 SignedSizeOfTag
-= 2 * (cmsInt32Number
) sizeof(cmsUInt32Number
);
5084 if (!ReadOneElem(io
, & a
-> DisplayValue
, i
, BaseOffset
)) return FALSE
;
5088 *SignedSizeOfTagPtr
= SignedSizeOfTag
;
5093 // Write one element
5095 cmsBool
WriteOneElem(cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
)
5097 if (!_cmsWriteUInt32Number(io
, e
->Offsets
[i
])) return FALSE
;
5098 if (!_cmsWriteUInt32Number(io
, e
->Sizes
[i
])) return FALSE
;
5104 cmsBool
WriteOffsetArray(cmsIOHANDLER
* io
, _cmsDICarray
* a
, cmsUInt32Number Count
, cmsUInt32Number Length
)
5108 for (i
=0; i
< Count
; i
++) {
5110 if (!WriteOneElem(io
, &a
-> Name
, i
)) return FALSE
;
5111 if (!WriteOneElem(io
, &a
-> Value
, i
)) return FALSE
;
5115 if (!WriteOneElem(io
, &a
-> DisplayName
, i
)) return FALSE
;
5120 if (!WriteOneElem(io
, &a
-> DisplayValue
, i
)) return FALSE
;
5128 cmsBool
ReadOneWChar(cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, wchar_t ** wcstr
)
5131 cmsUInt32Number nChars
;
5133 // Special case for undefined strings (see ICC Votable
5134 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
5135 if (e
-> Offsets
[i
] == 0) {
5141 if (!io
-> Seek(io
, e
-> Offsets
[i
])) return FALSE
;
5143 nChars
= e
->Sizes
[i
] / sizeof(cmsUInt16Number
);
5146 *wcstr
= (wchar_t*) _cmsMallocZero(e
->ContextID
, (nChars
+ 1) * sizeof(wchar_t));
5147 if (*wcstr
== NULL
) return FALSE
;
5149 if (!_cmsReadWCharArray(io
, nChars
, *wcstr
)) {
5150 _cmsFree(e
->ContextID
, *wcstr
);
5154 // End of string marker
5155 (*wcstr
)[nChars
] = 0;
5160 cmsUInt32Number
mywcslen(const wchar_t *s
)
5168 return (cmsUInt32Number
)(p
- s
);
5172 cmsBool
WriteOneWChar(cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, const wchar_t * wcstr
, cmsUInt32Number BaseOffset
)
5174 cmsUInt32Number Before
= io
->Tell(io
);
5177 e
->Offsets
[i
] = Before
- BaseOffset
;
5179 if (wcstr
== NULL
) {
5185 n
= mywcslen(wcstr
);
5186 if (!_cmsWriteWCharArray(io
, n
, wcstr
)) return FALSE
;
5188 e
->Sizes
[i
] = io
->Tell(io
) - Before
;
5193 cmsBool
ReadOneMLUC(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, cmsMLU
** mlu
)
5195 cmsUInt32Number nItems
= 0;
5197 // A way to get null MLUCs
5198 if (e
-> Offsets
[i
] == 0 || e
->Sizes
[i
] == 0) {
5204 if (!io
-> Seek(io
, e
-> Offsets
[i
])) return FALSE
;
5206 *mlu
= (cmsMLU
*) Type_MLU_Read(self
, io
, &nItems
, e
->Sizes
[i
]);
5207 return *mlu
!= NULL
;
5211 cmsBool
WriteOneMLUC(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, const cmsMLU
* mlu
, cmsUInt32Number BaseOffset
)
5213 cmsUInt32Number Before
;
5215 // Special case for undefined strings (see ICC Votable
5216 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
5223 Before
= io
->Tell(io
);
5224 e
->Offsets
[i
] = Before
- BaseOffset
;
5226 if (!Type_MLU_Write(self
, io
, (void*) mlu
, 1)) return FALSE
;
5228 e
->Sizes
[i
] = io
->Tell(io
) - Before
;
5234 void *Type_Dictionary_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
5236 cmsHANDLE hDict
= NULL
;
5237 cmsUInt32Number i
, Count
, Length
;
5238 cmsUInt32Number BaseOffset
;
5240 wchar_t *NameWCS
= NULL
, *ValueWCS
= NULL
;
5241 cmsMLU
*DisplayNameMLU
= NULL
, *DisplayValueMLU
=NULL
;
5243 cmsInt32Number SignedSizeOfTag
= (cmsInt32Number
)SizeOfTag
;
5246 memset(&a
, 0, sizeof(a
));
5248 // Get actual position as a basis for element offsets
5249 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
5251 // Get name-value record count
5252 SignedSizeOfTag
-= sizeof(cmsUInt32Number
);
5253 if (SignedSizeOfTag
< 0) goto Error
;
5254 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
5257 SignedSizeOfTag
-= sizeof(cmsUInt32Number
);
5258 if (SignedSizeOfTag
< 0) goto Error
;
5259 if (!_cmsReadUInt32Number(io
, &Length
)) return NULL
;
5262 // Check for valid lengths
5263 if (Length
!= 16 && Length
!= 24 && Length
!= 32) {
5264 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown record length in dictionary '%d'", Length
);
5268 // Creates an empty dictionary
5269 hDict
= cmsDictAlloc(self
-> ContextID
);
5270 if (hDict
== NULL
) return NULL
;
5272 // On depending on record size, create column arrays
5273 if (!AllocArray(self
-> ContextID
, &a
, Count
, Length
)) goto Error
;
5275 // Read column arrays
5276 if (!ReadOffsetArray(io
, &a
, Count
, Length
, BaseOffset
, &SignedSizeOfTag
)) goto Error
;
5278 // Seek to each element and read it
5279 for (i
=0; i
< Count
; i
++) {
5281 if (!ReadOneWChar(io
, &a
.Name
, i
, &NameWCS
)) goto Error
;
5282 if (!ReadOneWChar(io
, &a
.Value
, i
, &ValueWCS
)) goto Error
;
5285 if (!ReadOneMLUC(self
, io
, &a
.DisplayName
, i
, &DisplayNameMLU
)) goto Error
;
5289 if (!ReadOneMLUC(self
, io
, &a
.DisplayValue
, i
, &DisplayValueMLU
)) goto Error
;
5292 if (NameWCS
== NULL
|| ValueWCS
== NULL
) {
5294 cmsSignalError(self
->ContextID
, cmsERROR_CORRUPTION_DETECTED
, "Bad dictionary Name/Value");
5299 rc
= cmsDictAddEntry(hDict
, NameWCS
, ValueWCS
, DisplayNameMLU
, DisplayValueMLU
);
5302 if (NameWCS
!= NULL
) _cmsFree(self
->ContextID
, NameWCS
);
5303 if (ValueWCS
!= NULL
) _cmsFree(self
->ContextID
, ValueWCS
);
5304 if (DisplayNameMLU
!= NULL
) cmsMLUfree(DisplayNameMLU
);
5305 if (DisplayValueMLU
!= NULL
) cmsMLUfree(DisplayValueMLU
);
5307 if (!rc
) goto Error
;
5312 return (void*) hDict
;
5316 if (hDict
!= NULL
) cmsDictFree(hDict
);
5322 cmsBool
Type_Dictionary_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
5324 cmsHANDLE hDict
= (cmsHANDLE
) Ptr
;
5325 const cmsDICTentry
* p
;
5326 cmsBool AnyName
, AnyValue
;
5327 cmsUInt32Number i
, Count
, Length
;
5328 cmsUInt32Number DirectoryPos
, CurrentPos
, BaseOffset
;
5331 if (hDict
== NULL
) return FALSE
;
5333 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
5335 // Let's inspect the dictionary
5336 Count
= 0; AnyName
= FALSE
; AnyValue
= FALSE
;
5337 for (p
= cmsDictGetEntryList(hDict
); p
!= NULL
; p
= cmsDictNextEntry(p
)) {
5339 if (p
->DisplayName
!= NULL
) AnyName
= TRUE
;
5340 if (p
->DisplayValue
!= NULL
) AnyValue
= TRUE
;
5345 if (AnyName
) Length
+= 8;
5346 if (AnyValue
) Length
+= 8;
5348 if (!_cmsWriteUInt32Number(io
, Count
)) return FALSE
;
5349 if (!_cmsWriteUInt32Number(io
, Length
)) return FALSE
;
5351 // Keep starting position of offsets table
5352 DirectoryPos
= io
->Tell(io
);
5354 // Allocate offsets array
5355 if (!AllocArray(self
->ContextID
, &a
, Count
, Length
)) goto Error
;
5357 // Write a fake directory to be filled latter on
5358 if (!WriteOffsetArray(io
, &a
, Count
, Length
)) goto Error
;
5360 // Write each element. Keep track of the size as well.
5361 p
= cmsDictGetEntryList(hDict
);
5362 for (i
=0; i
< Count
; i
++) {
5364 if (!WriteOneWChar(io
, &a
.Name
, i
, p
->Name
, BaseOffset
)) goto Error
;
5365 if (!WriteOneWChar(io
, &a
.Value
, i
, p
->Value
, BaseOffset
)) goto Error
;
5367 if (p
->DisplayName
!= NULL
) {
5368 if (!WriteOneMLUC(self
, io
, &a
.DisplayName
, i
, p
->DisplayName
, BaseOffset
)) goto Error
;
5371 if (p
->DisplayValue
!= NULL
) {
5372 if (!WriteOneMLUC(self
, io
, &a
.DisplayValue
, i
, p
->DisplayValue
, BaseOffset
)) goto Error
;
5375 p
= cmsDictNextEntry(p
);
5378 // Write the directory
5379 CurrentPos
= io
->Tell(io
);
5380 if (!io
->Seek(io
, DirectoryPos
)) goto Error
;
5382 if (!WriteOffsetArray(io
, &a
, Count
, Length
)) goto Error
;
5384 if (!io
->Seek(io
, CurrentPos
)) goto Error
;
5393 cmsUNUSED_PARAMETER(nItems
);
5398 void* Type_Dictionary_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
5400 return (void*) cmsDictDup((cmsHANDLE
) Ptr
);
5402 cmsUNUSED_PARAMETER(n
);
5403 cmsUNUSED_PARAMETER(self
);
5408 void Type_Dictionary_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
5410 cmsDictFree((cmsHANDLE
) Ptr
);
5411 cmsUNUSED_PARAMETER(self
);
5414 // cicp VideoSignalType
5417 void* Type_VideoSignal_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
5419 cmsVideoSignalType
* cicp
= NULL
;
5421 if (SizeOfTag
!= 8) return NULL
;
5423 if (!_cmsReadUInt32Number(io
, NULL
)) return NULL
;
5425 cicp
= (cmsVideoSignalType
*)_cmsCalloc(self
->ContextID
, 1, sizeof(cmsVideoSignalType
));
5426 if (cicp
== NULL
) return NULL
;
5428 if (!_cmsReadUInt8Number(io
, &cicp
->ColourPrimaries
)) goto Error
;
5429 if (!_cmsReadUInt8Number(io
, &cicp
->TransferCharacteristics
)) goto Error
;
5430 if (!_cmsReadUInt8Number(io
, &cicp
->MatrixCoefficients
)) goto Error
;
5431 if (!_cmsReadUInt8Number(io
, &cicp
->VideoFullRangeFlag
)) goto Error
;
5438 if (cicp
!= NULL
) _cmsFree(self
->ContextID
, cicp
);
5443 cmsBool
Type_VideoSignal_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
5445 cmsVideoSignalType
* cicp
= (cmsVideoSignalType
*)Ptr
;
5447 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
5448 if (!_cmsWriteUInt8Number(io
, cicp
->ColourPrimaries
)) return FALSE
;
5449 if (!_cmsWriteUInt8Number(io
, cicp
->TransferCharacteristics
)) return FALSE
;
5450 if (!_cmsWriteUInt8Number(io
, cicp
->MatrixCoefficients
)) return FALSE
;
5451 if (!_cmsWriteUInt8Number(io
, cicp
->VideoFullRangeFlag
)) return FALSE
;
5455 cmsUNUSED_PARAMETER(self
);
5456 cmsUNUSED_PARAMETER(nItems
);
5459 void* Type_VideoSignal_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
5461 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsVideoSignalType
));
5463 cmsUNUSED_PARAMETER(n
);
5468 void Type_VideoSignal_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
5470 _cmsFree(self
->ContextID
, Ptr
);
5473 // ********************************************************************************
5474 // Type support main routines
5475 // ********************************************************************************
5478 // This is the list of built-in types
5479 static const _cmsTagTypeLinkedList SupportedTagTypes
[] = {
5481 {TYPE_HANDLER(cmsSigChromaticityType
, Chromaticity
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[1] },
5482 {TYPE_HANDLER(cmsSigColorantOrderType
, ColorantOrderType
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[2] },
5483 {TYPE_HANDLER(cmsSigS15Fixed16ArrayType
, S15Fixed16
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[3] },
5484 {TYPE_HANDLER(cmsSigU16Fixed16ArrayType
, U16Fixed16
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[4] },
5485 {TYPE_HANDLER(cmsSigTextType
, Text
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[5] },
5486 {TYPE_HANDLER(cmsSigTextDescriptionType
, Text_Description
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[6] },
5487 {TYPE_HANDLER(cmsSigCurveType
, Curve
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[7] },
5488 {TYPE_HANDLER(cmsSigParametricCurveType
, ParametricCurve
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[8] },
5489 {TYPE_HANDLER(cmsSigDateTimeType
, DateTime
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[9] },
5490 {TYPE_HANDLER(cmsSigLut8Type
, LUT8
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[10] },
5491 {TYPE_HANDLER(cmsSigLut16Type
, LUT16
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[11] },
5492 {TYPE_HANDLER(cmsSigColorantTableType
, ColorantTable
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[12] },
5493 {TYPE_HANDLER(cmsSigNamedColor2Type
, NamedColor
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[13] },
5494 {TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType
, MLU
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[14] },
5495 {TYPE_HANDLER(cmsSigProfileSequenceDescType
, ProfileSequenceDesc
),(_cmsTagTypeLinkedList
*) &SupportedTagTypes
[15] },
5496 {TYPE_HANDLER(cmsSigSignatureType
, Signature
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[16] },
5497 {TYPE_HANDLER(cmsSigMeasurementType
, Measurement
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[17] },
5498 {TYPE_HANDLER(cmsSigDataType
, Data
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[18] },
5499 {TYPE_HANDLER(cmsSigLutAtoBType
, LUTA2B
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[19] },
5500 {TYPE_HANDLER(cmsSigLutBtoAType
, LUTB2A
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[20] },
5501 {TYPE_HANDLER(cmsSigUcrBgType
, UcrBg
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[21] },
5502 {TYPE_HANDLER(cmsSigCrdInfoType
, CrdInfo
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[22] },
5503 {TYPE_HANDLER(cmsSigMultiProcessElementType
, MPE
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[23] },
5504 {TYPE_HANDLER(cmsSigScreeningType
, Screening
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[24] },
5505 {TYPE_HANDLER(cmsSigViewingConditionsType
, ViewingConditions
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[25] },
5506 {TYPE_HANDLER(cmsSigXYZType
, XYZ
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[26] },
5507 {TYPE_HANDLER(cmsCorbisBrokenXYZtype
, XYZ
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[27] },
5508 {TYPE_HANDLER(cmsMonacoBrokenCurveType
, Curve
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[28] },
5509 {TYPE_HANDLER(cmsSigProfileSequenceIdType
, ProfileSequenceId
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[29] },
5510 {TYPE_HANDLER(cmsSigDictType
, Dictionary
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[30] },
5511 {TYPE_HANDLER(cmsSigcicpType
, VideoSignal
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[31] },
5512 {TYPE_HANDLER(cmsSigVcgtType
, vcgt
), NULL
}
5516 _cmsTagTypePluginChunkType _cmsTagTypePluginChunk
= { NULL
};
5520 // Duplicates the zone of memory used by the plug-in in the new context
5522 void DupTagTypeList(struct _cmsContext_struct
* ctx
,
5523 const struct _cmsContext_struct
* src
,
5526 _cmsTagTypePluginChunkType newHead
= { NULL
};
5527 _cmsTagTypeLinkedList
* entry
;
5528 _cmsTagTypeLinkedList
* Anterior
= NULL
;
5529 _cmsTagTypePluginChunkType
* head
= (_cmsTagTypePluginChunkType
*) src
->chunks
[loc
];
5531 // Walk the list copying all nodes
5532 for (entry
= head
->TagTypes
;
5534 entry
= entry
->Next
) {
5536 _cmsTagTypeLinkedList
*newEntry
= ( _cmsTagTypeLinkedList
*) _cmsSubAllocDup(ctx
->MemPool
, entry
, sizeof(_cmsTagTypeLinkedList
));
5538 if (newEntry
== NULL
)
5541 // We want to keep the linked list order, so this is a little bit tricky
5542 newEntry
-> Next
= NULL
;
5544 Anterior
-> Next
= newEntry
;
5546 Anterior
= newEntry
;
5548 if (newHead
.TagTypes
== NULL
)
5549 newHead
.TagTypes
= newEntry
;
5552 ctx
->chunks
[loc
] = _cmsSubAllocDup(ctx
->MemPool
, &newHead
, sizeof(_cmsTagTypePluginChunkType
));
5556 void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct
* ctx
,
5557 const struct _cmsContext_struct
* src
)
5561 // Duplicate the LIST
5562 DupTagTypeList(ctx
, src
, TagTypePlugin
);
5565 static _cmsTagTypePluginChunkType TagTypePluginChunk
= { NULL
};
5566 ctx
->chunks
[TagTypePlugin
] = _cmsSubAllocDup(ctx
->MemPool
, &TagTypePluginChunk
, sizeof(_cmsTagTypePluginChunkType
));
5570 void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct
* ctx
,
5571 const struct _cmsContext_struct
* src
)
5575 // Duplicate the LIST
5576 DupTagTypeList(ctx
, src
, MPEPlugin
);
5579 static _cmsTagTypePluginChunkType TagTypePluginChunk
= { NULL
};
5580 ctx
->chunks
[MPEPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, &TagTypePluginChunk
, sizeof(_cmsTagTypePluginChunkType
));
5586 // Both kind of plug-ins share same structure
5587 cmsBool
_cmsRegisterTagTypePlugin(cmsContext id
, cmsPluginBase
* Data
)
5589 return RegisterTypesPlugin(id
, Data
, TagTypePlugin
);
5592 cmsBool
_cmsRegisterMultiProcessElementPlugin(cmsContext id
, cmsPluginBase
* Data
)
5594 return RegisterTypesPlugin(id
, Data
,MPEPlugin
);
5598 // Wrapper for tag types
5599 cmsTagTypeHandler
* _cmsGetTagTypeHandler(cmsContext ContextID
, cmsTagTypeSignature sig
)
5601 _cmsTagTypePluginChunkType
* ctx
= ( _cmsTagTypePluginChunkType
*) _cmsContextGetClientChunk(ContextID
, TagTypePlugin
);
5603 return GetHandler(sig
, ctx
->TagTypes
, (_cmsTagTypeLinkedList
*) SupportedTagTypes
);
5606 // ********************************************************************************
5607 // Tag support main routines
5608 // ********************************************************************************
5610 typedef struct _cmsTagLinkedList_st
{
5612 cmsTagSignature Signature
;
5613 cmsTagDescriptor Descriptor
;
5614 struct _cmsTagLinkedList_st
* Next
;
5616 } _cmsTagLinkedList
;
5618 // This is the list of built-in tags. The data of this list can be modified by plug-ins
5619 static _cmsTagLinkedList SupportedTags
[] = {
5621 { cmsSigAToB0Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutAtoBType
, cmsSigLut8Type
}, DecideLUTtypeA2B
}, &SupportedTags
[1]},
5622 { cmsSigAToB1Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutAtoBType
, cmsSigLut8Type
}, DecideLUTtypeA2B
}, &SupportedTags
[2]},
5623 { cmsSigAToB2Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutAtoBType
, cmsSigLut8Type
}, DecideLUTtypeA2B
}, &SupportedTags
[3]},
5624 { cmsSigBToA0Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[4]},
5625 { cmsSigBToA1Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[5]},
5626 { cmsSigBToA2Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[6]},
5628 // Allow corbis and its broken XYZ type
5629 { cmsSigRedColorantTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, DecideXYZtype
}, &SupportedTags
[7]},
5630 { cmsSigGreenColorantTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, DecideXYZtype
}, &SupportedTags
[8]},
5631 { cmsSigBlueColorantTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, DecideXYZtype
}, &SupportedTags
[9]},
5633 { cmsSigRedTRCTag
, { 1, 3, { cmsSigCurveType
, cmsSigParametricCurveType
, cmsMonacoBrokenCurveType
}, DecideCurveType
}, &SupportedTags
[10]},
5634 { cmsSigGreenTRCTag
, { 1, 3, { cmsSigCurveType
, cmsSigParametricCurveType
, cmsMonacoBrokenCurveType
}, DecideCurveType
}, &SupportedTags
[11]},
5635 { cmsSigBlueTRCTag
, { 1, 3, { cmsSigCurveType
, cmsSigParametricCurveType
, cmsMonacoBrokenCurveType
}, DecideCurveType
}, &SupportedTags
[12]},
5637 { cmsSigCalibrationDateTimeTag
, { 1, 1, { cmsSigDateTimeType
}, NULL
}, &SupportedTags
[13]},
5638 { cmsSigCharTargetTag
, { 1, 1, { cmsSigTextType
}, NULL
}, &SupportedTags
[14]},
5640 { cmsSigChromaticAdaptationTag
, { 9, 1, { cmsSigS15Fixed16ArrayType
}, NULL
}, &SupportedTags
[15]},
5641 { cmsSigChromaticityTag
, { 1, 1, { cmsSigChromaticityType
}, NULL
}, &SupportedTags
[16]},
5642 { cmsSigColorantOrderTag
, { 1, 1, { cmsSigColorantOrderType
}, NULL
}, &SupportedTags
[17]},
5643 { cmsSigColorantTableTag
, { 1, 1, { cmsSigColorantTableType
}, NULL
}, &SupportedTags
[18]},
5644 { cmsSigColorantTableOutTag
, { 1, 1, { cmsSigColorantTableType
}, NULL
}, &SupportedTags
[19]},
5646 { cmsSigCopyrightTag
, { 1, 3, { cmsSigTextType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextDescriptionType
}, DecideTextType
}, &SupportedTags
[20]},
5647 { cmsSigDateTimeTag
, { 1, 1, { cmsSigDateTimeType
}, NULL
}, &SupportedTags
[21]},
5649 { cmsSigDeviceMfgDescTag
, { 1, 3, { cmsSigTextDescriptionType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextType
}, DecideTextDescType
}, &SupportedTags
[22]},
5650 { cmsSigDeviceModelDescTag
, { 1, 3, { cmsSigTextDescriptionType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextType
}, DecideTextDescType
}, &SupportedTags
[23]},
5652 { cmsSigGamutTag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[24]},
5654 { cmsSigGrayTRCTag
, { 1, 2, { cmsSigCurveType
, cmsSigParametricCurveType
}, DecideCurveType
}, &SupportedTags
[25]},
5655 { cmsSigLuminanceTag
, { 1, 1, { cmsSigXYZType
}, NULL
}, &SupportedTags
[26]},
5657 { cmsSigMediaBlackPointTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, NULL
}, &SupportedTags
[27]},
5658 { cmsSigMediaWhitePointTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, NULL
}, &SupportedTags
[28]},
5660 { cmsSigNamedColor2Tag
, { 1, 1, { cmsSigNamedColor2Type
}, NULL
}, &SupportedTags
[29]},
5662 { cmsSigPreview0Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[30]},
5663 { cmsSigPreview1Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[31]},
5664 { cmsSigPreview2Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[32]},
5666 { cmsSigProfileDescriptionTag
, { 1, 3, { cmsSigTextDescriptionType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextType
}, DecideTextDescType
}, &SupportedTags
[33]},
5667 { cmsSigProfileSequenceDescTag
, { 1, 1, { cmsSigProfileSequenceDescType
}, NULL
}, &SupportedTags
[34]},
5668 { cmsSigTechnologyTag
, { 1, 1, { cmsSigSignatureType
}, NULL
}, &SupportedTags
[35]},
5670 { cmsSigColorimetricIntentImageStateTag
, { 1, 1, { cmsSigSignatureType
}, NULL
}, &SupportedTags
[36]},
5671 { cmsSigPerceptualRenderingIntentGamutTag
, { 1, 1, { cmsSigSignatureType
}, NULL
}, &SupportedTags
[37]},
5672 { cmsSigSaturationRenderingIntentGamutTag
, { 1, 1, { cmsSigSignatureType
}, NULL
}, &SupportedTags
[38]},
5674 { cmsSigMeasurementTag
, { 1, 1, { cmsSigMeasurementType
}, NULL
}, &SupportedTags
[39]},
5676 { cmsSigPs2CRD0Tag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[40]},
5677 { cmsSigPs2CRD1Tag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[41]},
5678 { cmsSigPs2CRD2Tag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[42]},
5679 { cmsSigPs2CRD3Tag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[43]},
5680 { cmsSigPs2CSATag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[44]},
5681 { cmsSigPs2RenderingIntentTag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[45]},
5683 { cmsSigViewingCondDescTag
, { 1, 3, { cmsSigTextDescriptionType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextType
}, DecideTextDescType
}, &SupportedTags
[46]},
5685 { cmsSigUcrBgTag
, { 1, 1, { cmsSigUcrBgType
}, NULL
}, &SupportedTags
[47]},
5686 { cmsSigCrdInfoTag
, { 1, 1, { cmsSigCrdInfoType
}, NULL
}, &SupportedTags
[48]},
5688 { cmsSigDToB0Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[49]},
5689 { cmsSigDToB1Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[50]},
5690 { cmsSigDToB2Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[51]},
5691 { cmsSigDToB3Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[52]},
5692 { cmsSigBToD0Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[53]},
5693 { cmsSigBToD1Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[54]},
5694 { cmsSigBToD2Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[55]},
5695 { cmsSigBToD3Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[56]},
5697 { cmsSigScreeningDescTag
, { 1, 1, { cmsSigTextDescriptionType
}, NULL
}, &SupportedTags
[57]},
5698 { cmsSigViewingConditionsTag
, { 1, 1, { cmsSigViewingConditionsType
}, NULL
}, &SupportedTags
[58]},
5700 { cmsSigScreeningTag
, { 1, 1, { cmsSigScreeningType
}, NULL
}, &SupportedTags
[59]},
5701 { cmsSigVcgtTag
, { 1, 1, { cmsSigVcgtType
}, NULL
}, &SupportedTags
[60]},
5702 { cmsSigMetaTag
, { 1, 1, { cmsSigDictType
}, NULL
}, &SupportedTags
[61]},
5703 { cmsSigProfileSequenceIdTag
, { 1, 1, { cmsSigProfileSequenceIdType
}, NULL
}, &SupportedTags
[62]},
5705 { cmsSigProfileDescriptionMLTag
,{ 1, 1, { cmsSigMultiLocalizedUnicodeType
}, NULL
}, &SupportedTags
[63]},
5706 { cmsSigcicpTag
, { 1, 1, { cmsSigcicpType
}, NULL
}, &SupportedTags
[64]},
5708 { cmsSigArgyllArtsTag
, { 9, 1, { cmsSigS15Fixed16ArrayType
}, NULL
}, NULL
}
5714 ======================= =========================================
5715 cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
5716 cmsSigNamedColorTag ==> Deprecated
5717 cmsSigDataTag ==> Ancient, unused
5718 cmsSigDeviceSettingsTag ==> Deprecated, useless
5722 _cmsTagPluginChunkType _cmsTagPluginChunk
= { NULL
};
5725 // Duplicates the zone of memory used by the plug-in in the new context
5727 void DupTagList(struct _cmsContext_struct
* ctx
,
5728 const struct _cmsContext_struct
* src
)
5730 _cmsTagPluginChunkType newHead
= { NULL
};
5731 _cmsTagLinkedList
* entry
;
5732 _cmsTagLinkedList
* Anterior
= NULL
;
5733 _cmsTagPluginChunkType
* head
= (_cmsTagPluginChunkType
*) src
->chunks
[TagPlugin
];
5735 // Walk the list copying all nodes
5736 for (entry
= head
->Tag
;
5738 entry
= entry
->Next
) {
5740 _cmsTagLinkedList
*newEntry
= ( _cmsTagLinkedList
*) _cmsSubAllocDup(ctx
->MemPool
, entry
, sizeof(_cmsTagLinkedList
));
5742 if (newEntry
== NULL
)
5745 // We want to keep the linked list order, so this is a little bit tricky
5746 newEntry
-> Next
= NULL
;
5748 Anterior
-> Next
= newEntry
;
5750 Anterior
= newEntry
;
5752 if (newHead
.Tag
== NULL
)
5753 newHead
.Tag
= newEntry
;
5756 ctx
->chunks
[TagPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, &newHead
, sizeof(_cmsTagPluginChunkType
));
5759 void _cmsAllocTagPluginChunk(struct _cmsContext_struct
* ctx
,
5760 const struct _cmsContext_struct
* src
)
5764 DupTagList(ctx
, src
);
5767 static _cmsTagPluginChunkType TagPluginChunk
= { NULL
};
5768 ctx
->chunks
[TagPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, &TagPluginChunk
, sizeof(_cmsTagPluginChunkType
));
5773 cmsBool
_cmsRegisterTagPlugin(cmsContext id
, cmsPluginBase
* Data
)
5775 cmsPluginTag
* Plugin
= (cmsPluginTag
*) Data
;
5776 _cmsTagLinkedList
*pt
;
5777 _cmsTagPluginChunkType
* TagPluginChunk
= ( _cmsTagPluginChunkType
*) _cmsContextGetClientChunk(id
, TagPlugin
);
5781 TagPluginChunk
->Tag
= NULL
;
5785 pt
= (_cmsTagLinkedList
*) _cmsPluginMalloc(id
, sizeof(_cmsTagLinkedList
));
5786 if (pt
== NULL
) return FALSE
;
5788 pt
->Signature
= Plugin
->Signature
;
5789 pt
->Descriptor
= Plugin
->Descriptor
;
5790 pt
->Next
= TagPluginChunk
->Tag
;
5792 TagPluginChunk
->Tag
= pt
;
5797 // Return a descriptor for a given tag or NULL
5798 cmsTagDescriptor
* _cmsGetTagDescriptor(cmsContext ContextID
, cmsTagSignature sig
)
5800 _cmsTagLinkedList
* pt
;
5801 _cmsTagPluginChunkType
* TagPluginChunk
= ( _cmsTagPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, TagPlugin
);
5803 for (pt
= TagPluginChunk
->Tag
;
5807 if (sig
== pt
-> Signature
) return &pt
->Descriptor
;
5810 for (pt
= SupportedTags
;
5814 if (sig
== pt
-> Signature
) return &pt
->Descriptor
;