1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2022 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 // Check for overflow
1524 if (Offset
< (SizeOfHeader
+ 8)) goto Error
;
1525 if (((Offset
+ Len
) < Len
) || ((Offset
+ Len
) > SizeOfTag
+ 8)) goto Error
;
1527 // True begin of the string
1528 BeginOfThisString
= Offset
- SizeOfHeader
- 8;
1530 // Adjust to wchar_t elements
1531 mlu
->Entries
[i
].Len
= (Len
* sizeof(wchar_t)) / sizeof(cmsUInt16Number
);
1532 mlu
->Entries
[i
].StrW
= (BeginOfThisString
* sizeof(wchar_t)) / sizeof(cmsUInt16Number
);
1534 // To guess maximum size, add offset + len
1535 EndOfThisString
= BeginOfThisString
+ Len
;
1536 if (EndOfThisString
> LargestPosition
)
1537 LargestPosition
= EndOfThisString
;
1540 // Now read the remaining of tag and fill all strings. Subtract the directory
1541 SizeOfTag
= (LargestPosition
* sizeof(wchar_t)) / sizeof(cmsUInt16Number
);
1550 Block
= (wchar_t*) _cmsMalloc(self
->ContextID
, SizeOfTag
);
1551 if (Block
== NULL
) goto Error
;
1552 NumOfWchar
= SizeOfTag
/ sizeof(wchar_t);
1553 if (!_cmsReadWCharArray(io
, NumOfWchar
, Block
)) {
1554 _cmsFree(self
->ContextID
, Block
);
1559 mlu
->MemPool
= Block
;
1560 mlu
->PoolSize
= SizeOfTag
;
1561 mlu
->PoolUsed
= SizeOfTag
;
1567 if (mlu
) cmsMLUfree(mlu
);
1572 cmsBool
Type_MLU_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
1574 cmsMLU
* mlu
=(cmsMLU
*) Ptr
;
1575 cmsUInt32Number HeaderSize
;
1576 cmsUInt32Number Len
, Offset
;
1581 // Empty placeholder
1582 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
1583 if (!_cmsWriteUInt32Number(io
, 12)) return FALSE
;
1587 if (!_cmsWriteUInt32Number(io
, mlu
->UsedEntries
)) return FALSE
;
1588 if (!_cmsWriteUInt32Number(io
, 12)) return FALSE
;
1590 HeaderSize
= 12 * mlu
->UsedEntries
+ sizeof(_cmsTagBase
);
1592 for (i
=0; i
< mlu
->UsedEntries
; i
++) {
1594 Len
= mlu
->Entries
[i
].Len
;
1595 Offset
= mlu
->Entries
[i
].StrW
;
1597 Len
= (Len
* sizeof(cmsUInt16Number
)) / sizeof(wchar_t);
1598 Offset
= (Offset
* sizeof(cmsUInt16Number
)) / sizeof(wchar_t) + HeaderSize
+ 8;
1600 if (!_cmsWriteUInt16Number(io
, mlu
->Entries
[i
].Language
)) return FALSE
;
1601 if (!_cmsWriteUInt16Number(io
, mlu
->Entries
[i
].Country
)) return FALSE
;
1602 if (!_cmsWriteUInt32Number(io
, Len
)) return FALSE
;
1603 if (!_cmsWriteUInt32Number(io
, Offset
)) return FALSE
;
1606 if (!_cmsWriteWCharArray(io
, mlu
->PoolUsed
/ sizeof(wchar_t), (wchar_t*) mlu
->MemPool
)) return FALSE
;
1610 cmsUNUSED_PARAMETER(nItems
);
1611 cmsUNUSED_PARAMETER(self
);
1616 void* Type_MLU_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
1618 return (void*) cmsMLUdup((cmsMLU
*) Ptr
);
1620 cmsUNUSED_PARAMETER(n
);
1621 cmsUNUSED_PARAMETER(self
);
1625 void Type_MLU_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
1627 cmsMLUfree((cmsMLU
*) Ptr
);
1630 cmsUNUSED_PARAMETER(self
);
1634 // ********************************************************************************
1635 // Type cmsSigLut8Type
1636 // ********************************************************************************
1638 // Decide which LUT type to use on writing
1640 cmsTagTypeSignature
DecideLUTtypeA2B(cmsFloat64Number ICCVersion
, const void *Data
)
1642 cmsPipeline
* Lut
= (cmsPipeline
*) Data
;
1644 if (ICCVersion
< 4.0) {
1645 if (Lut
->SaveAs8Bits
) return cmsSigLut8Type
;
1646 return cmsSigLut16Type
;
1649 return cmsSigLutAtoBType
;
1654 cmsTagTypeSignature
DecideLUTtypeB2A(cmsFloat64Number ICCVersion
, const void *Data
)
1656 cmsPipeline
* Lut
= (cmsPipeline
*) Data
;
1658 if (ICCVersion
< 4.0) {
1659 if (Lut
->SaveAs8Bits
) return cmsSigLut8Type
;
1660 return cmsSigLut16Type
;
1663 return cmsSigLutBtoAType
;
1668 This structure represents a colour transform using tables of 8-bit precision.
1669 This type contains four processing elements: a 3 by 3 matrix (which shall be
1670 the identity matrix unless the input colour space is XYZ), a set of one dimensional
1671 input tables, a multidimensional lookup table, and a set of one dimensional output
1672 tables. Data is processed using these elements via the following sequence:
1673 (matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables)
1675 Byte Position Field Length (bytes) Content Encoded as...
1676 8 1 Number of Input Channels (i) uInt8Number
1677 9 1 Number of Output Channels (o) uInt8Number
1678 10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number
1679 11 1 Reserved for padding (fill with 00h)
1681 12..15 4 Encoded e00 parameter s15Fixed16Number
1685 // Read 8 bit tables as gamma functions
1687 cmsBool
Read8bitTables(cmsContext ContextID
, cmsIOHANDLER
* io
, cmsPipeline
* lut
, cmsUInt32Number nChannels
)
1689 cmsUInt8Number
* Temp
= NULL
;
1690 cmsUInt32Number i
, j
;
1691 cmsToneCurve
* Tables
[cmsMAXCHANNELS
];
1693 if (nChannels
> cmsMAXCHANNELS
) return FALSE
;
1694 if (nChannels
<= 0) return FALSE
;
1696 memset(Tables
, 0, sizeof(Tables
));
1698 Temp
= (cmsUInt8Number
*) _cmsMalloc(ContextID
, 256);
1699 if (Temp
== NULL
) return FALSE
;
1701 for (i
=0; i
< nChannels
; i
++) {
1702 Tables
[i
] = cmsBuildTabulatedToneCurve16(ContextID
, 256, NULL
);
1703 if (Tables
[i
] == NULL
) goto Error
;
1706 for (i
=0; i
< nChannels
; i
++) {
1708 if (io
->Read(io
, Temp
, 256, 1) != 1) goto Error
;
1710 for (j
=0; j
< 256; j
++)
1711 Tables
[i
]->Table16
[j
] = (cmsUInt16Number
) FROM_8_TO_16(Temp
[j
]);
1714 _cmsFree(ContextID
, Temp
);
1717 if (!cmsPipelineInsertStage(lut
, cmsAT_END
, cmsStageAllocToneCurves(ContextID
, nChannels
, Tables
)))
1720 for (i
=0; i
< nChannels
; i
++)
1721 cmsFreeToneCurve(Tables
[i
]);
1726 for (i
=0; i
< nChannels
; i
++) {
1727 if (Tables
[i
]) cmsFreeToneCurve(Tables
[i
]);
1730 if (Temp
) _cmsFree(ContextID
, Temp
);
1736 cmsBool
Write8bitTables(cmsContext ContextID
, cmsIOHANDLER
* io
, cmsUInt32Number n
, _cmsStageToneCurvesData
* Tables
)
1742 for (i
=0; i
< n
; i
++) {
1746 // Usual case of identity curves
1747 if ((Tables
->TheCurves
[i
]->nEntries
== 2) &&
1748 (Tables
->TheCurves
[i
]->Table16
[0] == 0) &&
1749 (Tables
->TheCurves
[i
]->Table16
[1] == 65535)) {
1751 for (j
=0; j
< 256; j
++) {
1752 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) j
)) return FALSE
;
1756 if (Tables
->TheCurves
[i
]->nEntries
!= 256) {
1757 cmsSignalError(ContextID
, cmsERROR_RANGE
, "LUT8 needs 256 entries on prelinearization");
1761 for (j
=0; j
< 256; j
++) {
1763 val
= (cmsUInt8Number
) FROM_16_TO_8(Tables
->TheCurves
[i
]->Table16
[j
]);
1765 if (!_cmsWriteUInt8Number(io
, val
)) return FALSE
;
1775 cmsUInt32Number
uipow(cmsUInt32Number n
, cmsUInt32Number a
, cmsUInt32Number b
)
1777 cmsUInt32Number rv
= 1, rc
;
1779 if (a
== 0) return 0;
1780 if (n
== 0) return 0;
1782 for (; b
> 0; b
--) {
1786 // Check for overflow
1787 if (rv
> UINT_MAX
/ a
) return (cmsUInt32Number
) -1;
1793 if (rv
!= rc
/ n
) return (cmsUInt32Number
) -1;
1798 // That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
1799 // 8 bit lut may be scaled easily to v4 PCS, but we need also to properly adjust
1800 // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
1803 void *Type_LUT8_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
1805 cmsUInt8Number InputChannels
, OutputChannels
, CLUTpoints
;
1806 cmsUInt8Number
* Temp
= NULL
;
1807 cmsPipeline
* NewLUT
= NULL
;
1808 cmsUInt32Number nTabSize
, i
;
1809 cmsFloat64Number Matrix
[3*3];
1813 if (!_cmsReadUInt8Number(io
, &InputChannels
)) goto Error
;
1814 if (!_cmsReadUInt8Number(io
, &OutputChannels
)) goto Error
;
1815 if (!_cmsReadUInt8Number(io
, &CLUTpoints
)) goto Error
;
1817 if (CLUTpoints
== 1) goto Error
; // Impossible value, 0 for no CLUT and then 2 at least
1820 if (!_cmsReadUInt8Number(io
, NULL
)) goto Error
;
1823 if (InputChannels
== 0 || InputChannels
> cmsMAXCHANNELS
) goto Error
;
1824 if (OutputChannels
== 0 || OutputChannels
> cmsMAXCHANNELS
) goto Error
;
1826 // Allocates an empty Pipeline
1827 NewLUT
= cmsPipelineAlloc(self
->ContextID
, InputChannels
, OutputChannels
);
1828 if (NewLUT
== NULL
) goto Error
;
1831 if (!_cmsRead15Fixed16Number(io
, &Matrix
[0])) goto Error
;
1832 if (!_cmsRead15Fixed16Number(io
, &Matrix
[1])) goto Error
;
1833 if (!_cmsRead15Fixed16Number(io
, &Matrix
[2])) goto Error
;
1834 if (!_cmsRead15Fixed16Number(io
, &Matrix
[3])) goto Error
;
1835 if (!_cmsRead15Fixed16Number(io
, &Matrix
[4])) goto Error
;
1836 if (!_cmsRead15Fixed16Number(io
, &Matrix
[5])) goto Error
;
1837 if (!_cmsRead15Fixed16Number(io
, &Matrix
[6])) goto Error
;
1838 if (!_cmsRead15Fixed16Number(io
, &Matrix
[7])) goto Error
;
1839 if (!_cmsRead15Fixed16Number(io
, &Matrix
[8])) goto Error
;
1842 // Only operates if not identity...
1843 if ((InputChannels
== 3) && !_cmsMAT3isIdentity((cmsMAT3
*) Matrix
)) {
1845 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_BEGIN
, cmsStageAllocMatrix(self
->ContextID
, 3, 3, Matrix
, NULL
)))
1850 if (!Read8bitTables(self
->ContextID
, io
, NewLUT
, InputChannels
)) goto Error
;
1852 // Get 3D CLUT. Check the overflow....
1853 nTabSize
= uipow(OutputChannels
, CLUTpoints
, InputChannels
);
1854 if (nTabSize
== (cmsUInt32Number
) -1) goto Error
;
1857 cmsUInt16Number
*PtrW
, *T
;
1859 PtrW
= T
= (cmsUInt16Number
*) _cmsCalloc(self
->ContextID
, nTabSize
, sizeof(cmsUInt16Number
));
1860 if (T
== NULL
) goto Error
;
1862 Temp
= (cmsUInt8Number
*) _cmsMalloc(self
->ContextID
, nTabSize
);
1864 _cmsFree(self
->ContextID
, T
);
1868 if (io
->Read(io
, Temp
, nTabSize
, 1) != 1) {
1869 _cmsFree(self
->ContextID
, T
);
1870 _cmsFree(self
->ContextID
, Temp
);
1874 for (i
= 0; i
< nTabSize
; i
++) {
1876 *PtrW
++ = FROM_8_TO_16(Temp
[i
]);
1878 _cmsFree(self
->ContextID
, Temp
);
1881 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, cmsStageAllocCLut16bit(self
->ContextID
, CLUTpoints
, InputChannels
, OutputChannels
, T
))) {
1882 _cmsFree(self
->ContextID
, T
);
1885 _cmsFree(self
->ContextID
, T
);
1889 // Get output tables
1890 if (!Read8bitTables(self
->ContextID
, io
, NewLUT
, OutputChannels
)) goto Error
;
1896 if (NewLUT
!= NULL
) cmsPipelineFree(NewLUT
);
1899 cmsUNUSED_PARAMETER(SizeOfTag
);
1902 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1904 cmsBool
Type_LUT8_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
1906 cmsUInt32Number j
, nTabSize
, i
;
1908 cmsPipeline
* NewLUT
= (cmsPipeline
*) Ptr
;
1910 _cmsStageToneCurvesData
* PreMPE
= NULL
, *PostMPE
= NULL
;
1911 _cmsStageMatrixData
* MatMPE
= NULL
;
1912 _cmsStageCLutData
* clut
= NULL
;
1913 cmsUInt32Number clutPoints
;
1915 // Disassemble the LUT into components.
1916 mpe
= NewLUT
-> Elements
;
1917 if (mpe
->Type
== cmsSigMatrixElemType
) {
1919 if (mpe
->InputChannels
!= 3 || mpe
->OutputChannels
!= 3) return FALSE
;
1920 MatMPE
= (_cmsStageMatrixData
*) mpe
->Data
;
1924 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCurveSetElemType
) {
1925 PreMPE
= (_cmsStageToneCurvesData
*) mpe
->Data
;
1929 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCLutElemType
) {
1930 clut
= (_cmsStageCLutData
*) mpe
-> Data
;
1934 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCurveSetElemType
) {
1935 PostMPE
= (_cmsStageToneCurvesData
*) mpe
->Data
;
1939 // That should be all
1941 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "LUT is not suitable to be saved as LUT8");
1948 // Lut8 only allows same CLUT points in all dimensions
1949 clutPoints
= clut
->Params
->nSamples
[0];
1950 for (i
= 1; i
< cmsPipelineInputChannels(NewLUT
); i
++) {
1951 if (clut
->Params
->nSamples
[i
] != clutPoints
) {
1952 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "LUT with different samples per dimension not suitable to be saved as LUT16");
1958 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
)cmsPipelineInputChannels(NewLUT
))) return FALSE
;
1959 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
)cmsPipelineOutputChannels(NewLUT
))) return FALSE
;
1960 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) clutPoints
)) return FALSE
;
1961 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
; // Padding
1963 if (MatMPE
!= NULL
) {
1965 for (i
= 0; i
< 9; i
++)
1967 if (!_cmsWrite15Fixed16Number(io
, MatMPE
->Double
[i
])) return FALSE
;
1972 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
1973 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1974 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1975 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1976 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
1977 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1978 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1979 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
1980 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
1983 // The prelinearization table
1984 if (!Write8bitTables(self
->ContextID
, io
, NewLUT
->InputChannels
, PreMPE
)) return FALSE
;
1986 nTabSize
= uipow(NewLUT
->OutputChannels
, clutPoints
, NewLUT
->InputChannels
);
1987 if (nTabSize
== (cmsUInt32Number
) -1) return FALSE
;
1993 for (j
=0; j
< nTabSize
; j
++) {
1995 val
= (cmsUInt8Number
) FROM_16_TO_8(clut
->Tab
.T
[j
]);
1996 if (!_cmsWriteUInt8Number(io
, val
)) return FALSE
;
2001 // The postlinearization table
2002 if (!Write8bitTables(self
->ContextID
, io
, NewLUT
->OutputChannels
, PostMPE
)) return FALSE
;
2006 cmsUNUSED_PARAMETER(nItems
);
2011 void* Type_LUT8_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
2013 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
2015 cmsUNUSED_PARAMETER(n
);
2016 cmsUNUSED_PARAMETER(self
);
2020 void Type_LUT8_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
2022 cmsPipelineFree((cmsPipeline
*) Ptr
);
2025 cmsUNUSED_PARAMETER(self
);
2028 // ********************************************************************************
2029 // Type cmsSigLut16Type
2030 // ********************************************************************************
2032 // Read 16 bit tables as gamma functions
2034 cmsBool
Read16bitTables(cmsContext ContextID
, cmsIOHANDLER
* io
, cmsPipeline
* lut
,
2035 cmsUInt32Number nChannels
, cmsUInt32Number nEntries
)
2038 cmsToneCurve
* Tables
[cmsMAXCHANNELS
];
2040 // Maybe an empty table? (this is a lcms extension)
2041 if (nEntries
<= 0) return TRUE
;
2043 // Check for malicious profiles
2044 if (nEntries
< 2) return FALSE
;
2045 if (nChannels
> cmsMAXCHANNELS
) return FALSE
;
2047 // Init table to zero
2048 memset(Tables
, 0, sizeof(Tables
));
2050 for (i
=0; i
< nChannels
; i
++) {
2052 Tables
[i
] = cmsBuildTabulatedToneCurve16(ContextID
, nEntries
, NULL
);
2053 if (Tables
[i
] == NULL
) goto Error
;
2055 if (!_cmsReadUInt16Array(io
, nEntries
, Tables
[i
]->Table16
)) goto Error
;
2059 // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code)
2060 if (!cmsPipelineInsertStage(lut
, cmsAT_END
, cmsStageAllocToneCurves(ContextID
, nChannels
, Tables
)))
2063 for (i
=0; i
< nChannels
; i
++)
2064 cmsFreeToneCurve(Tables
[i
]);
2069 for (i
=0; i
< nChannels
; i
++) {
2070 if (Tables
[i
]) cmsFreeToneCurve(Tables
[i
]);
2077 cmsBool
Write16bitTables(cmsContext ContextID
, cmsIOHANDLER
* io
, _cmsStageToneCurvesData
* Tables
)
2081 cmsUInt16Number val
;
2082 cmsUInt32Number nEntries
;
2084 _cmsAssert(Tables
!= NULL
);
2086 for (i
=0; i
< Tables
->nCurves
; i
++) {
2088 nEntries
= Tables
->TheCurves
[i
]->nEntries
;
2090 for (j
=0; j
< nEntries
; j
++) {
2092 val
= Tables
->TheCurves
[i
]->Table16
[j
];
2093 if (!_cmsWriteUInt16Number(io
, val
)) return FALSE
;
2098 cmsUNUSED_PARAMETER(ContextID
);
2102 void *Type_LUT16_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
2104 cmsUInt8Number InputChannels
, OutputChannels
, CLUTpoints
;
2105 cmsPipeline
* NewLUT
= NULL
;
2106 cmsUInt32Number nTabSize
;
2107 cmsFloat64Number Matrix
[3*3];
2108 cmsUInt16Number InputEntries
, OutputEntries
;
2112 if (!_cmsReadUInt8Number(io
, &InputChannels
)) return NULL
;
2113 if (!_cmsReadUInt8Number(io
, &OutputChannels
)) return NULL
;
2114 if (!_cmsReadUInt8Number(io
, &CLUTpoints
)) return NULL
; // 255 maximum
2117 if (!_cmsReadUInt8Number(io
, NULL
)) return NULL
;
2120 if (InputChannels
== 0 || InputChannels
> cmsMAXCHANNELS
) goto Error
;
2121 if (OutputChannels
== 0 || OutputChannels
> cmsMAXCHANNELS
) goto Error
;
2123 // Allocates an empty LUT
2124 NewLUT
= cmsPipelineAlloc(self
->ContextID
, InputChannels
, OutputChannels
);
2125 if (NewLUT
== NULL
) goto Error
;
2128 if (!_cmsRead15Fixed16Number(io
, &Matrix
[0])) goto Error
;
2129 if (!_cmsRead15Fixed16Number(io
, &Matrix
[1])) goto Error
;
2130 if (!_cmsRead15Fixed16Number(io
, &Matrix
[2])) goto Error
;
2131 if (!_cmsRead15Fixed16Number(io
, &Matrix
[3])) goto Error
;
2132 if (!_cmsRead15Fixed16Number(io
, &Matrix
[4])) goto Error
;
2133 if (!_cmsRead15Fixed16Number(io
, &Matrix
[5])) goto Error
;
2134 if (!_cmsRead15Fixed16Number(io
, &Matrix
[6])) goto Error
;
2135 if (!_cmsRead15Fixed16Number(io
, &Matrix
[7])) goto Error
;
2136 if (!_cmsRead15Fixed16Number(io
, &Matrix
[8])) goto Error
;
2139 // Only operates on 3 channels
2140 if ((InputChannels
== 3) && !_cmsMAT3isIdentity((cmsMAT3
*) Matrix
)) {
2142 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, cmsStageAllocMatrix(self
->ContextID
, 3, 3, Matrix
, NULL
)))
2146 if (!_cmsReadUInt16Number(io
, &InputEntries
)) goto Error
;
2147 if (!_cmsReadUInt16Number(io
, &OutputEntries
)) goto Error
;
2149 if (InputEntries
> 0x7FFF || OutputEntries
> 0x7FFF) goto Error
;
2150 if (CLUTpoints
== 1) goto Error
; // Impossible value, 0 for no CLUT and then 2 at least
2153 if (!Read16bitTables(self
->ContextID
, io
, NewLUT
, InputChannels
, InputEntries
)) goto Error
;
2156 nTabSize
= uipow(OutputChannels
, CLUTpoints
, InputChannels
);
2157 if (nTabSize
== (cmsUInt32Number
) -1) goto Error
;
2162 T
= (cmsUInt16Number
*) _cmsCalloc(self
->ContextID
, nTabSize
, sizeof(cmsUInt16Number
));
2163 if (T
== NULL
) goto Error
;
2165 if (!_cmsReadUInt16Array(io
, nTabSize
, T
)) {
2166 _cmsFree(self
->ContextID
, T
);
2170 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, cmsStageAllocCLut16bit(self
->ContextID
, CLUTpoints
, InputChannels
, OutputChannels
, T
))) {
2171 _cmsFree(self
->ContextID
, T
);
2174 _cmsFree(self
->ContextID
, T
);
2178 // Get output tables
2179 if (!Read16bitTables(self
->ContextID
, io
, NewLUT
, OutputChannels
, OutputEntries
)) goto Error
;
2185 if (NewLUT
!= NULL
) cmsPipelineFree(NewLUT
);
2188 cmsUNUSED_PARAMETER(SizeOfTag
);
2191 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
2192 // Some empty defaults are created for missing parts
2195 cmsBool
Type_LUT16_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
2197 cmsUInt32Number nTabSize
;
2198 cmsPipeline
* NewLUT
= (cmsPipeline
*) Ptr
;
2200 _cmsStageToneCurvesData
* PreMPE
= NULL
, *PostMPE
= NULL
;
2201 _cmsStageMatrixData
* MatMPE
= NULL
;
2202 _cmsStageCLutData
* clut
= NULL
;
2203 cmsUInt32Number i
, InputChannels
, OutputChannels
, clutPoints
;
2205 // Disassemble the LUT into components.
2206 mpe
= NewLUT
-> Elements
;
2207 if (mpe
!= NULL
&& mpe
->Type
== cmsSigMatrixElemType
) {
2209 MatMPE
= (_cmsStageMatrixData
*) mpe
->Data
;
2210 if (mpe
->InputChannels
!= 3 || mpe
->OutputChannels
!= 3) return FALSE
;
2215 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCurveSetElemType
) {
2216 PreMPE
= (_cmsStageToneCurvesData
*) mpe
->Data
;
2220 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCLutElemType
) {
2221 clut
= (_cmsStageCLutData
*) mpe
-> Data
;
2225 if (mpe
!= NULL
&& mpe
->Type
== cmsSigCurveSetElemType
) {
2226 PostMPE
= (_cmsStageToneCurvesData
*) mpe
->Data
;
2230 // That should be all
2232 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "LUT is not suitable to be saved as LUT16");
2236 InputChannels
= cmsPipelineInputChannels(NewLUT
);
2237 OutputChannels
= cmsPipelineOutputChannels(NewLUT
);
2242 // Lut16 only allows same CLUT points in all dimensions
2243 clutPoints
= clut
->Params
->nSamples
[0];
2244 for (i
= 1; i
< InputChannels
; i
++) {
2245 if (clut
->Params
->nSamples
[i
] != clutPoints
) {
2246 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "LUT with different samples per dimension not suitable to be saved as LUT16");
2252 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) InputChannels
)) return FALSE
;
2253 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) OutputChannels
)) return FALSE
;
2254 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) clutPoints
)) return FALSE
;
2255 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
; // Padding
2257 if (MatMPE
!= NULL
) {
2259 for (i
= 0; i
< 9; i
++)
2261 if (!_cmsWrite15Fixed16Number(io
, MatMPE
->Double
[i
])) return FALSE
;
2267 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
2268 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2269 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2270 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2271 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
2272 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2273 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2274 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2275 if (!_cmsWrite15Fixed16Number(io
, 1)) return FALSE
;
2279 if (PreMPE
!= NULL
) {
2280 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) PreMPE
->TheCurves
[0]->nEntries
)) return FALSE
;
2282 if (!_cmsWriteUInt16Number(io
, 2)) return FALSE
;
2285 if (PostMPE
!= NULL
) {
2286 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) PostMPE
->TheCurves
[0]->nEntries
)) return FALSE
;
2288 if (!_cmsWriteUInt16Number(io
, 2)) return FALSE
;
2292 // The prelinearization table
2294 if (PreMPE
!= NULL
) {
2295 if (!Write16bitTables(self
->ContextID
, io
, PreMPE
)) return FALSE
;
2298 for (i
=0; i
< InputChannels
; i
++) {
2300 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
;
2301 if (!_cmsWriteUInt16Number(io
, 0xffff)) return FALSE
;
2305 nTabSize
= uipow(OutputChannels
, clutPoints
, InputChannels
);
2306 if (nTabSize
== (cmsUInt32Number
) -1) return FALSE
;
2310 if (!_cmsWriteUInt16Array(io
, nTabSize
, clut
->Tab
.T
)) return FALSE
;
2314 // The postlinearization table
2315 if (PostMPE
!= NULL
) {
2316 if (!Write16bitTables(self
->ContextID
, io
, PostMPE
)) return FALSE
;
2319 for (i
=0; i
< OutputChannels
; i
++) {
2321 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
;
2322 if (!_cmsWriteUInt16Number(io
, 0xffff)) return FALSE
;
2328 cmsUNUSED_PARAMETER(nItems
);
2332 void* Type_LUT16_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
2334 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
2336 cmsUNUSED_PARAMETER(n
);
2337 cmsUNUSED_PARAMETER(self
);
2341 void Type_LUT16_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
2343 cmsPipelineFree((cmsPipeline
*) Ptr
);
2346 cmsUNUSED_PARAMETER(self
);
2350 // ********************************************************************************
2351 // Type cmsSigLutAToBType
2352 // ********************************************************************************
2355 // V4 stuff. Read matrix for LutAtoB and LutBtoA
2358 cmsStage
* ReadMatrix(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number Offset
)
2360 cmsFloat64Number dMat
[3*3];
2361 cmsFloat64Number dOff
[3];
2365 if (!io
-> Seek(io
, Offset
)) return NULL
;
2368 if (!_cmsRead15Fixed16Number(io
, &dMat
[0])) return NULL
;
2369 if (!_cmsRead15Fixed16Number(io
, &dMat
[1])) return NULL
;
2370 if (!_cmsRead15Fixed16Number(io
, &dMat
[2])) return NULL
;
2371 if (!_cmsRead15Fixed16Number(io
, &dMat
[3])) return NULL
;
2372 if (!_cmsRead15Fixed16Number(io
, &dMat
[4])) return NULL
;
2373 if (!_cmsRead15Fixed16Number(io
, &dMat
[5])) return NULL
;
2374 if (!_cmsRead15Fixed16Number(io
, &dMat
[6])) return NULL
;
2375 if (!_cmsRead15Fixed16Number(io
, &dMat
[7])) return NULL
;
2376 if (!_cmsRead15Fixed16Number(io
, &dMat
[8])) return NULL
;
2378 if (!_cmsRead15Fixed16Number(io
, &dOff
[0])) return NULL
;
2379 if (!_cmsRead15Fixed16Number(io
, &dOff
[1])) return NULL
;
2380 if (!_cmsRead15Fixed16Number(io
, &dOff
[2])) return NULL
;
2382 Mat
= cmsStageAllocMatrix(self
->ContextID
, 3, 3, dMat
, dOff
);
2390 // V4 stuff. Read CLUT part for LutAtoB and LutBtoA
2393 cmsStage
* ReadCLUT(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
,
2394 cmsUInt32Number Offset
, cmsUInt32Number InputChannels
, cmsUInt32Number OutputChannels
)
2396 cmsUInt8Number gridPoints8
[cmsMAXCHANNELS
]; // Number of grid points in each dimension.
2397 cmsUInt32Number GridPoints
[cmsMAXCHANNELS
], i
;
2398 cmsUInt8Number Precision
;
2400 _cmsStageCLutData
* Data
;
2402 if (!io
-> Seek(io
, Offset
)) return NULL
;
2403 if (io
-> Read(io
, gridPoints8
, cmsMAXCHANNELS
, 1) != 1) return NULL
;
2406 for (i
=0; i
< cmsMAXCHANNELS
; i
++) {
2408 if (gridPoints8
[i
] == 1) return NULL
; // Impossible value, 0 for no CLUT and then 2 at least
2409 GridPoints
[i
] = gridPoints8
[i
];
2412 if (!_cmsReadUInt8Number(io
, &Precision
)) return NULL
;
2414 if (!_cmsReadUInt8Number(io
, NULL
)) return NULL
;
2415 if (!_cmsReadUInt8Number(io
, NULL
)) return NULL
;
2416 if (!_cmsReadUInt8Number(io
, NULL
)) return NULL
;
2418 CLUT
= cmsStageAllocCLut16bitGranular(self
->ContextID
, GridPoints
, InputChannels
, OutputChannels
, NULL
);
2419 if (CLUT
== NULL
) return NULL
;
2421 Data
= (_cmsStageCLutData
*) CLUT
->Data
;
2423 // Precision can be 1 or 2 bytes
2424 if (Precision
== 1) {
2428 for (i
=0; i
< Data
->nEntries
; i
++) {
2430 if (io
->Read(io
, &v
, sizeof(cmsUInt8Number
), 1) != 1) {
2434 Data
->Tab
.T
[i
] = FROM_8_TO_16(v
);
2439 if (Precision
== 2) {
2441 if (!_cmsReadUInt16Array(io
, Data
->nEntries
, Data
->Tab
.T
)) {
2448 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown precision of '%d'", Precision
);
2456 cmsToneCurve
* ReadEmbeddedCurve(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
)
2458 cmsTagTypeSignature BaseType
;
2459 cmsUInt32Number nItems
;
2461 BaseType
= _cmsReadTypeBase(io
);
2464 case cmsSigCurveType
:
2465 return (cmsToneCurve
*) Type_Curve_Read(self
, io
, &nItems
, 0);
2467 case cmsSigParametricCurveType
:
2468 return (cmsToneCurve
*) Type_ParametricCurve_Read(self
, io
, &nItems
, 0);
2474 _cmsTagSignature2String(String
, (cmsTagSignature
) BaseType
);
2475 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown curve type '%s'", String
);
2482 // Read a set of curves from specific offset
2484 cmsStage
* ReadSetOfCurves(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number Offset
, cmsUInt32Number nCurves
)
2486 cmsToneCurve
* Curves
[cmsMAXCHANNELS
];
2488 cmsStage
* Lin
= NULL
;
2490 if (nCurves
> cmsMAXCHANNELS
) return FALSE
;
2492 if (!io
-> Seek(io
, Offset
)) return FALSE
;
2494 for (i
=0; i
< nCurves
; i
++)
2497 for (i
=0; i
< nCurves
; i
++) {
2499 Curves
[i
] = ReadEmbeddedCurve(self
, io
);
2500 if (Curves
[i
] == NULL
) goto Error
;
2501 if (!_cmsReadAlignment(io
)) goto Error
;
2505 Lin
= cmsStageAllocToneCurves(self
->ContextID
, nCurves
, Curves
);
2508 for (i
=0; i
< nCurves
; i
++)
2509 cmsFreeToneCurve(Curves
[i
]);
2517 // This structure represents a colour transform. The type contains up to five processing
2518 // elements which are stored in the AtoBTag tag in the following order: a set of one
2519 // dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves,
2520 // a multidimensional lookup table, and a set of one dimensional output curves.
2521 // Data are processed using these elements via the following sequence:
2523 //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves).
2526 It is possible to use any or all of these processing elements. At least one processing element
2527 must be included.Only the following combinations are allowed:
2532 A - CLUT - M - Matrix - B
2537 void* Type_LUTA2B_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
2539 cmsUInt32Number BaseOffset
;
2540 cmsUInt8Number inputChan
; // Number of input channels
2541 cmsUInt8Number outputChan
; // Number of output channels
2542 cmsUInt32Number offsetB
; // Offset to first "B" curve
2543 cmsUInt32Number offsetMat
; // Offset to matrix
2544 cmsUInt32Number offsetM
; // Offset to first "M" curve
2545 cmsUInt32Number offsetC
; // Offset to CLUT
2546 cmsUInt32Number offsetA
; // Offset to first "A" curve
2547 cmsPipeline
* NewLUT
= NULL
;
2550 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
2552 if (!_cmsReadUInt8Number(io
, &inputChan
)) return NULL
;
2553 if (!_cmsReadUInt8Number(io
, &outputChan
)) return NULL
;
2555 if (!_cmsReadUInt16Number(io
, NULL
)) return NULL
;
2557 if (!_cmsReadUInt32Number(io
, &offsetB
)) return NULL
;
2558 if (!_cmsReadUInt32Number(io
, &offsetMat
)) return NULL
;
2559 if (!_cmsReadUInt32Number(io
, &offsetM
)) return NULL
;
2560 if (!_cmsReadUInt32Number(io
, &offsetC
)) return NULL
;
2561 if (!_cmsReadUInt32Number(io
, &offsetA
)) return NULL
;
2563 if (inputChan
== 0 || inputChan
>= cmsMAXCHANNELS
) return NULL
;
2564 if (outputChan
== 0 || outputChan
>= cmsMAXCHANNELS
) return NULL
;
2566 // Allocates an empty LUT
2567 NewLUT
= cmsPipelineAlloc(self
->ContextID
, inputChan
, outputChan
);
2568 if (NewLUT
== NULL
) return NULL
;
2571 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetA
, inputChan
)))
2576 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadCLUT(self
, io
, BaseOffset
+ offsetC
, inputChan
, outputChan
)))
2581 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetM
, outputChan
)))
2585 if (offsetMat
!= 0) {
2586 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadMatrix(self
, io
, BaseOffset
+ offsetMat
)))
2591 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetB
, outputChan
)))
2598 cmsPipelineFree(NewLUT
);
2601 cmsUNUSED_PARAMETER(SizeOfTag
);
2604 // Write a set of curves
2606 cmsBool
WriteMatrix(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsStage
* mpe
)
2608 cmsUInt32Number i
, n
;
2610 _cmsStageMatrixData
* m
= (_cmsStageMatrixData
*) mpe
-> Data
;
2612 n
= mpe
->InputChannels
* mpe
->OutputChannels
;
2615 for (i
= 0; i
< n
; i
++)
2617 if (!_cmsWrite15Fixed16Number(io
, m
->Double
[i
])) return FALSE
;
2620 if (m
->Offset
!= NULL
) {
2622 for (i
= 0; i
< mpe
->OutputChannels
; i
++)
2624 if (!_cmsWrite15Fixed16Number(io
, m
->Offset
[i
])) return FALSE
;
2628 for (i
= 0; i
< mpe
->OutputChannels
; i
++)
2630 if (!_cmsWrite15Fixed16Number(io
, 0)) return FALSE
;
2637 cmsUNUSED_PARAMETER(self
);
2641 // Write a set of curves
2643 cmsBool
WriteSetOfCurves(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsTagTypeSignature Type
, cmsStage
* mpe
)
2645 cmsUInt32Number i
, n
;
2646 cmsTagTypeSignature CurrentType
;
2647 cmsToneCurve
** Curves
;
2650 n
= cmsStageOutputChannels(mpe
);
2651 Curves
= _cmsStageGetPtrToCurveSet(mpe
);
2653 for (i
=0; i
< n
; i
++) {
2655 // If this is a table-based curve, use curve type even on V4
2658 if ((Curves
[i
] ->nSegments
== 0)||
2659 ((Curves
[i
]->nSegments
== 2) && (Curves
[i
] ->Segments
[1].Type
== 0)) )
2660 CurrentType
= cmsSigCurveType
;
2662 if (Curves
[i
] ->Segments
[0].Type
< 0)
2663 CurrentType
= cmsSigCurveType
;
2665 if (!_cmsWriteTypeBase(io
, CurrentType
)) return FALSE
;
2667 switch (CurrentType
) {
2669 case cmsSigCurveType
:
2670 if (!Type_Curve_Write(self
, io
, Curves
[i
], 1)) return FALSE
;
2673 case cmsSigParametricCurveType
:
2674 if (!Type_ParametricCurve_Write(self
, io
, Curves
[i
], 1)) return FALSE
;
2681 _cmsTagSignature2String(String
, (cmsTagSignature
) Type
);
2682 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown curve type '%s'", String
);
2687 if (!_cmsWriteAlignment(io
)) return FALSE
;
2696 cmsBool
WriteCLUT(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt8Number Precision
, cmsStage
* mpe
)
2698 cmsUInt8Number gridPoints
[cmsMAXCHANNELS
]; // Number of grid points in each dimension.
2700 _cmsStageCLutData
* CLUT
= ( _cmsStageCLutData
*) mpe
-> Data
;
2702 if (CLUT
->HasFloatValues
) {
2703 cmsSignalError(self
->ContextID
, cmsERROR_NOT_SUITABLE
, "Cannot save floating point data, CLUT are 8 or 16 bit only");
2707 memset(gridPoints
, 0, sizeof(gridPoints
));
2708 for (i
=0; i
< (cmsUInt32Number
) CLUT
->Params
->nInputs
; i
++)
2709 gridPoints
[i
] = (cmsUInt8Number
) CLUT
->Params
->nSamples
[i
];
2711 if (!io
-> Write(io
, cmsMAXCHANNELS
*sizeof(cmsUInt8Number
), gridPoints
)) return FALSE
;
2713 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) Precision
)) return FALSE
;
2714 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
;
2715 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
;
2716 if (!_cmsWriteUInt8Number(io
, 0)) return FALSE
;
2718 // Precision can be 1 or 2 bytes
2719 if (Precision
== 1) {
2721 for (i
=0; i
< CLUT
->nEntries
; i
++) {
2723 if (!_cmsWriteUInt8Number(io
, FROM_16_TO_8(CLUT
->Tab
.T
[i
]))) return FALSE
;
2727 if (Precision
== 2) {
2729 if (!_cmsWriteUInt16Array(io
, CLUT
->nEntries
, CLUT
->Tab
.T
)) return FALSE
;
2732 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown precision of '%d'", Precision
);
2736 if (!_cmsWriteAlignment(io
)) return FALSE
;
2745 cmsBool
Type_LUTA2B_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
2747 cmsPipeline
* Lut
= (cmsPipeline
*) Ptr
;
2748 cmsUInt32Number inputChan
, outputChan
;
2749 cmsStage
*A
= NULL
, *B
= NULL
, *M
= NULL
;
2750 cmsStage
* Matrix
= NULL
;
2751 cmsStage
* CLUT
= NULL
;
2752 cmsUInt32Number offsetB
= 0, offsetMat
= 0, offsetM
= 0, offsetC
= 0, offsetA
= 0;
2753 cmsUInt32Number BaseOffset
, DirectoryPos
, CurrentPos
;
2755 // Get the base for all offsets
2756 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
2758 if (Lut
->Elements
!= NULL
)
2759 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 1, cmsSigCurveSetElemType
, &B
))
2760 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 3, cmsSigCurveSetElemType
, cmsSigMatrixElemType
, cmsSigCurveSetElemType
, &M
, &Matrix
, &B
))
2761 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 3, cmsSigCurveSetElemType
, cmsSigCLutElemType
, cmsSigCurveSetElemType
, &A
, &CLUT
, &B
))
2762 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 5, cmsSigCurveSetElemType
, cmsSigCLutElemType
, cmsSigCurveSetElemType
,
2763 cmsSigMatrixElemType
, cmsSigCurveSetElemType
, &A
, &CLUT
, &M
, &Matrix
, &B
)) {
2765 cmsSignalError(self
->ContextID
, cmsERROR_NOT_SUITABLE
, "LUT is not suitable to be saved as LutAToB");
2769 // Get input, output channels
2770 inputChan
= cmsPipelineInputChannels(Lut
);
2771 outputChan
= cmsPipelineOutputChannels(Lut
);
2773 // Write channel count
2774 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) inputChan
)) return FALSE
;
2775 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) outputChan
)) return FALSE
;
2776 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
;
2778 // Keep directory to be filled latter
2779 DirectoryPos
= io
->Tell(io
);
2781 // Write the directory
2782 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2783 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2784 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2785 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2786 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2790 offsetA
= io
->Tell(io
) - BaseOffset
;
2791 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, A
)) return FALSE
;
2795 offsetC
= io
->Tell(io
) - BaseOffset
;
2796 if (!WriteCLUT(self
, io
, (Lut
->SaveAs8Bits
? 1U : 2U), CLUT
)) return FALSE
;
2801 offsetM
= io
->Tell(io
) - BaseOffset
;
2802 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, M
)) return FALSE
;
2805 if (Matrix
!= NULL
) {
2806 offsetMat
= io
->Tell(io
) - BaseOffset
;
2807 if (!WriteMatrix(self
, io
, Matrix
)) return FALSE
;
2812 offsetB
= io
->Tell(io
) - BaseOffset
;
2813 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, B
)) return FALSE
;
2816 CurrentPos
= io
->Tell(io
);
2818 if (!io
->Seek(io
, DirectoryPos
)) return FALSE
;
2820 if (!_cmsWriteUInt32Number(io
, offsetB
)) return FALSE
;
2821 if (!_cmsWriteUInt32Number(io
, offsetMat
)) return FALSE
;
2822 if (!_cmsWriteUInt32Number(io
, offsetM
)) return FALSE
;
2823 if (!_cmsWriteUInt32Number(io
, offsetC
)) return FALSE
;
2824 if (!_cmsWriteUInt32Number(io
, offsetA
)) return FALSE
;
2826 if (!io
->Seek(io
, CurrentPos
)) return FALSE
;
2830 cmsUNUSED_PARAMETER(nItems
);
2835 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
2837 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
2839 cmsUNUSED_PARAMETER(n
);
2840 cmsUNUSED_PARAMETER(self
);
2844 void Type_LUTA2B_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
2846 cmsPipelineFree((cmsPipeline
*) Ptr
);
2849 cmsUNUSED_PARAMETER(self
);
2856 void* Type_LUTB2A_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
2858 cmsUInt8Number inputChan
; // Number of input channels
2859 cmsUInt8Number outputChan
; // Number of output channels
2860 cmsUInt32Number BaseOffset
; // Actual position in file
2861 cmsUInt32Number offsetB
; // Offset to first "B" curve
2862 cmsUInt32Number offsetMat
; // Offset to matrix
2863 cmsUInt32Number offsetM
; // Offset to first "M" curve
2864 cmsUInt32Number offsetC
; // Offset to CLUT
2865 cmsUInt32Number offsetA
; // Offset to first "A" curve
2866 cmsPipeline
* NewLUT
= NULL
;
2869 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
2871 if (!_cmsReadUInt8Number(io
, &inputChan
)) return NULL
;
2872 if (!_cmsReadUInt8Number(io
, &outputChan
)) return NULL
;
2874 if (inputChan
== 0 || inputChan
>= cmsMAXCHANNELS
) return NULL
;
2875 if (outputChan
== 0 || outputChan
>= cmsMAXCHANNELS
) return NULL
;
2878 if (!_cmsReadUInt16Number(io
, NULL
)) return NULL
;
2880 if (!_cmsReadUInt32Number(io
, &offsetB
)) return NULL
;
2881 if (!_cmsReadUInt32Number(io
, &offsetMat
)) return NULL
;
2882 if (!_cmsReadUInt32Number(io
, &offsetM
)) return NULL
;
2883 if (!_cmsReadUInt32Number(io
, &offsetC
)) return NULL
;
2884 if (!_cmsReadUInt32Number(io
, &offsetA
)) return NULL
;
2886 // Allocates an empty LUT
2887 NewLUT
= cmsPipelineAlloc(self
->ContextID
, inputChan
, outputChan
);
2888 if (NewLUT
== NULL
) return NULL
;
2891 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetB
, inputChan
)))
2895 if (offsetMat
!= 0) {
2896 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadMatrix(self
, io
, BaseOffset
+ offsetMat
)))
2901 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetM
, inputChan
)))
2906 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadCLUT(self
, io
, BaseOffset
+ offsetC
, inputChan
, outputChan
)))
2911 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, ReadSetOfCurves(self
, io
, BaseOffset
+ offsetA
, outputChan
)))
2918 cmsPipelineFree(NewLUT
);
2921 cmsUNUSED_PARAMETER(SizeOfTag
);
2929 B - Matrix - M - CLUT - A
2933 cmsBool
Type_LUTB2A_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
2935 cmsPipeline
* Lut
= (cmsPipeline
*) Ptr
;
2936 cmsUInt32Number inputChan
, outputChan
;
2937 cmsStage
*A
= NULL
, *B
= NULL
, *M
= NULL
;
2938 cmsStage
*Matrix
= NULL
;
2939 cmsStage
*CLUT
= NULL
;
2940 cmsUInt32Number offsetB
= 0, offsetMat
= 0, offsetM
= 0, offsetC
= 0, offsetA
= 0;
2941 cmsUInt32Number BaseOffset
, DirectoryPos
, CurrentPos
;
2944 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
2946 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 1, cmsSigCurveSetElemType
, &B
))
2947 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 3, cmsSigCurveSetElemType
, cmsSigMatrixElemType
, cmsSigCurveSetElemType
, &B
, &Matrix
, &M
))
2948 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 3, cmsSigCurveSetElemType
, cmsSigCLutElemType
, cmsSigCurveSetElemType
, &B
, &CLUT
, &A
))
2949 if (!cmsPipelineCheckAndRetreiveStages(Lut
, 5, cmsSigCurveSetElemType
, cmsSigMatrixElemType
, cmsSigCurveSetElemType
,
2950 cmsSigCLutElemType
, cmsSigCurveSetElemType
, &B
, &Matrix
, &M
, &CLUT
, &A
)) {
2951 cmsSignalError(self
->ContextID
, cmsERROR_NOT_SUITABLE
, "LUT is not suitable to be saved as LutBToA");
2955 inputChan
= cmsPipelineInputChannels(Lut
);
2956 outputChan
= cmsPipelineOutputChannels(Lut
);
2958 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) inputChan
)) return FALSE
;
2959 if (!_cmsWriteUInt8Number(io
, (cmsUInt8Number
) outputChan
)) return FALSE
;
2960 if (!_cmsWriteUInt16Number(io
, 0)) return FALSE
;
2962 DirectoryPos
= io
->Tell(io
);
2964 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2965 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2966 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2967 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2968 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
2972 offsetA
= io
->Tell(io
) - BaseOffset
;
2973 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, A
)) return FALSE
;
2977 offsetC
= io
->Tell(io
) - BaseOffset
;
2978 if (!WriteCLUT(self
, io
, (Lut
->SaveAs8Bits
? 1U : 2U), CLUT
)) return FALSE
;
2983 offsetM
= io
->Tell(io
) - BaseOffset
;
2984 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, M
)) return FALSE
;
2987 if (Matrix
!= NULL
) {
2988 offsetMat
= io
->Tell(io
) - BaseOffset
;
2989 if (!WriteMatrix(self
, io
, Matrix
)) return FALSE
;
2994 offsetB
= io
->Tell(io
) - BaseOffset
;
2995 if (!WriteSetOfCurves(self
, io
, cmsSigParametricCurveType
, B
)) return FALSE
;
2998 CurrentPos
= io
->Tell(io
);
3000 if (!io
->Seek(io
, DirectoryPos
)) return FALSE
;
3002 if (!_cmsWriteUInt32Number(io
, offsetB
)) return FALSE
;
3003 if (!_cmsWriteUInt32Number(io
, offsetMat
)) return FALSE
;
3004 if (!_cmsWriteUInt32Number(io
, offsetM
)) return FALSE
;
3005 if (!_cmsWriteUInt32Number(io
, offsetC
)) return FALSE
;
3006 if (!_cmsWriteUInt32Number(io
, offsetA
)) return FALSE
;
3008 if (!io
->Seek(io
, CurrentPos
)) return FALSE
;
3012 cmsUNUSED_PARAMETER(nItems
);
3018 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3020 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
3022 cmsUNUSED_PARAMETER(n
);
3023 cmsUNUSED_PARAMETER(self
);
3027 void Type_LUTB2A_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3029 cmsPipelineFree((cmsPipeline
*) Ptr
);
3032 cmsUNUSED_PARAMETER(self
);
3037 // ********************************************************************************
3038 // Type cmsSigColorantTableType
3039 // ********************************************************************************
3041 The purpose of this tag is to identify the colorants used in the profile by a
3042 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
3043 value. The first colorant listed is the colorant of the first device channel of
3044 a lut tag. The second colorant listed is the colorant of the second device channel
3045 of a lut tag, and so on.
3049 void *Type_ColorantTable_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3051 cmsUInt32Number i
, Count
;
3052 cmsNAMEDCOLORLIST
* List
;
3054 cmsUInt16Number PCS
[3];
3057 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
3059 if (Count
> cmsMAXCHANNELS
) {
3060 cmsSignalError(self
->ContextID
, cmsERROR_RANGE
, "Too many colorants '%d'", Count
);
3064 List
= cmsAllocNamedColorList(self
->ContextID
, Count
, 0, "", "");
3068 for (i
=0; i
< Count
; i
++) {
3070 if (io
->Read(io
, Name
, 32, 1) != 1) goto Error
;
3073 if (!_cmsReadUInt16Array(io
, 3, PCS
)) goto Error
;
3075 if (!cmsAppendNamedColor(List
, Name
, PCS
, NULL
)) goto Error
;
3084 cmsFreeNamedColorList(List
);
3087 cmsUNUSED_PARAMETER(SizeOfTag
);
3092 // Saves a colorant table. It is using the named color structure for simplicity sake
3094 cmsBool
Type_ColorantTable_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3096 cmsNAMEDCOLORLIST
* NamedColorList
= (cmsNAMEDCOLORLIST
*) Ptr
;
3097 cmsUInt32Number i
, nColors
;
3099 nColors
= cmsNamedColorCount(NamedColorList
);
3101 if (!_cmsWriteUInt32Number(io
, nColors
)) return FALSE
;
3103 for (i
=0; i
< nColors
; i
++) {
3105 char root
[cmsMAX_PATH
];
3106 cmsUInt16Number PCS
[3];
3108 memset(root
, 0, sizeof(root
));
3110 if (!cmsNamedColorInfo(NamedColorList
, i
, root
, NULL
, NULL
, PCS
, NULL
)) return 0;
3113 if (!io
->Write(io
, 32, root
)) return FALSE
;
3114 if (!_cmsWriteUInt16Array(io
, 3, PCS
)) return FALSE
;
3119 cmsUNUSED_PARAMETER(nItems
);
3120 cmsUNUSED_PARAMETER(self
);
3125 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
3127 cmsNAMEDCOLORLIST
* nc
= (cmsNAMEDCOLORLIST
*) Ptr
;
3128 return (void*) cmsDupNamedColorList(nc
);
3130 cmsUNUSED_PARAMETER(n
);
3131 cmsUNUSED_PARAMETER(self
);
3136 void Type_ColorantTable_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3138 cmsFreeNamedColorList((cmsNAMEDCOLORLIST
*) Ptr
);
3141 cmsUNUSED_PARAMETER(self
);
3145 // ********************************************************************************
3146 // Type cmsSigNamedColor2Type
3147 // ********************************************************************************
3149 //The namedColor2Type is a count value and array of structures that provide color
3150 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3151 //device representation of the color are given. Both representations are 16-bit values.
3152 //The device representation corresponds to the header's 'color space of data' field.
3153 //This representation should be consistent with the 'number of device components'
3154 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3155 //The PCS representation corresponds to the header's PCS field. The PCS representation
3156 //is always provided. Color names are fixed-length, 32-byte fields including null
3157 //termination. In order to maintain maximum portability, it is strongly recommended
3158 //that special characters of the 7-bit ASCII set not be used.
3161 void *Type_NamedColor_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3163 cmsUInt32Number vendorFlag
; // Bottom 16 bits for ICC use
3164 cmsUInt32Number count
; // Count of named colors
3165 cmsUInt32Number nDeviceCoords
; // Num of device coordinates
3166 char prefix
[32]; // Prefix for each color name
3167 char suffix
[32]; // Suffix for each color name
3168 cmsNAMEDCOLORLIST
* v
;
3173 if (!_cmsReadUInt32Number(io
, &vendorFlag
)) return NULL
;
3174 if (!_cmsReadUInt32Number(io
, &count
)) return NULL
;
3175 if (!_cmsReadUInt32Number(io
, &nDeviceCoords
)) return NULL
;
3177 if (io
-> Read(io
, prefix
, 32, 1) != 1) return NULL
;
3178 if (io
-> Read(io
, suffix
, 32, 1) != 1) return NULL
;
3180 prefix
[31] = suffix
[31] = 0;
3182 v
= cmsAllocNamedColorList(self
->ContextID
, count
, nDeviceCoords
, prefix
, suffix
);
3184 cmsSignalError(self
->ContextID
, cmsERROR_RANGE
, "Too many named colors '%d'", count
);
3188 if (nDeviceCoords
> cmsMAXCHANNELS
) {
3189 cmsSignalError(self
->ContextID
, cmsERROR_RANGE
, "Too many device coordinates '%d'", nDeviceCoords
);
3192 for (i
=0; i
< count
; i
++) {
3194 cmsUInt16Number PCS
[3];
3195 cmsUInt16Number Colorant
[cmsMAXCHANNELS
];
3198 memset(Colorant
, 0, sizeof(Colorant
));
3199 if (io
-> Read(io
, Root
, 32, 1) != 1) goto Error
;
3200 Root
[32] = 0; // To prevent exploits
3202 if (!_cmsReadUInt16Array(io
, 3, PCS
)) goto Error
;
3203 if (!_cmsReadUInt16Array(io
, nDeviceCoords
, Colorant
)) goto Error
;
3205 if (!cmsAppendNamedColor(v
, Root
, PCS
, Colorant
)) goto Error
;
3212 cmsFreeNamedColorList(v
);
3215 cmsUNUSED_PARAMETER(SizeOfTag
);
3219 // Saves a named color list into a named color profile
3221 cmsBool
Type_NamedColor_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3223 cmsNAMEDCOLORLIST
* NamedColorList
= (cmsNAMEDCOLORLIST
*) Ptr
;
3224 char prefix
[33]; // Prefix for each color name
3225 char suffix
[33]; // Suffix for each color name
3226 cmsUInt32Number i
, nColors
;
3228 nColors
= cmsNamedColorCount(NamedColorList
);
3230 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
3231 if (!_cmsWriteUInt32Number(io
, nColors
)) return FALSE
;
3232 if (!_cmsWriteUInt32Number(io
, NamedColorList
->ColorantCount
)) return FALSE
;
3234 memcpy(prefix
, (const char*) NamedColorList
->Prefix
, sizeof(prefix
));
3235 memcpy(suffix
, (const char*) NamedColorList
->Suffix
, sizeof(suffix
));
3237 suffix
[32] = prefix
[32] = 0;
3239 if (!io
->Write(io
, 32, prefix
)) return FALSE
;
3240 if (!io
->Write(io
, 32, suffix
)) return FALSE
;
3242 for (i
=0; i
< nColors
; i
++) {
3244 cmsUInt16Number PCS
[3];
3245 cmsUInt16Number Colorant
[cmsMAXCHANNELS
];
3246 char Root
[cmsMAX_PATH
];
3248 memset(Root
, 0, sizeof(Root
));
3249 memset(PCS
, 0, sizeof(PCS
));
3250 memset(Colorant
, 0, sizeof(Colorant
));
3252 if (!cmsNamedColorInfo(NamedColorList
, i
, Root
, NULL
, NULL
, PCS
, Colorant
)) return 0;
3254 if (!io
->Write(io
, 32 , Root
)) return FALSE
;
3255 if (!_cmsWriteUInt16Array(io
, 3, PCS
)) return FALSE
;
3256 if (!_cmsWriteUInt16Array(io
, NamedColorList
->ColorantCount
, Colorant
)) return FALSE
;
3261 cmsUNUSED_PARAMETER(nItems
);
3262 cmsUNUSED_PARAMETER(self
);
3266 void* Type_NamedColor_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
3268 cmsNAMEDCOLORLIST
* nc
= (cmsNAMEDCOLORLIST
*) Ptr
;
3270 return (void*) cmsDupNamedColorList(nc
);
3272 cmsUNUSED_PARAMETER(n
);
3273 cmsUNUSED_PARAMETER(self
);
3278 void Type_NamedColor_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3280 cmsFreeNamedColorList((cmsNAMEDCOLORLIST
*) Ptr
);
3283 cmsUNUSED_PARAMETER(self
);
3287 // ********************************************************************************
3288 // Type cmsSigProfileSequenceDescType
3289 // ********************************************************************************
3291 // This type is an array of structures, each of which contains information from the
3292 // header fields and tags from the original profiles which were combined to create
3293 // the final profile. The order of the structures is the order in which the profiles
3294 // were combined and includes a structure for the final profile. This provides a
3295 // description of the profile sequence from source to destination,
3296 // typically used with the DeviceLink profile.
3299 cmsBool
ReadEmbeddedText(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsMLU
** mlu
, cmsUInt32Number SizeOfTag
)
3301 cmsTagTypeSignature BaseType
;
3302 cmsUInt32Number nItems
;
3304 BaseType
= _cmsReadTypeBase(io
);
3308 case cmsSigTextType
:
3309 if (*mlu
) cmsMLUfree(*mlu
);
3310 *mlu
= (cmsMLU
*)Type_Text_Read(self
, io
, &nItems
, SizeOfTag
);
3311 return (*mlu
!= NULL
);
3313 case cmsSigTextDescriptionType
:
3314 if (*mlu
) cmsMLUfree(*mlu
);
3315 *mlu
= (cmsMLU
*) Type_Text_Description_Read(self
, io
, &nItems
, SizeOfTag
);
3316 return (*mlu
!= NULL
);
3319 TBD: Size is needed for MLU, and we have no idea on which is the available size
3322 case cmsSigMultiLocalizedUnicodeType
:
3323 if (*mlu
) cmsMLUfree(*mlu
);
3324 *mlu
= (cmsMLU
*) Type_MLU_Read(self
, io
, &nItems
, SizeOfTag
);
3325 return (*mlu
!= NULL
);
3327 default: return FALSE
;
3333 void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3336 cmsUInt32Number i
, Count
;
3340 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
3342 if (SizeOfTag
< sizeof(cmsUInt32Number
)) return NULL
;
3343 SizeOfTag
-= sizeof(cmsUInt32Number
);
3346 OutSeq
= cmsAllocProfileSequenceDescription(self
->ContextID
, Count
);
3347 if (OutSeq
== NULL
) return NULL
;
3351 // Get structures as well
3353 for (i
=0; i
< Count
; i
++) {
3355 cmsPSEQDESC
* sec
= &OutSeq
-> seq
[i
];
3357 if (!_cmsReadUInt32Number(io
, &sec
->deviceMfg
)) goto Error
;
3358 if (SizeOfTag
< sizeof(cmsUInt32Number
)) goto Error
;
3359 SizeOfTag
-= sizeof(cmsUInt32Number
);
3361 if (!_cmsReadUInt32Number(io
, &sec
->deviceModel
)) goto Error
;
3362 if (SizeOfTag
< sizeof(cmsUInt32Number
)) goto Error
;
3363 SizeOfTag
-= sizeof(cmsUInt32Number
);
3365 if (!_cmsReadUInt64Number(io
, &sec
->attributes
)) goto Error
;
3366 if (SizeOfTag
< sizeof(cmsUInt64Number
)) goto Error
;
3367 SizeOfTag
-= sizeof(cmsUInt64Number
);
3369 if (!_cmsReadUInt32Number(io
, (cmsUInt32Number
*)&sec
->technology
)) goto Error
;
3370 if (SizeOfTag
< sizeof(cmsUInt32Number
)) goto Error
;
3371 SizeOfTag
-= sizeof(cmsUInt32Number
);
3373 if (!ReadEmbeddedText(self
, io
, &sec
->Manufacturer
, SizeOfTag
)) goto Error
;
3374 if (!ReadEmbeddedText(self
, io
, &sec
->Model
, SizeOfTag
)) goto Error
;
3381 cmsFreeProfileSequenceDescription(OutSeq
);
3386 // Aux--Embed a text description type. It can be of type text description or multilocalized unicode
3387 // and it depends of the version number passed on cmsTagDescriptor structure instead of stack
3389 cmsBool
SaveDescription(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsMLU
* Text
)
3391 if (self
->ICCVersion
< 0x4000000) {
3393 if (!_cmsWriteTypeBase(io
, cmsSigTextDescriptionType
)) return FALSE
;
3394 return Type_Text_Description_Write(self
, io
, Text
, 1);
3397 if (!_cmsWriteTypeBase(io
, cmsSigMultiLocalizedUnicodeType
)) return FALSE
;
3398 return Type_MLU_Write(self
, io
, Text
, 1);
3404 cmsBool
Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3406 cmsSEQ
* Seq
= (cmsSEQ
*) Ptr
;
3409 if (!_cmsWriteUInt32Number(io
, Seq
->n
)) return FALSE
;
3411 for (i
=0; i
< Seq
->n
; i
++) {
3413 cmsPSEQDESC
* sec
= &Seq
-> seq
[i
];
3415 if (!_cmsWriteUInt32Number(io
, sec
->deviceMfg
)) return FALSE
;
3416 if (!_cmsWriteUInt32Number(io
, sec
->deviceModel
)) return FALSE
;
3417 if (!_cmsWriteUInt64Number(io
, &sec
->attributes
)) return FALSE
;
3418 if (!_cmsWriteUInt32Number(io
, sec
->technology
)) return FALSE
;
3420 if (!SaveDescription(self
, io
, sec
->Manufacturer
)) return FALSE
;
3421 if (!SaveDescription(self
, io
, sec
->Model
)) return FALSE
;
3426 cmsUNUSED_PARAMETER(nItems
);
3431 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
3433 return (void*) cmsDupProfileSequenceDescription((cmsSEQ
*) Ptr
);
3435 cmsUNUSED_PARAMETER(n
);
3436 cmsUNUSED_PARAMETER(self
);
3440 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3442 cmsFreeProfileSequenceDescription((cmsSEQ
*) Ptr
);
3445 cmsUNUSED_PARAMETER(self
);
3449 // ********************************************************************************
3450 // Type cmsSigProfileSequenceIdType
3451 // ********************************************************************************
3453 In certain workflows using ICC Device Link Profiles, it is necessary to identify the
3454 original profiles that were combined to create the Device Link Profile.
3455 This type is an array of structures, each of which contains information for
3456 identification of a profile used in a sequence
3461 cmsBool
ReadSeqID(struct _cms_typehandler_struct
* self
,
3465 cmsUInt32Number SizeOfTag
)
3467 cmsSEQ
* OutSeq
= (cmsSEQ
*) Cargo
;
3468 cmsPSEQDESC
* seq
= &OutSeq
->seq
[n
];
3470 if (io
-> Read(io
, seq
->ProfileID
.ID8
, 16, 1) != 1) return FALSE
;
3471 if (!ReadEmbeddedText(self
, io
, &seq
->Description
, SizeOfTag
)) return FALSE
;
3479 void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3482 cmsUInt32Number Count
;
3483 cmsUInt32Number BaseOffset
;
3487 // Get actual position as a basis for element offsets
3488 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
3491 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
3493 // Allocate an empty structure
3494 OutSeq
= cmsAllocProfileSequenceDescription(self
->ContextID
, Count
);
3495 if (OutSeq
== NULL
) return NULL
;
3498 // Read the position table
3499 if (!ReadPositionTable(self
, io
, Count
, BaseOffset
, OutSeq
, ReadSeqID
)) {
3501 cmsFreeProfileSequenceDescription(OutSeq
);
3509 cmsUNUSED_PARAMETER(SizeOfTag
);
3514 cmsBool
WriteSeqID(struct _cms_typehandler_struct
* self
,
3518 cmsUInt32Number SizeOfTag
)
3520 cmsSEQ
* Seq
= (cmsSEQ
*) Cargo
;
3522 if (!io
->Write(io
, 16, Seq
->seq
[n
].ProfileID
.ID8
)) return FALSE
;
3524 // Store here the MLU
3525 if (!SaveDescription(self
, io
, Seq
->seq
[n
].Description
)) return FALSE
;
3529 cmsUNUSED_PARAMETER(SizeOfTag
);
3533 cmsBool
Type_ProfileSequenceId_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3535 cmsSEQ
* Seq
= (cmsSEQ
*) Ptr
;
3536 cmsUInt32Number BaseOffset
;
3538 // Keep the base offset
3539 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
3541 // This is the table count
3542 if (!_cmsWriteUInt32Number(io
, Seq
->n
)) return FALSE
;
3544 // This is the position table and content
3545 if (!WritePositionTable(self
, io
, 0, Seq
->n
, BaseOffset
, Seq
, WriteSeqID
)) return FALSE
;
3549 cmsUNUSED_PARAMETER(nItems
);
3553 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
3555 return (void*) cmsDupProfileSequenceDescription((cmsSEQ
*) Ptr
);
3557 cmsUNUSED_PARAMETER(n
);
3558 cmsUNUSED_PARAMETER(self
);
3562 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3564 cmsFreeProfileSequenceDescription((cmsSEQ
*) Ptr
);
3567 cmsUNUSED_PARAMETER(self
);
3571 // ********************************************************************************
3572 // Type cmsSigUcrBgType
3573 // ********************************************************************************
3575 This type contains curves representing the under color removal and black
3576 generation and a text string which is a general description of the method used
3581 void *Type_UcrBg_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3583 cmsUcrBg
* n
= (cmsUcrBg
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsUcrBg
));
3584 cmsUInt32Number CountUcr
, CountBg
;
3585 cmsInt32Number SignedSizeOfTag
= (cmsInt32Number
)SizeOfTag
;
3589 if (n
== NULL
) return NULL
;
3591 // First curve is Under color removal
3593 if (SignedSizeOfTag
< (cmsInt32Number
) sizeof(cmsUInt32Number
)) return NULL
;
3594 if (!_cmsReadUInt32Number(io
, &CountUcr
)) return NULL
;
3595 SignedSizeOfTag
-= sizeof(cmsUInt32Number
);
3597 n
->Ucr
= cmsBuildTabulatedToneCurve16(self
->ContextID
, CountUcr
, NULL
);
3598 if (n
->Ucr
== NULL
) goto error
;
3600 if (SignedSizeOfTag
< (cmsInt32Number
)(CountUcr
* sizeof(cmsUInt16Number
))) goto error
;
3601 if (!_cmsReadUInt16Array(io
, CountUcr
, n
->Ucr
->Table16
)) goto error
;
3603 SignedSizeOfTag
-= CountUcr
* sizeof(cmsUInt16Number
);
3605 // Second curve is Black generation
3607 if (SignedSizeOfTag
< (cmsInt32Number
)sizeof(cmsUInt32Number
)) goto error
;
3608 if (!_cmsReadUInt32Number(io
, &CountBg
)) goto error
;
3609 SignedSizeOfTag
-= sizeof(cmsUInt32Number
);
3611 n
->Bg
= cmsBuildTabulatedToneCurve16(self
->ContextID
, CountBg
, NULL
);
3612 if (n
->Bg
== NULL
) goto error
;
3614 if (SignedSizeOfTag
< (cmsInt32Number
) (CountBg
* sizeof(cmsUInt16Number
))) goto error
;
3615 if (!_cmsReadUInt16Array(io
, CountBg
, n
->Bg
->Table16
)) goto error
;
3616 SignedSizeOfTag
-= CountBg
* sizeof(cmsUInt16Number
);
3618 if (SignedSizeOfTag
< 0 || SignedSizeOfTag
> 32000) goto error
;
3620 // Now comes the text. The length is specified by the tag size
3621 n
->Desc
= cmsMLUalloc(self
->ContextID
, 1);
3622 if (n
->Desc
== NULL
) goto error
;
3624 ASCIIString
= (char*) _cmsMalloc(self
->ContextID
, SignedSizeOfTag
+ 1);
3625 if (io
->Read(io
, ASCIIString
, sizeof(char), SignedSizeOfTag
) != (cmsUInt32Number
)SignedSizeOfTag
)
3627 _cmsFree(self
->ContextID
, ASCIIString
);
3631 ASCIIString
[SignedSizeOfTag
] = 0;
3632 cmsMLUsetASCII(n
->Desc
, cmsNoLanguage
, cmsNoCountry
, ASCIIString
);
3633 _cmsFree(self
->ContextID
, ASCIIString
);
3640 if (n
->Ucr
) cmsFreeToneCurve(n
->Ucr
);
3641 if (n
->Bg
) cmsFreeToneCurve(n
->Bg
);
3642 if (n
->Desc
) cmsMLUfree(n
->Desc
);
3643 _cmsFree(self
->ContextID
, n
);
3650 cmsBool
Type_UcrBg_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3652 cmsUcrBg
* Value
= (cmsUcrBg
*) Ptr
;
3653 cmsUInt32Number TextSize
;
3656 // First curve is Under color removal
3657 if (!_cmsWriteUInt32Number(io
, Value
->Ucr
->nEntries
)) return FALSE
;
3658 if (!_cmsWriteUInt16Array(io
, Value
->Ucr
->nEntries
, Value
->Ucr
->Table16
)) return FALSE
;
3660 // Then black generation
3661 if (!_cmsWriteUInt32Number(io
, Value
->Bg
->nEntries
)) return FALSE
;
3662 if (!_cmsWriteUInt16Array(io
, Value
->Bg
->nEntries
, Value
->Bg
->Table16
)) return FALSE
;
3664 // Now comes the text. The length is specified by the tag size
3665 TextSize
= cmsMLUgetASCII(Value
->Desc
, cmsNoLanguage
, cmsNoCountry
, NULL
, 0);
3666 Text
= (char*) _cmsMalloc(self
->ContextID
, TextSize
);
3667 if (cmsMLUgetASCII(Value
->Desc
, cmsNoLanguage
, cmsNoCountry
, Text
, TextSize
) != TextSize
) return FALSE
;
3669 if (!io
->Write(io
, TextSize
, Text
)) return FALSE
;
3670 _cmsFree(self
->ContextID
, Text
);
3674 cmsUNUSED_PARAMETER(nItems
);
3678 void* Type_UcrBg_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3680 cmsUcrBg
* Src
= (cmsUcrBg
*) Ptr
;
3681 cmsUcrBg
* NewUcrBg
= (cmsUcrBg
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsUcrBg
));
3683 if (NewUcrBg
== NULL
) return NULL
;
3685 NewUcrBg
->Bg
= cmsDupToneCurve(Src
->Bg
);
3686 NewUcrBg
->Ucr
= cmsDupToneCurve(Src
->Ucr
);
3687 NewUcrBg
->Desc
= cmsMLUdup(Src
->Desc
);
3689 return (void*) NewUcrBg
;
3691 cmsUNUSED_PARAMETER(n
);
3695 void Type_UcrBg_Free(struct _cms_typehandler_struct
* self
, void *Ptr
)
3697 cmsUcrBg
* Src
= (cmsUcrBg
*) Ptr
;
3699 if (Src
->Ucr
) cmsFreeToneCurve(Src
->Ucr
);
3700 if (Src
->Bg
) cmsFreeToneCurve(Src
->Bg
);
3701 if (Src
->Desc
) cmsMLUfree(Src
->Desc
);
3703 _cmsFree(self
->ContextID
, Ptr
);
3706 // ********************************************************************************
3707 // Type cmsSigCrdInfoType
3708 // ********************************************************************************
3711 This type contains the PostScript product name to which this profile corresponds
3712 and the names of the companion CRDs. Recall that a single profile can generate
3713 multiple CRDs. It is implemented as a MLU being the language code "PS" and then
3714 country varies for each element:
3716 nm: PostScript product name
3717 #0: Rendering intent 0 CRD name
3718 #1: Rendering intent 1 CRD name
3719 #2: Rendering intent 2 CRD name
3720 #3: Rendering intent 3 CRD name
3725 // Auxiliary, read an string specified as count + string
3727 cmsBool
ReadCountAndString(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsMLU
* mlu
, cmsUInt32Number
* SizeOfTag
, const char* Section
)
3729 cmsUInt32Number Count
;
3732 if (*SizeOfTag
< sizeof(cmsUInt32Number
)) return FALSE
;
3734 if (!_cmsReadUInt32Number(io
, &Count
)) return FALSE
;
3736 if (Count
> UINT_MAX
- sizeof(cmsUInt32Number
)) return FALSE
;
3737 if (*SizeOfTag
< Count
+ sizeof(cmsUInt32Number
)) return FALSE
;
3739 Text
= (char*) _cmsMalloc(self
->ContextID
, Count
+1);
3740 if (Text
== NULL
) return FALSE
;
3742 if (io
->Read(io
, Text
, sizeof(cmsUInt8Number
), Count
) != Count
) {
3743 _cmsFree(self
->ContextID
, Text
);
3749 cmsMLUsetASCII(mlu
, "PS", Section
, Text
);
3750 _cmsFree(self
->ContextID
, Text
);
3752 *SizeOfTag
-= (Count
+ sizeof(cmsUInt32Number
));
3757 cmsBool
WriteCountAndString(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsMLU
* mlu
, const char* Section
)
3759 cmsUInt32Number TextSize
;
3762 TextSize
= cmsMLUgetASCII(mlu
, "PS", Section
, NULL
, 0);
3763 Text
= (char*) _cmsMalloc(self
->ContextID
, TextSize
);
3765 if (!_cmsWriteUInt32Number(io
, TextSize
)) return FALSE
;
3767 if (cmsMLUgetASCII(mlu
, "PS", Section
, Text
, TextSize
) == 0) return FALSE
;
3769 if (!io
->Write(io
, TextSize
, Text
)) return FALSE
;
3770 _cmsFree(self
->ContextID
, Text
);
3776 void *Type_CrdInfo_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3778 cmsMLU
* mlu
= cmsMLUalloc(self
->ContextID
, 5);
3781 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "nm")) goto Error
;
3782 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "#0")) goto Error
;
3783 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "#1")) goto Error
;
3784 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "#2")) goto Error
;
3785 if (!ReadCountAndString(self
, io
, mlu
, &SizeOfTag
, "#3")) goto Error
;
3797 cmsBool
Type_CrdInfo_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3800 cmsMLU
* mlu
= (cmsMLU
*) Ptr
;
3802 if (!WriteCountAndString(self
, io
, mlu
, "nm")) goto Error
;
3803 if (!WriteCountAndString(self
, io
, mlu
, "#0")) goto Error
;
3804 if (!WriteCountAndString(self
, io
, mlu
, "#1")) goto Error
;
3805 if (!WriteCountAndString(self
, io
, mlu
, "#2")) goto Error
;
3806 if (!WriteCountAndString(self
, io
, mlu
, "#3")) goto Error
;
3813 cmsUNUSED_PARAMETER(nItems
);
3818 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3820 return (void*) cmsMLUdup((cmsMLU
*) Ptr
);
3822 cmsUNUSED_PARAMETER(n
);
3823 cmsUNUSED_PARAMETER(self
);
3827 void Type_CrdInfo_Free(struct _cms_typehandler_struct
* self
, void *Ptr
)
3829 cmsMLUfree((cmsMLU
*) Ptr
);
3832 cmsUNUSED_PARAMETER(self
);
3835 // ********************************************************************************
3836 // Type cmsSigScreeningType
3837 // ********************************************************************************
3839 //The screeningType describes various screening parameters including screen
3840 //frequency, screening angle, and spot shape.
3843 void *Type_Screening_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3845 cmsScreening
* sc
= NULL
;
3848 sc
= (cmsScreening
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsScreening
));
3849 if (sc
== NULL
) return NULL
;
3853 if (!_cmsReadUInt32Number(io
, &sc
->Flag
)) goto Error
;
3854 if (!_cmsReadUInt32Number(io
, &sc
->nChannels
)) goto Error
;
3856 if (sc
->nChannels
> cmsMAXCHANNELS
- 1)
3857 sc
->nChannels
= cmsMAXCHANNELS
- 1;
3859 for (i
=0; i
< sc
->nChannels
; i
++) {
3861 if (!_cmsRead15Fixed16Number(io
, &sc
->Channels
[i
].Frequency
)) goto Error
;
3862 if (!_cmsRead15Fixed16Number(io
, &sc
->Channels
[i
].ScreenAngle
)) goto Error
;
3863 if (!_cmsReadUInt32Number(io
, &sc
->Channels
[i
].SpotShape
)) goto Error
;
3873 _cmsFree(self
->ContextID
, sc
);
3877 cmsUNUSED_PARAMETER(SizeOfTag
);
3882 cmsBool
Type_Screening_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3884 cmsScreening
* sc
= (cmsScreening
* ) Ptr
;
3887 if (!_cmsWriteUInt32Number(io
, sc
->Flag
)) return FALSE
;
3888 if (!_cmsWriteUInt32Number(io
, sc
->nChannels
)) return FALSE
;
3890 for (i
=0; i
< sc
->nChannels
; i
++) {
3892 if (!_cmsWrite15Fixed16Number(io
, sc
->Channels
[i
].Frequency
)) return FALSE
;
3893 if (!_cmsWrite15Fixed16Number(io
, sc
->Channels
[i
].ScreenAngle
)) return FALSE
;
3894 if (!_cmsWriteUInt32Number(io
, sc
->Channels
[i
].SpotShape
)) return FALSE
;
3899 cmsUNUSED_PARAMETER(nItems
);
3900 cmsUNUSED_PARAMETER(self
);
3905 void* Type_Screening_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3907 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsScreening
));
3909 cmsUNUSED_PARAMETER(n
);
3914 void Type_Screening_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3916 _cmsFree(self
->ContextID
, Ptr
);
3919 // ********************************************************************************
3920 // Type cmsSigViewingConditionsType
3921 // ********************************************************************************
3923 //This type represents a set of viewing condition parameters including:
3924 //CIE 'absolute' illuminant white point tristimulus values and CIE 'absolute'
3925 //surround tristimulus values.
3928 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
3930 cmsICCViewingConditions
* vc
= NULL
;
3932 vc
= (cmsICCViewingConditions
*) _cmsMallocZero(self
->ContextID
, sizeof(cmsICCViewingConditions
));
3933 if (vc
== NULL
) return NULL
;
3937 if (!_cmsReadXYZNumber(io
, &vc
->IlluminantXYZ
)) goto Error
;
3938 if (!_cmsReadXYZNumber(io
, &vc
->SurroundXYZ
)) goto Error
;
3939 if (!_cmsReadUInt32Number(io
, &vc
->IlluminantType
)) goto Error
;
3947 _cmsFree(self
->ContextID
, vc
);
3951 cmsUNUSED_PARAMETER(SizeOfTag
);
3956 cmsBool
Type_ViewingConditions_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
3958 cmsICCViewingConditions
* sc
= (cmsICCViewingConditions
* ) Ptr
;
3960 if (!_cmsWriteXYZNumber(io
, &sc
->IlluminantXYZ
)) return FALSE
;
3961 if (!_cmsWriteXYZNumber(io
, &sc
->SurroundXYZ
)) return FALSE
;
3962 if (!_cmsWriteUInt32Number(io
, sc
->IlluminantType
)) return FALSE
;
3966 cmsUNUSED_PARAMETER(nItems
);
3967 cmsUNUSED_PARAMETER(self
);
3972 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3974 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsICCViewingConditions
));
3976 cmsUNUSED_PARAMETER(n
);
3981 void Type_ViewingConditions_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
3983 _cmsFree(self
->ContextID
, Ptr
);
3987 // ********************************************************************************
3988 // Type cmsSigMultiProcessElementType
3989 // ********************************************************************************
3993 void* GenericMPEdup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
3995 return (void*) cmsStageDup((cmsStage
*) Ptr
);
3997 cmsUNUSED_PARAMETER(n
);
3998 cmsUNUSED_PARAMETER(self
);
4002 void GenericMPEfree(struct _cms_typehandler_struct
* self
, void *Ptr
)
4004 cmsStageFree((cmsStage
*) Ptr
);
4007 cmsUNUSED_PARAMETER(self
);
4010 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
4011 // The first curve segment always starts at -Infinity, and the last curve segment always ends at +Infinity. The
4012 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
4013 // specified either in terms of a formula, or by a sampled curve.
4016 // Read an embedded segmented curve
4018 cmsToneCurve
* ReadSegmentedCurve(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
)
4020 cmsCurveSegSignature ElementSig
;
4021 cmsUInt32Number i
, j
;
4022 cmsUInt16Number nSegments
;
4023 cmsCurveSegment
* Segments
;
4024 cmsToneCurve
* Curve
;
4025 cmsFloat32Number PrevBreak
= MINUS_INF
; // - infinite
4027 // Take signature and channels for each element.
4028 if (!_cmsReadUInt32Number(io
, (cmsUInt32Number
*) &ElementSig
)) return NULL
;
4030 // That should be a segmented curve
4031 if (ElementSig
!= cmsSigSegmentedCurve
) return NULL
;
4033 if (!_cmsReadUInt32Number(io
, NULL
)) return NULL
;
4034 if (!_cmsReadUInt16Number(io
, &nSegments
)) return NULL
;
4035 if (!_cmsReadUInt16Number(io
, NULL
)) return NULL
;
4037 if (nSegments
< 1) return NULL
;
4038 Segments
= (cmsCurveSegment
*) _cmsCalloc(self
->ContextID
, nSegments
, sizeof(cmsCurveSegment
));
4039 if (Segments
== NULL
) return NULL
;
4042 for (i
=0; i
< (cmsUInt32Number
) nSegments
- 1; i
++) {
4044 Segments
[i
].x0
= PrevBreak
;
4045 if (!_cmsReadFloat32Number(io
, &Segments
[i
].x1
)) goto Error
;
4046 PrevBreak
= Segments
[i
].x1
;
4049 Segments
[nSegments
-1].x0
= PrevBreak
;
4050 Segments
[nSegments
-1].x1
= PLUS_INF
; // A big cmsFloat32Number number
4053 for (i
=0; i
< nSegments
; i
++) {
4055 if (!_cmsReadUInt32Number(io
, (cmsUInt32Number
*) &ElementSig
)) goto Error
;
4056 if (!_cmsReadUInt32Number(io
, NULL
)) goto Error
;
4058 switch (ElementSig
) {
4060 case cmsSigFormulaCurveSeg
: {
4062 cmsUInt16Number Type
;
4063 cmsUInt32Number ParamsByType
[] = { 4, 5, 5 };
4065 if (!_cmsReadUInt16Number(io
, &Type
)) goto Error
;
4066 if (!_cmsReadUInt16Number(io
, NULL
)) goto Error
;
4068 Segments
[i
].Type
= Type
+ 6;
4069 if (Type
> 2) goto Error
;
4071 for (j
= 0; j
< ParamsByType
[Type
]; j
++) {
4074 if (!_cmsReadFloat32Number(io
, &f
)) goto Error
;
4075 Segments
[i
].Params
[j
] = f
;
4081 case cmsSigSampledCurveSeg
: {
4082 cmsUInt32Number Count
;
4084 if (!_cmsReadUInt32Number(io
, &Count
)) goto Error
;
4086 // The first point is implicit in the last stage, we allocate an extra note to be populated latter on
4088 Segments
[i
].nGridPoints
= Count
;
4089 Segments
[i
].SampledPoints
= (cmsFloat32Number
*)_cmsCalloc(self
->ContextID
, Count
, sizeof(cmsFloat32Number
));
4090 if (Segments
[i
].SampledPoints
== NULL
) goto Error
;
4092 Segments
[i
].SampledPoints
[0] = 0;
4093 for (j
= 1; j
< Count
; j
++) {
4094 if (!_cmsReadFloat32Number(io
, &Segments
[i
].SampledPoints
[j
])) goto Error
;
4103 _cmsTagSignature2String(String
, (cmsTagSignature
) ElementSig
);
4104 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown curve element type '%s' found.", String
);
4111 Curve
= cmsBuildSegmentedToneCurve(self
->ContextID
, nSegments
, Segments
);
4113 for (i
=0; i
< nSegments
; i
++) {
4114 if (Segments
[i
].SampledPoints
) _cmsFree(self
->ContextID
, Segments
[i
].SampledPoints
);
4116 _cmsFree(self
->ContextID
, Segments
);
4118 // Explore for missing implicit points
4119 for (i
= 0; i
< nSegments
; i
++) {
4121 // If sampled curve, fix it
4122 if (Curve
->Segments
[i
].Type
== 0) {
4124 Curve
->Segments
[i
].SampledPoints
[0] = cmsEvalToneCurveFloat(Curve
, Curve
->Segments
[i
].x0
);
4132 for (i
=0; i
< nSegments
; i
++) {
4133 if (Segments
[i
].SampledPoints
) _cmsFree(self
->ContextID
, Segments
[i
].SampledPoints
);
4135 _cmsFree(self
->ContextID
, Segments
);
4142 cmsBool
ReadMPECurve(struct _cms_typehandler_struct
* self
,
4146 cmsUInt32Number SizeOfTag
)
4148 cmsToneCurve
** GammaTables
= ( cmsToneCurve
**) Cargo
;
4150 GammaTables
[n
] = ReadSegmentedCurve(self
, io
);
4151 return (GammaTables
[n
] != NULL
);
4153 cmsUNUSED_PARAMETER(SizeOfTag
);
4157 void *Type_MPEcurve_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
4159 cmsStage
* mpe
= NULL
;
4160 cmsUInt16Number InputChans
, OutputChans
;
4161 cmsUInt32Number i
, BaseOffset
;
4162 cmsToneCurve
** GammaTables
;
4166 // Get actual position as a basis for element offsets
4167 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
4169 if (!_cmsReadUInt16Number(io
, &InputChans
)) return NULL
;
4170 if (!_cmsReadUInt16Number(io
, &OutputChans
)) return NULL
;
4172 if (InputChans
!= OutputChans
) return NULL
;
4174 GammaTables
= (cmsToneCurve
**) _cmsCalloc(self
->ContextID
, InputChans
, sizeof(cmsToneCurve
*));
4175 if (GammaTables
== NULL
) return NULL
;
4177 if (ReadPositionTable(self
, io
, InputChans
, BaseOffset
, GammaTables
, ReadMPECurve
)) {
4179 mpe
= cmsStageAllocToneCurves(self
->ContextID
, InputChans
, GammaTables
);
4185 for (i
=0; i
< InputChans
; i
++) {
4186 if (GammaTables
[i
]) cmsFreeToneCurve(GammaTables
[i
]);
4189 _cmsFree(self
->ContextID
, GammaTables
);
4190 *nItems
= (mpe
!= NULL
) ? 1U : 0;
4193 cmsUNUSED_PARAMETER(SizeOfTag
);
4197 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
4199 cmsBool
WriteSegmentedCurve(cmsIOHANDLER
* io
, cmsToneCurve
* g
)
4201 cmsUInt32Number i
, j
;
4202 cmsCurveSegment
* Segments
= g
->Segments
;
4203 cmsUInt32Number nSegments
= g
->nSegments
;
4205 if (!_cmsWriteUInt32Number(io
, cmsSigSegmentedCurve
)) goto Error
;
4206 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
;
4207 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) nSegments
)) goto Error
;
4208 if (!_cmsWriteUInt16Number(io
, 0)) goto Error
;
4210 // Write the break-points
4211 for (i
=0; i
< nSegments
- 1; i
++) {
4212 if (!_cmsWriteFloat32Number(io
, Segments
[i
].x1
)) goto Error
;
4215 // Write the segments
4216 for (i
=0; i
< g
->nSegments
; i
++) {
4218 cmsCurveSegment
* ActualSeg
= Segments
+ i
;
4220 if (ActualSeg
-> Type
== 0) {
4222 // This is a sampled curve. First point is implicit in the ICC format, but not in our representation
4223 if (!_cmsWriteUInt32Number(io
, (cmsUInt32Number
) cmsSigSampledCurveSeg
)) goto Error
;
4224 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
;
4225 if (!_cmsWriteUInt32Number(io
, ActualSeg
-> nGridPoints
- 1)) goto Error
;
4227 for (j
=1; j
< g
->Segments
[i
].nGridPoints
; j
++) {
4228 if (!_cmsWriteFloat32Number(io
, ActualSeg
-> SampledPoints
[j
])) goto Error
;
4234 cmsUInt32Number ParamsByType
[] = { 4, 5, 5 };
4236 // This is a formula-based
4237 if (!_cmsWriteUInt32Number(io
, (cmsUInt32Number
) cmsSigFormulaCurveSeg
)) goto Error
;
4238 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
;
4240 // We only allow 1, 2 and 3 as types
4241 Type
= ActualSeg
->Type
- 6;
4242 if (Type
> 2 || Type
< 0) goto Error
;
4244 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) Type
)) goto Error
;
4245 if (!_cmsWriteUInt16Number(io
, 0)) goto Error
;
4247 for (j
=0; j
< ParamsByType
[Type
]; j
++) {
4248 if (!_cmsWriteFloat32Number(io
, (cmsFloat32Number
) ActualSeg
->Params
[j
])) goto Error
;
4252 // It seems there is no need to align. Code is here, and for safety commented out
4253 // if (!_cmsWriteAlignment(io)) goto Error;
4264 cmsBool
WriteMPECurve(struct _cms_typehandler_struct
* self
,
4268 cmsUInt32Number SizeOfTag
)
4270 _cmsStageToneCurvesData
* Curves
= (_cmsStageToneCurvesData
*) Cargo
;
4272 return WriteSegmentedCurve(io
, Curves
->TheCurves
[n
]);
4274 cmsUNUSED_PARAMETER(SizeOfTag
);
4275 cmsUNUSED_PARAMETER(self
);
4278 // Write a curve, checking first for validity
4280 cmsBool
Type_MPEcurve_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4282 cmsUInt32Number BaseOffset
;
4283 cmsStage
* mpe
= (cmsStage
*) Ptr
;
4284 _cmsStageToneCurvesData
* Curves
= (_cmsStageToneCurvesData
*) mpe
->Data
;
4286 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
4288 // Write the header. Since those are curves, input and output channels are same
4289 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->InputChannels
)) return FALSE
;
4290 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->InputChannels
)) return FALSE
;
4292 if (!WritePositionTable(self
, io
, 0,
4293 mpe
->InputChannels
, BaseOffset
, Curves
, WriteMPECurve
)) return FALSE
;
4298 cmsUNUSED_PARAMETER(nItems
);
4303 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4304 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4305 // is organized as follows:
4306 // array = [e11, e12, ..., e1P, e21, e22, ..., e2P, ..., eQ1, eQ2, ..., eQP, e1, e2, ..., eQ]
4309 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
4312 cmsUInt16Number InputChans
, OutputChans
;
4313 cmsUInt32Number nElems
, i
;
4314 cmsFloat64Number
* Matrix
;
4315 cmsFloat64Number
* Offsets
;
4317 if (!_cmsReadUInt16Number(io
, &InputChans
)) return NULL
;
4318 if (!_cmsReadUInt16Number(io
, &OutputChans
)) return NULL
;
4321 // Input and output chans may be ANY (up to 0xffff),
4322 // but we choose to limit to 16 channels for now
4323 if (InputChans
>= cmsMAXCHANNELS
) return NULL
;
4324 if (OutputChans
>= cmsMAXCHANNELS
) return NULL
;
4326 nElems
= (cmsUInt32Number
) InputChans
* OutputChans
;
4328 Matrix
= (cmsFloat64Number
*) _cmsCalloc(self
->ContextID
, nElems
, sizeof(cmsFloat64Number
));
4329 if (Matrix
== NULL
) return NULL
;
4331 Offsets
= (cmsFloat64Number
*) _cmsCalloc(self
->ContextID
, OutputChans
, sizeof(cmsFloat64Number
));
4332 if (Offsets
== NULL
) {
4334 _cmsFree(self
->ContextID
, Matrix
);
4338 for (i
=0; i
< nElems
; i
++) {
4342 if (!_cmsReadFloat32Number(io
, &v
)) {
4343 _cmsFree(self
->ContextID
, Matrix
);
4344 _cmsFree(self
->ContextID
, Offsets
);
4351 for (i
=0; i
< OutputChans
; i
++) {
4355 if (!_cmsReadFloat32Number(io
, &v
)) {
4356 _cmsFree(self
->ContextID
, Matrix
);
4357 _cmsFree(self
->ContextID
, Offsets
);
4364 mpe
= cmsStageAllocMatrix(self
->ContextID
, OutputChans
, InputChans
, Matrix
, Offsets
);
4365 _cmsFree(self
->ContextID
, Matrix
);
4366 _cmsFree(self
->ContextID
, Offsets
);
4372 cmsUNUSED_PARAMETER(SizeOfTag
);
4376 cmsBool
Type_MPEmatrix_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4378 cmsUInt32Number i
, nElems
;
4379 cmsStage
* mpe
= (cmsStage
*) Ptr
;
4380 _cmsStageMatrixData
* Matrix
= (_cmsStageMatrixData
*) mpe
->Data
;
4382 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->InputChannels
)) return FALSE
;
4383 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->OutputChannels
)) return FALSE
;
4385 nElems
= mpe
->InputChannels
* mpe
->OutputChannels
;
4387 for (i
=0; i
< nElems
; i
++) {
4388 if (!_cmsWriteFloat32Number(io
, (cmsFloat32Number
) Matrix
->Double
[i
])) return FALSE
;
4392 for (i
=0; i
< mpe
->OutputChannels
; i
++) {
4394 if (Matrix
->Offset
== NULL
) {
4396 if (!_cmsWriteFloat32Number(io
, 0)) return FALSE
;
4399 if (!_cmsWriteFloat32Number(io
, (cmsFloat32Number
) Matrix
->Offset
[i
])) return FALSE
;
4405 cmsUNUSED_PARAMETER(nItems
);
4406 cmsUNUSED_PARAMETER(self
);
4412 void *Type_MPEclut_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
4414 cmsStage
* mpe
= NULL
;
4415 cmsUInt16Number InputChans
, OutputChans
;
4416 cmsUInt8Number Dimensions8
[16];
4417 cmsUInt32Number i
, nMaxGrids
, GridPoints
[MAX_INPUT_DIMENSIONS
];
4418 _cmsStageCLutData
* clut
;
4420 if (!_cmsReadUInt16Number(io
, &InputChans
)) return NULL
;
4421 if (!_cmsReadUInt16Number(io
, &OutputChans
)) return NULL
;
4423 if (InputChans
== 0) goto Error
;
4424 if (OutputChans
== 0) goto Error
;
4426 if (io
->Read(io
, Dimensions8
, sizeof(cmsUInt8Number
), 16) != 16)
4429 // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
4430 nMaxGrids
= InputChans
> MAX_INPUT_DIMENSIONS
? (cmsUInt32Number
) MAX_INPUT_DIMENSIONS
: InputChans
;
4432 for (i
= 0; i
< nMaxGrids
; i
++) {
4433 if (Dimensions8
[i
] == 1) goto Error
; // Impossible value, 0 for no CLUT and then 2 at least
4434 GridPoints
[i
] = (cmsUInt32Number
)Dimensions8
[i
];
4437 // Allocate the true CLUT
4438 mpe
= cmsStageAllocCLutFloatGranular(self
->ContextID
, GridPoints
, InputChans
, OutputChans
, NULL
);
4439 if (mpe
== NULL
) goto Error
;
4441 // Read and sanitize the data
4442 clut
= (_cmsStageCLutData
*) mpe
->Data
;
4443 for (i
=0; i
< clut
->nEntries
; i
++) {
4445 if (!_cmsReadFloat32Number(io
, &clut
->Tab
.TFloat
[i
])) goto Error
;
4453 if (mpe
!= NULL
) cmsStageFree(mpe
);
4456 cmsUNUSED_PARAMETER(SizeOfTag
);
4459 // Write a CLUT in floating point
4461 cmsBool
Type_MPEclut_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4463 cmsUInt8Number Dimensions8
[16]; // 16 because the spec says 16 and not max number of channels
4465 cmsStage
* mpe
= (cmsStage
*) Ptr
;
4466 _cmsStageCLutData
* clut
= (_cmsStageCLutData
*) mpe
->Data
;
4468 // Check for maximum number of channels supported by lcms
4469 if (mpe
-> InputChannels
> MAX_INPUT_DIMENSIONS
) return FALSE
;
4471 // Only floats are supported in MPE
4472 if (clut
->HasFloatValues
== FALSE
) return FALSE
;
4474 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->InputChannels
)) return FALSE
;
4475 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) mpe
->OutputChannels
)) return FALSE
;
4477 memset(Dimensions8
, 0, sizeof(Dimensions8
));
4479 for (i
=0; i
< mpe
->InputChannels
; i
++)
4480 Dimensions8
[i
] = (cmsUInt8Number
) clut
->Params
->nSamples
[i
];
4482 if (!io
->Write(io
, 16, Dimensions8
)) return FALSE
;
4484 for (i
=0; i
< clut
->nEntries
; i
++) {
4486 if (!_cmsWriteFloat32Number(io
, clut
->Tab
.TFloat
[i
])) return FALSE
;
4491 cmsUNUSED_PARAMETER(nItems
);
4492 cmsUNUSED_PARAMETER(self
);
4497 // This is the list of built-in MPE types
4498 static _cmsTagTypeLinkedList SupportedMPEtypes
[] = {
4500 {{ (cmsTagTypeSignature
) cmsSigBAcsElemType
, NULL
, NULL
, NULL
, NULL
, NULL
, 0 }, &SupportedMPEtypes
[1] }, // Ignore those elements for now
4501 {{ (cmsTagTypeSignature
) cmsSigEAcsElemType
, NULL
, NULL
, NULL
, NULL
, NULL
, 0 }, &SupportedMPEtypes
[2] }, // (That's what the spec says)
4503 {TYPE_MPE_HANDLER((cmsTagTypeSignature
) cmsSigCurveSetElemType
, MPEcurve
), &SupportedMPEtypes
[3] },
4504 {TYPE_MPE_HANDLER((cmsTagTypeSignature
) cmsSigMatrixElemType
, MPEmatrix
), &SupportedMPEtypes
[4] },
4505 {TYPE_MPE_HANDLER((cmsTagTypeSignature
) cmsSigCLutElemType
, MPEclut
), NULL
},
4508 _cmsTagTypePluginChunkType _cmsMPETypePluginChunk
= { NULL
};
4511 cmsBool
ReadMPEElem(struct _cms_typehandler_struct
* self
,
4515 cmsUInt32Number SizeOfTag
)
4517 cmsStageSignature ElementSig
;
4518 cmsTagTypeHandler
* TypeHandler
;
4519 cmsUInt32Number nItems
;
4520 cmsPipeline
*NewLUT
= (cmsPipeline
*) Cargo
;
4521 _cmsTagTypePluginChunkType
* MPETypePluginChunk
= ( _cmsTagTypePluginChunkType
*) _cmsContextGetClientChunk(self
->ContextID
, MPEPlugin
);
4524 // Take signature and channels for each element.
4525 if (!_cmsReadUInt32Number(io
, (cmsUInt32Number
*) &ElementSig
)) return FALSE
;
4527 // The reserved placeholder
4528 if (!_cmsReadUInt32Number(io
, NULL
)) return FALSE
;
4530 // Read diverse MPE types
4531 TypeHandler
= GetHandler((cmsTagTypeSignature
) ElementSig
, MPETypePluginChunk
->TagTypes
, SupportedMPEtypes
);
4532 if (TypeHandler
== NULL
) {
4536 _cmsTagSignature2String(String
, (cmsTagSignature
) ElementSig
);
4538 // An unknown element was found.
4539 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown MPE type '%s' found.", String
);
4543 // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
4544 // Read the MPE. No size is given
4545 if (TypeHandler
->ReadPtr
!= NULL
) {
4547 // This is a real element which should be read and processed
4548 if (!cmsPipelineInsertStage(NewLUT
, cmsAT_END
, (cmsStage
*) TypeHandler
->ReadPtr(self
, io
, &nItems
, SizeOfTag
)))
4554 cmsUNUSED_PARAMETER(SizeOfTag
);
4555 cmsUNUSED_PARAMETER(n
);
4559 // This is the main dispatcher for MPE
4561 void *Type_MPE_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
4563 cmsUInt16Number InputChans
, OutputChans
;
4564 cmsUInt32Number ElementCount
;
4565 cmsPipeline
*NewLUT
= NULL
;
4566 cmsUInt32Number BaseOffset
;
4568 // Get actual position as a basis for element offsets
4569 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
4571 // Read channels and element count
4572 if (!_cmsReadUInt16Number(io
, &InputChans
)) return NULL
;
4573 if (!_cmsReadUInt16Number(io
, &OutputChans
)) return NULL
;
4575 if (InputChans
== 0 || InputChans
>= cmsMAXCHANNELS
) return NULL
;
4576 if (OutputChans
== 0 || OutputChans
>= cmsMAXCHANNELS
) return NULL
;
4578 // Allocates an empty LUT
4579 NewLUT
= cmsPipelineAlloc(self
->ContextID
, InputChans
, OutputChans
);
4580 if (NewLUT
== NULL
) return NULL
;
4582 if (!_cmsReadUInt32Number(io
, &ElementCount
)) goto Error
;
4583 if (!ReadPositionTable(self
, io
, ElementCount
, BaseOffset
, NewLUT
, ReadMPEElem
)) goto Error
;
4585 // Check channel count
4586 if (InputChans
!= NewLUT
->InputChannels
||
4587 OutputChans
!= NewLUT
->OutputChannels
) goto Error
;
4595 if (NewLUT
!= NULL
) cmsPipelineFree(NewLUT
);
4599 cmsUNUSED_PARAMETER(SizeOfTag
);
4604 // This one is a little bit more complex, so we don't use position tables this time.
4606 cmsBool
Type_MPE_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4608 cmsUInt32Number i
, BaseOffset
, DirectoryPos
, CurrentPos
;
4609 cmsUInt32Number inputChan
, outputChan
;
4610 cmsUInt32Number ElemCount
;
4611 cmsUInt32Number
*ElementOffsets
= NULL
, *ElementSizes
= NULL
, Before
;
4612 cmsStageSignature ElementSig
;
4613 cmsPipeline
* Lut
= (cmsPipeline
*) Ptr
;
4614 cmsStage
* Elem
= Lut
->Elements
;
4615 cmsTagTypeHandler
* TypeHandler
;
4616 _cmsTagTypePluginChunkType
* MPETypePluginChunk
= ( _cmsTagTypePluginChunkType
*) _cmsContextGetClientChunk(self
->ContextID
, MPEPlugin
);
4618 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
4620 inputChan
= cmsPipelineInputChannels(Lut
);
4621 outputChan
= cmsPipelineOutputChannels(Lut
);
4622 ElemCount
= cmsPipelineStageCount(Lut
);
4624 ElementOffsets
= (cmsUInt32Number
*) _cmsCalloc(self
->ContextID
, ElemCount
, sizeof(cmsUInt32Number
));
4625 if (ElementOffsets
== NULL
) goto Error
;
4627 ElementSizes
= (cmsUInt32Number
*) _cmsCalloc(self
->ContextID
, ElemCount
, sizeof(cmsUInt32Number
));
4628 if (ElementSizes
== NULL
) goto Error
;
4631 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) inputChan
)) goto Error
;
4632 if (!_cmsWriteUInt16Number(io
, (cmsUInt16Number
) outputChan
)) goto Error
;
4633 if (!_cmsWriteUInt32Number(io
, (cmsUInt16Number
) ElemCount
)) goto Error
;
4635 DirectoryPos
= io
->Tell(io
);
4637 // Write a fake directory to be filled latter on
4638 for (i
=0; i
< ElemCount
; i
++) {
4639 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
; // Offset
4640 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
; // size
4643 // Write each single tag. Keep track of the size as well.
4644 for (i
=0; i
< ElemCount
; i
++) {
4646 ElementOffsets
[i
] = io
->Tell(io
) - BaseOffset
;
4648 ElementSig
= Elem
->Type
;
4650 TypeHandler
= GetHandler((cmsTagTypeSignature
) ElementSig
, MPETypePluginChunk
->TagTypes
, SupportedMPEtypes
);
4651 if (TypeHandler
== NULL
) {
4655 _cmsTagSignature2String(String
, (cmsTagSignature
) ElementSig
);
4657 // An unknown element was found.
4658 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Found unknown MPE type '%s'", String
);
4662 if (!_cmsWriteUInt32Number(io
, ElementSig
)) goto Error
;
4663 if (!_cmsWriteUInt32Number(io
, 0)) goto Error
;
4664 Before
= io
->Tell(io
);
4665 if (!TypeHandler
->WritePtr(self
, io
, Elem
, 1)) goto Error
;
4666 if (!_cmsWriteAlignment(io
)) goto Error
;
4668 ElementSizes
[i
] = io
->Tell(io
) - Before
;
4673 // Write the directory
4674 CurrentPos
= io
->Tell(io
);
4676 if (!io
->Seek(io
, DirectoryPos
)) goto Error
;
4678 for (i
=0; i
< ElemCount
; i
++) {
4679 if (!_cmsWriteUInt32Number(io
, ElementOffsets
[i
])) goto Error
;
4680 if (!_cmsWriteUInt32Number(io
, ElementSizes
[i
])) goto Error
;
4683 if (!io
->Seek(io
, CurrentPos
)) goto Error
;
4685 if (ElementOffsets
!= NULL
) _cmsFree(self
->ContextID
, ElementOffsets
);
4686 if (ElementSizes
!= NULL
) _cmsFree(self
->ContextID
, ElementSizes
);
4690 if (ElementOffsets
!= NULL
) _cmsFree(self
->ContextID
, ElementOffsets
);
4691 if (ElementSizes
!= NULL
) _cmsFree(self
->ContextID
, ElementSizes
);
4694 cmsUNUSED_PARAMETER(nItems
);
4699 void* Type_MPE_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
4701 return (void*) cmsPipelineDup((cmsPipeline
*) Ptr
);
4703 cmsUNUSED_PARAMETER(n
);
4704 cmsUNUSED_PARAMETER(self
);
4708 void Type_MPE_Free(struct _cms_typehandler_struct
* self
, void *Ptr
)
4710 cmsPipelineFree((cmsPipeline
*) Ptr
);
4713 cmsUNUSED_PARAMETER(self
);
4717 // ********************************************************************************
4718 // Type cmsSigVcgtType
4719 // ********************************************************************************
4722 #define cmsVideoCardGammaTableType 0
4723 #define cmsVideoCardGammaFormulaType 1
4734 void *Type_vcgt_Read(struct _cms_typehandler_struct
* self
,
4736 cmsUInt32Number
* nItems
,
4737 cmsUInt32Number SizeOfTag
)
4739 cmsUInt32Number TagType
, n
, i
;
4740 cmsToneCurve
** Curves
;
4745 if (!_cmsReadUInt32Number(io
, &TagType
)) return NULL
;
4747 // Allocate space for the array
4748 Curves
= ( cmsToneCurve
**) _cmsCalloc(self
->ContextID
, 3, sizeof(cmsToneCurve
*));
4749 if (Curves
== NULL
) return NULL
;
4751 // There are two possible flavors
4754 // Gamma is stored as a table
4755 case cmsVideoCardGammaTableType
:
4757 cmsUInt16Number nChannels
, nElems
, nBytes
;
4759 // Check channel count, which should be 3 (we don't support monochrome this time)
4760 if (!_cmsReadUInt16Number(io
, &nChannels
)) goto Error
;
4762 if (nChannels
!= 3) {
4763 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unsupported number of channels for VCGT '%d'", nChannels
);
4767 // Get Table element count and bytes per element
4768 if (!_cmsReadUInt16Number(io
, &nElems
)) goto Error
;
4769 if (!_cmsReadUInt16Number(io
, &nBytes
)) goto Error
;
4771 // Adobe's quirk fixup. Fixing broken profiles...
4772 if (nElems
== 256 && nBytes
== 1 && SizeOfTag
== 1576)
4776 // Populate tone curves
4777 for (n
=0; n
< 3; n
++) {
4779 Curves
[n
] = cmsBuildTabulatedToneCurve16(self
->ContextID
, nElems
, NULL
);
4780 if (Curves
[n
] == NULL
) goto Error
;
4782 // On depending on byte depth
4787 for (i
=0; i
< nElems
; i
++) {
4791 if (!_cmsReadUInt8Number(io
, &v
)) goto Error
;
4792 Curves
[n
] ->Table16
[i
] = FROM_8_TO_16(v
);
4796 // One word 0..65535
4798 if (!_cmsReadUInt16Array(io
, nElems
, Curves
[n
]->Table16
)) goto Error
;
4803 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unsupported bit depth for VCGT '%d'", nBytes
* 8);
4806 } // For all 3 channels
4810 // In this case, gamma is stored as a formula
4811 case cmsVideoCardGammaFormulaType
:
4813 _cmsVCGTGAMMA Colorant
[3];
4815 // Populate tone curves
4816 for (n
=0; n
< 3; n
++) {
4820 if (!_cmsRead15Fixed16Number(io
, &Colorant
[n
].Gamma
)) goto Error
;
4821 if (!_cmsRead15Fixed16Number(io
, &Colorant
[n
].Min
)) goto Error
;
4822 if (!_cmsRead15Fixed16Number(io
, &Colorant
[n
].Max
)) goto Error
;
4824 // Parametric curve type 5 is:
4825 // Y = (aX + b)^Gamma + e | X >= d
4826 // Y = cX + f | X < d
4829 // Y = (Max - Min) * (X ^ Gamma) + Min
4831 // So, the translation is
4832 // a = (Max - Min) ^ ( 1 / Gamma)
4836 Params
[0] = Colorant
[n
].Gamma
;
4837 Params
[1] = pow((Colorant
[n
].Max
- Colorant
[n
].Min
), (1.0 / Colorant
[n
].Gamma
));
4841 Params
[5] = Colorant
[n
].Min
;
4844 Curves
[n
] = cmsBuildParametricToneCurve(self
->ContextID
, 5, Params
);
4845 if (Curves
[n
] == NULL
) goto Error
;
4852 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unsupported tag type for VCGT '%d'", TagType
);
4857 return (void*) Curves
;
4859 // Regret, free all resources
4862 cmsFreeToneCurveTriple(Curves
);
4863 _cmsFree(self
->ContextID
, Curves
);
4866 cmsUNUSED_PARAMETER(SizeOfTag
);
4870 // We don't support all flavors, only 16bits tables and formula
4872 cmsBool
Type_vcgt_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
4874 cmsToneCurve
** Curves
= (cmsToneCurve
**) Ptr
;
4875 cmsUInt32Number i
, j
;
4877 if (cmsGetToneCurveParametricType(Curves
[0]) == 5 &&
4878 cmsGetToneCurveParametricType(Curves
[1]) == 5 &&
4879 cmsGetToneCurveParametricType(Curves
[2]) == 5) {
4881 if (!_cmsWriteUInt32Number(io
, cmsVideoCardGammaFormulaType
)) return FALSE
;
4884 for (i
=0; i
< 3; i
++) {
4888 v
.Gamma
= Curves
[i
] ->Segments
[0].Params
[0];
4889 v
.Min
= Curves
[i
] ->Segments
[0].Params
[5];
4890 v
.Max
= pow(Curves
[i
] ->Segments
[0].Params
[1], v
.Gamma
) + v
.Min
;
4892 if (!_cmsWrite15Fixed16Number(io
, v
.Gamma
)) return FALSE
;
4893 if (!_cmsWrite15Fixed16Number(io
, v
.Min
)) return FALSE
;
4894 if (!_cmsWrite15Fixed16Number(io
, v
.Max
)) return FALSE
;
4900 // Always store as a table of 256 words
4901 if (!_cmsWriteUInt32Number(io
, cmsVideoCardGammaTableType
)) return FALSE
;
4902 if (!_cmsWriteUInt16Number(io
, 3)) return FALSE
;
4903 if (!_cmsWriteUInt16Number(io
, 256)) return FALSE
;
4904 if (!_cmsWriteUInt16Number(io
, 2)) return FALSE
;
4906 for (i
=0; i
< 3; i
++) {
4907 for (j
=0; j
< 256; j
++) {
4909 cmsFloat32Number v
= cmsEvalToneCurveFloat(Curves
[i
], (cmsFloat32Number
) (j
/ 255.0));
4910 cmsUInt16Number n
= _cmsQuickSaturateWord(v
* 65535.0);
4912 if (!_cmsWriteUInt16Number(io
, n
)) return FALSE
;
4919 cmsUNUSED_PARAMETER(self
);
4920 cmsUNUSED_PARAMETER(nItems
);
4924 void* Type_vcgt_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
4926 cmsToneCurve
** OldCurves
= (cmsToneCurve
**) Ptr
;
4927 cmsToneCurve
** NewCurves
;
4929 NewCurves
= ( cmsToneCurve
**) _cmsCalloc(self
->ContextID
, 3, sizeof(cmsToneCurve
*));
4930 if (NewCurves
== NULL
) return NULL
;
4932 NewCurves
[0] = cmsDupToneCurve(OldCurves
[0]);
4933 NewCurves
[1] = cmsDupToneCurve(OldCurves
[1]);
4934 NewCurves
[2] = cmsDupToneCurve(OldCurves
[2]);
4936 return (void*) NewCurves
;
4938 cmsUNUSED_PARAMETER(n
);
4943 void Type_vcgt_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
4945 cmsFreeToneCurveTriple((cmsToneCurve
**) Ptr
);
4946 _cmsFree(self
->ContextID
, Ptr
);
4950 // ********************************************************************************
4951 // Type cmsSigDictType
4952 // ********************************************************************************
4954 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data
4956 cmsContext ContextID
;
4957 cmsUInt32Number
*Offsets
;
4958 cmsUInt32Number
*Sizes
;
4962 _cmsDICelem Name
, Value
, DisplayName
, DisplayValue
;
4966 // Allocate an empty array element
4968 cmsBool
AllocElem(cmsContext ContextID
, _cmsDICelem
* e
, cmsUInt32Number Count
)
4970 e
->Offsets
= (cmsUInt32Number
*) _cmsCalloc(ContextID
, Count
, sizeof(cmsUInt32Number
));
4971 if (e
->Offsets
== NULL
) return FALSE
;
4973 e
->Sizes
= (cmsUInt32Number
*) _cmsCalloc(ContextID
, Count
, sizeof(cmsUInt32Number
));
4974 if (e
->Sizes
== NULL
) {
4976 _cmsFree(ContextID
, e
-> Offsets
);
4980 e
->ContextID
= ContextID
;
4984 // Free an array element
4986 void FreeElem(_cmsDICelem
* e
)
4988 if (e
->Offsets
!= NULL
) _cmsFree(e
-> ContextID
, e
-> Offsets
);
4989 if (e
->Sizes
!= NULL
) _cmsFree(e
-> ContextID
, e
-> Sizes
);
4990 e
->Offsets
= e
->Sizes
= NULL
;
4993 // Get rid of whole array
4995 void FreeArray( _cmsDICarray
* a
)
4997 if (a
->Name
.Offsets
!= NULL
) FreeElem(&a
->Name
);
4998 if (a
->Value
.Offsets
!= NULL
) FreeElem(&a
->Value
);
4999 if (a
->DisplayName
.Offsets
!= NULL
) FreeElem(&a
->DisplayName
);
5000 if (a
->DisplayValue
.Offsets
!= NULL
) FreeElem(&a
->DisplayValue
);
5004 // Allocate whole array
5006 cmsBool
AllocArray(cmsContext ContextID
, _cmsDICarray
* a
, cmsUInt32Number Count
, cmsUInt32Number Length
)
5009 memset(a
, 0, sizeof(_cmsDICarray
));
5011 // On depending on record size, create column arrays
5012 if (!AllocElem(ContextID
, &a
->Name
, Count
)) goto Error
;
5013 if (!AllocElem(ContextID
, &a
->Value
, Count
)) goto Error
;
5016 if (!AllocElem(ContextID
, &a
-> DisplayName
, Count
)) goto Error
;
5020 if (!AllocElem(ContextID
, &a
->DisplayValue
, Count
)) goto Error
;
5031 cmsBool
ReadOneElem(cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, cmsUInt32Number BaseOffset
)
5033 if (!_cmsReadUInt32Number(io
, &e
->Offsets
[i
])) return FALSE
;
5034 if (!_cmsReadUInt32Number(io
, &e
->Sizes
[i
])) return FALSE
;
5036 // An offset of zero has special meaning and shall be preserved
5037 if (e
->Offsets
[i
] > 0)
5038 e
->Offsets
[i
] += BaseOffset
;
5044 cmsBool
ReadOffsetArray(cmsIOHANDLER
* io
, _cmsDICarray
* a
,
5045 cmsUInt32Number Count
, cmsUInt32Number Length
, cmsUInt32Number BaseOffset
,
5046 cmsInt32Number
* SignedSizeOfTagPtr
)
5049 cmsInt32Number SignedSizeOfTag
= *SignedSizeOfTagPtr
;
5051 // Read column arrays
5052 for (i
=0; i
< Count
; i
++) {
5054 if (SignedSizeOfTag
< 4 * (cmsInt32Number
) sizeof(cmsUInt32Number
)) return FALSE
;
5055 SignedSizeOfTag
-= 4 * sizeof(cmsUInt32Number
);
5057 if (!ReadOneElem(io
, &a
-> Name
, i
, BaseOffset
)) return FALSE
;
5058 if (!ReadOneElem(io
, &a
-> Value
, i
, BaseOffset
)) return FALSE
;
5062 if (SignedSizeOfTag
< 2 * (cmsInt32Number
) sizeof(cmsUInt32Number
)) return FALSE
;
5063 SignedSizeOfTag
-= 2 * sizeof(cmsUInt32Number
);
5065 if (!ReadOneElem(io
, &a
->DisplayName
, i
, BaseOffset
)) return FALSE
;
5071 if (SignedSizeOfTag
< 2 * (cmsInt32Number
) sizeof(cmsUInt32Number
)) return FALSE
;
5072 SignedSizeOfTag
-= 2 * (cmsInt32Number
) sizeof(cmsUInt32Number
);
5074 if (!ReadOneElem(io
, & a
-> DisplayValue
, i
, BaseOffset
)) return FALSE
;
5078 *SignedSizeOfTagPtr
= SignedSizeOfTag
;
5083 // Write one element
5085 cmsBool
WriteOneElem(cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
)
5087 if (!_cmsWriteUInt32Number(io
, e
->Offsets
[i
])) return FALSE
;
5088 if (!_cmsWriteUInt32Number(io
, e
->Sizes
[i
])) return FALSE
;
5094 cmsBool
WriteOffsetArray(cmsIOHANDLER
* io
, _cmsDICarray
* a
, cmsUInt32Number Count
, cmsUInt32Number Length
)
5098 for (i
=0; i
< Count
; i
++) {
5100 if (!WriteOneElem(io
, &a
-> Name
, i
)) return FALSE
;
5101 if (!WriteOneElem(io
, &a
-> Value
, i
)) return FALSE
;
5105 if (!WriteOneElem(io
, &a
-> DisplayName
, i
)) return FALSE
;
5110 if (!WriteOneElem(io
, &a
-> DisplayValue
, i
)) return FALSE
;
5118 cmsBool
ReadOneWChar(cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, wchar_t ** wcstr
)
5121 cmsUInt32Number nChars
;
5123 // Special case for undefined strings (see ICC Votable
5124 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
5125 if (e
-> Offsets
[i
] == 0) {
5131 if (!io
-> Seek(io
, e
-> Offsets
[i
])) return FALSE
;
5133 nChars
= e
->Sizes
[i
] / sizeof(cmsUInt16Number
);
5136 *wcstr
= (wchar_t*) _cmsMallocZero(e
->ContextID
, (nChars
+ 1) * sizeof(wchar_t));
5137 if (*wcstr
== NULL
) return FALSE
;
5139 if (!_cmsReadWCharArray(io
, nChars
, *wcstr
)) {
5140 _cmsFree(e
->ContextID
, *wcstr
);
5144 // End of string marker
5145 (*wcstr
)[nChars
] = 0;
5150 cmsUInt32Number
mywcslen(const wchar_t *s
)
5158 return (cmsUInt32Number
)(p
- s
);
5162 cmsBool
WriteOneWChar(cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, const wchar_t * wcstr
, cmsUInt32Number BaseOffset
)
5164 cmsUInt32Number Before
= io
->Tell(io
);
5167 e
->Offsets
[i
] = Before
- BaseOffset
;
5169 if (wcstr
== NULL
) {
5175 n
= mywcslen(wcstr
);
5176 if (!_cmsWriteWCharArray(io
, n
, wcstr
)) return FALSE
;
5178 e
->Sizes
[i
] = io
->Tell(io
) - Before
;
5183 cmsBool
ReadOneMLUC(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, cmsMLU
** mlu
)
5185 cmsUInt32Number nItems
= 0;
5187 // A way to get null MLUCs
5188 if (e
-> Offsets
[i
] == 0 || e
->Sizes
[i
] == 0) {
5194 if (!io
-> Seek(io
, e
-> Offsets
[i
])) return FALSE
;
5196 *mlu
= (cmsMLU
*) Type_MLU_Read(self
, io
, &nItems
, e
->Sizes
[i
]);
5197 return *mlu
!= NULL
;
5201 cmsBool
WriteOneMLUC(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, _cmsDICelem
* e
, cmsUInt32Number i
, const cmsMLU
* mlu
, cmsUInt32Number BaseOffset
)
5203 cmsUInt32Number Before
;
5205 // Special case for undefined strings (see ICC Votable
5206 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
5213 Before
= io
->Tell(io
);
5214 e
->Offsets
[i
] = Before
- BaseOffset
;
5216 if (!Type_MLU_Write(self
, io
, (void*) mlu
, 1)) return FALSE
;
5218 e
->Sizes
[i
] = io
->Tell(io
) - Before
;
5224 void *Type_Dictionary_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
5226 cmsHANDLE hDict
= NULL
;
5227 cmsUInt32Number i
, Count
, Length
;
5228 cmsUInt32Number BaseOffset
;
5230 wchar_t *NameWCS
= NULL
, *ValueWCS
= NULL
;
5231 cmsMLU
*DisplayNameMLU
= NULL
, *DisplayValueMLU
=NULL
;
5233 cmsInt32Number SignedSizeOfTag
= (cmsInt32Number
)SizeOfTag
;
5236 memset(&a
, 0, sizeof(a
));
5238 // Get actual position as a basis for element offsets
5239 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
5241 // Get name-value record count
5242 SignedSizeOfTag
-= sizeof(cmsUInt32Number
);
5243 if (SignedSizeOfTag
< 0) goto Error
;
5244 if (!_cmsReadUInt32Number(io
, &Count
)) return NULL
;
5247 SignedSizeOfTag
-= sizeof(cmsUInt32Number
);
5248 if (SignedSizeOfTag
< 0) goto Error
;
5249 if (!_cmsReadUInt32Number(io
, &Length
)) return NULL
;
5252 // Check for valid lengths
5253 if (Length
!= 16 && Length
!= 24 && Length
!= 32) {
5254 cmsSignalError(self
->ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unknown record length in dictionary '%d'", Length
);
5258 // Creates an empty dictionary
5259 hDict
= cmsDictAlloc(self
-> ContextID
);
5260 if (hDict
== NULL
) return NULL
;
5262 // On depending on record size, create column arrays
5263 if (!AllocArray(self
-> ContextID
, &a
, Count
, Length
)) goto Error
;
5265 // Read column arrays
5266 if (!ReadOffsetArray(io
, &a
, Count
, Length
, BaseOffset
, &SignedSizeOfTag
)) goto Error
;
5268 // Seek to each element and read it
5269 for (i
=0; i
< Count
; i
++) {
5271 if (!ReadOneWChar(io
, &a
.Name
, i
, &NameWCS
)) goto Error
;
5272 if (!ReadOneWChar(io
, &a
.Value
, i
, &ValueWCS
)) goto Error
;
5275 if (!ReadOneMLUC(self
, io
, &a
.DisplayName
, i
, &DisplayNameMLU
)) goto Error
;
5279 if (!ReadOneMLUC(self
, io
, &a
.DisplayValue
, i
, &DisplayValueMLU
)) goto Error
;
5282 if (NameWCS
== NULL
|| ValueWCS
== NULL
) {
5284 cmsSignalError(self
->ContextID
, cmsERROR_CORRUPTION_DETECTED
, "Bad dictionary Name/Value");
5289 rc
= cmsDictAddEntry(hDict
, NameWCS
, ValueWCS
, DisplayNameMLU
, DisplayValueMLU
);
5292 if (NameWCS
!= NULL
) _cmsFree(self
->ContextID
, NameWCS
);
5293 if (ValueWCS
!= NULL
) _cmsFree(self
->ContextID
, ValueWCS
);
5294 if (DisplayNameMLU
!= NULL
) cmsMLUfree(DisplayNameMLU
);
5295 if (DisplayValueMLU
!= NULL
) cmsMLUfree(DisplayValueMLU
);
5297 if (!rc
) goto Error
;
5302 return (void*) hDict
;
5306 if (hDict
!= NULL
) cmsDictFree(hDict
);
5312 cmsBool
Type_Dictionary_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
5314 cmsHANDLE hDict
= (cmsHANDLE
) Ptr
;
5315 const cmsDICTentry
* p
;
5316 cmsBool AnyName
, AnyValue
;
5317 cmsUInt32Number i
, Count
, Length
;
5318 cmsUInt32Number DirectoryPos
, CurrentPos
, BaseOffset
;
5321 if (hDict
== NULL
) return FALSE
;
5323 BaseOffset
= io
->Tell(io
) - sizeof(_cmsTagBase
);
5325 // Let's inspect the dictionary
5326 Count
= 0; AnyName
= FALSE
; AnyValue
= FALSE
;
5327 for (p
= cmsDictGetEntryList(hDict
); p
!= NULL
; p
= cmsDictNextEntry(p
)) {
5329 if (p
->DisplayName
!= NULL
) AnyName
= TRUE
;
5330 if (p
->DisplayValue
!= NULL
) AnyValue
= TRUE
;
5335 if (AnyName
) Length
+= 8;
5336 if (AnyValue
) Length
+= 8;
5338 if (!_cmsWriteUInt32Number(io
, Count
)) return FALSE
;
5339 if (!_cmsWriteUInt32Number(io
, Length
)) return FALSE
;
5341 // Keep starting position of offsets table
5342 DirectoryPos
= io
->Tell(io
);
5344 // Allocate offsets array
5345 if (!AllocArray(self
->ContextID
, &a
, Count
, Length
)) goto Error
;
5347 // Write a fake directory to be filled latter on
5348 if (!WriteOffsetArray(io
, &a
, Count
, Length
)) goto Error
;
5350 // Write each element. Keep track of the size as well.
5351 p
= cmsDictGetEntryList(hDict
);
5352 for (i
=0; i
< Count
; i
++) {
5354 if (!WriteOneWChar(io
, &a
.Name
, i
, p
->Name
, BaseOffset
)) goto Error
;
5355 if (!WriteOneWChar(io
, &a
.Value
, i
, p
->Value
, BaseOffset
)) goto Error
;
5357 if (p
->DisplayName
!= NULL
) {
5358 if (!WriteOneMLUC(self
, io
, &a
.DisplayName
, i
, p
->DisplayName
, BaseOffset
)) goto Error
;
5361 if (p
->DisplayValue
!= NULL
) {
5362 if (!WriteOneMLUC(self
, io
, &a
.DisplayValue
, i
, p
->DisplayValue
, BaseOffset
)) goto Error
;
5365 p
= cmsDictNextEntry(p
);
5368 // Write the directory
5369 CurrentPos
= io
->Tell(io
);
5370 if (!io
->Seek(io
, DirectoryPos
)) goto Error
;
5372 if (!WriteOffsetArray(io
, &a
, Count
, Length
)) goto Error
;
5374 if (!io
->Seek(io
, CurrentPos
)) goto Error
;
5383 cmsUNUSED_PARAMETER(nItems
);
5388 void* Type_Dictionary_Dup(struct _cms_typehandler_struct
* self
, const void *Ptr
, cmsUInt32Number n
)
5390 return (void*) cmsDictDup((cmsHANDLE
) Ptr
);
5392 cmsUNUSED_PARAMETER(n
);
5393 cmsUNUSED_PARAMETER(self
);
5398 void Type_Dictionary_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
5400 cmsDictFree((cmsHANDLE
) Ptr
);
5401 cmsUNUSED_PARAMETER(self
);
5404 // cicp VideoSignalType
5407 void* Type_VideoSignal_Read(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, cmsUInt32Number
* nItems
, cmsUInt32Number SizeOfTag
)
5409 cmsVideoSignalType
* cicp
= NULL
;
5411 if (SizeOfTag
!= 8) return NULL
;
5413 if (!_cmsReadUInt32Number(io
, NULL
)) return NULL
;
5415 cicp
= (cmsVideoSignalType
*)_cmsCalloc(self
->ContextID
, 1, sizeof(cmsVideoSignalType
));
5416 if (cicp
== NULL
) return NULL
;
5418 if (!_cmsReadUInt8Number(io
, &cicp
->ColourPrimaries
)) goto Error
;
5419 if (!_cmsReadUInt8Number(io
, &cicp
->TransferCharacteristics
)) goto Error
;
5420 if (!_cmsReadUInt8Number(io
, &cicp
->MatrixCoefficients
)) goto Error
;
5421 if (!_cmsReadUInt8Number(io
, &cicp
->VideoFullRangeFlag
)) goto Error
;
5428 if (cicp
!= NULL
) _cmsFree(self
->ContextID
, cicp
);
5433 cmsBool
Type_VideoSignal_Write(struct _cms_typehandler_struct
* self
, cmsIOHANDLER
* io
, void* Ptr
, cmsUInt32Number nItems
)
5435 cmsVideoSignalType
* cicp
= (cmsVideoSignalType
*)Ptr
;
5437 if (!_cmsWriteUInt32Number(io
, 0)) return FALSE
;
5438 if (!_cmsWriteUInt8Number(io
, cicp
->ColourPrimaries
)) return FALSE
;
5439 if (!_cmsWriteUInt8Number(io
, cicp
->TransferCharacteristics
)) return FALSE
;
5440 if (!_cmsWriteUInt8Number(io
, cicp
->MatrixCoefficients
)) return FALSE
;
5441 if (!_cmsWriteUInt8Number(io
, cicp
->VideoFullRangeFlag
)) return FALSE
;
5445 cmsUNUSED_PARAMETER(self
);
5446 cmsUNUSED_PARAMETER(nItems
);
5449 void* Type_VideoSignal_Dup(struct _cms_typehandler_struct
* self
, const void* Ptr
, cmsUInt32Number n
)
5451 return _cmsDupMem(self
->ContextID
, Ptr
, sizeof(cmsVideoSignalType
));
5453 cmsUNUSED_PARAMETER(n
);
5458 void Type_VideoSignal_Free(struct _cms_typehandler_struct
* self
, void* Ptr
)
5460 _cmsFree(self
->ContextID
, Ptr
);
5463 // ********************************************************************************
5464 // Type support main routines
5465 // ********************************************************************************
5468 // This is the list of built-in types
5469 static const _cmsTagTypeLinkedList SupportedTagTypes
[] = {
5471 {TYPE_HANDLER(cmsSigChromaticityType
, Chromaticity
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[1] },
5472 {TYPE_HANDLER(cmsSigColorantOrderType
, ColorantOrderType
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[2] },
5473 {TYPE_HANDLER(cmsSigS15Fixed16ArrayType
, S15Fixed16
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[3] },
5474 {TYPE_HANDLER(cmsSigU16Fixed16ArrayType
, U16Fixed16
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[4] },
5475 {TYPE_HANDLER(cmsSigTextType
, Text
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[5] },
5476 {TYPE_HANDLER(cmsSigTextDescriptionType
, Text_Description
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[6] },
5477 {TYPE_HANDLER(cmsSigCurveType
, Curve
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[7] },
5478 {TYPE_HANDLER(cmsSigParametricCurveType
, ParametricCurve
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[8] },
5479 {TYPE_HANDLER(cmsSigDateTimeType
, DateTime
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[9] },
5480 {TYPE_HANDLER(cmsSigLut8Type
, LUT8
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[10] },
5481 {TYPE_HANDLER(cmsSigLut16Type
, LUT16
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[11] },
5482 {TYPE_HANDLER(cmsSigColorantTableType
, ColorantTable
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[12] },
5483 {TYPE_HANDLER(cmsSigNamedColor2Type
, NamedColor
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[13] },
5484 {TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType
, MLU
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[14] },
5485 {TYPE_HANDLER(cmsSigProfileSequenceDescType
, ProfileSequenceDesc
),(_cmsTagTypeLinkedList
*) &SupportedTagTypes
[15] },
5486 {TYPE_HANDLER(cmsSigSignatureType
, Signature
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[16] },
5487 {TYPE_HANDLER(cmsSigMeasurementType
, Measurement
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[17] },
5488 {TYPE_HANDLER(cmsSigDataType
, Data
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[18] },
5489 {TYPE_HANDLER(cmsSigLutAtoBType
, LUTA2B
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[19] },
5490 {TYPE_HANDLER(cmsSigLutBtoAType
, LUTB2A
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[20] },
5491 {TYPE_HANDLER(cmsSigUcrBgType
, UcrBg
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[21] },
5492 {TYPE_HANDLER(cmsSigCrdInfoType
, CrdInfo
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[22] },
5493 {TYPE_HANDLER(cmsSigMultiProcessElementType
, MPE
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[23] },
5494 {TYPE_HANDLER(cmsSigScreeningType
, Screening
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[24] },
5495 {TYPE_HANDLER(cmsSigViewingConditionsType
, ViewingConditions
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[25] },
5496 {TYPE_HANDLER(cmsSigXYZType
, XYZ
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[26] },
5497 {TYPE_HANDLER(cmsCorbisBrokenXYZtype
, XYZ
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[27] },
5498 {TYPE_HANDLER(cmsMonacoBrokenCurveType
, Curve
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[28] },
5499 {TYPE_HANDLER(cmsSigProfileSequenceIdType
, ProfileSequenceId
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[29] },
5500 {TYPE_HANDLER(cmsSigDictType
, Dictionary
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[30] },
5501 {TYPE_HANDLER(cmsSigcicpType
, VideoSignal
), (_cmsTagTypeLinkedList
*) &SupportedTagTypes
[31] },
5502 {TYPE_HANDLER(cmsSigVcgtType
, vcgt
), NULL
}
5506 _cmsTagTypePluginChunkType _cmsTagTypePluginChunk
= { NULL
};
5510 // Duplicates the zone of memory used by the plug-in in the new context
5512 void DupTagTypeList(struct _cmsContext_struct
* ctx
,
5513 const struct _cmsContext_struct
* src
,
5516 _cmsTagTypePluginChunkType newHead
= { NULL
};
5517 _cmsTagTypeLinkedList
* entry
;
5518 _cmsTagTypeLinkedList
* Anterior
= NULL
;
5519 _cmsTagTypePluginChunkType
* head
= (_cmsTagTypePluginChunkType
*) src
->chunks
[loc
];
5521 // Walk the list copying all nodes
5522 for (entry
= head
->TagTypes
;
5524 entry
= entry
->Next
) {
5526 _cmsTagTypeLinkedList
*newEntry
= ( _cmsTagTypeLinkedList
*) _cmsSubAllocDup(ctx
->MemPool
, entry
, sizeof(_cmsTagTypeLinkedList
));
5528 if (newEntry
== NULL
)
5531 // We want to keep the linked list order, so this is a little bit tricky
5532 newEntry
-> Next
= NULL
;
5534 Anterior
-> Next
= newEntry
;
5536 Anterior
= newEntry
;
5538 if (newHead
.TagTypes
== NULL
)
5539 newHead
.TagTypes
= newEntry
;
5542 ctx
->chunks
[loc
] = _cmsSubAllocDup(ctx
->MemPool
, &newHead
, sizeof(_cmsTagTypePluginChunkType
));
5546 void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct
* ctx
,
5547 const struct _cmsContext_struct
* src
)
5551 // Duplicate the LIST
5552 DupTagTypeList(ctx
, src
, TagTypePlugin
);
5555 static _cmsTagTypePluginChunkType TagTypePluginChunk
= { NULL
};
5556 ctx
->chunks
[TagTypePlugin
] = _cmsSubAllocDup(ctx
->MemPool
, &TagTypePluginChunk
, sizeof(_cmsTagTypePluginChunkType
));
5560 void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct
* ctx
,
5561 const struct _cmsContext_struct
* src
)
5565 // Duplicate the LIST
5566 DupTagTypeList(ctx
, src
, MPEPlugin
);
5569 static _cmsTagTypePluginChunkType TagTypePluginChunk
= { NULL
};
5570 ctx
->chunks
[MPEPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, &TagTypePluginChunk
, sizeof(_cmsTagTypePluginChunkType
));
5576 // Both kind of plug-ins share same structure
5577 cmsBool
_cmsRegisterTagTypePlugin(cmsContext id
, cmsPluginBase
* Data
)
5579 return RegisterTypesPlugin(id
, Data
, TagTypePlugin
);
5582 cmsBool
_cmsRegisterMultiProcessElementPlugin(cmsContext id
, cmsPluginBase
* Data
)
5584 return RegisterTypesPlugin(id
, Data
,MPEPlugin
);
5588 // Wrapper for tag types
5589 cmsTagTypeHandler
* _cmsGetTagTypeHandler(cmsContext ContextID
, cmsTagTypeSignature sig
)
5591 _cmsTagTypePluginChunkType
* ctx
= ( _cmsTagTypePluginChunkType
*) _cmsContextGetClientChunk(ContextID
, TagTypePlugin
);
5593 return GetHandler(sig
, ctx
->TagTypes
, (_cmsTagTypeLinkedList
*) SupportedTagTypes
);
5596 // ********************************************************************************
5597 // Tag support main routines
5598 // ********************************************************************************
5600 typedef struct _cmsTagLinkedList_st
{
5602 cmsTagSignature Signature
;
5603 cmsTagDescriptor Descriptor
;
5604 struct _cmsTagLinkedList_st
* Next
;
5606 } _cmsTagLinkedList
;
5608 // This is the list of built-in tags. The data of this list can be modified by plug-ins
5609 static _cmsTagLinkedList SupportedTags
[] = {
5611 { cmsSigAToB0Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutAtoBType
, cmsSigLut8Type
}, DecideLUTtypeA2B
}, &SupportedTags
[1]},
5612 { cmsSigAToB1Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutAtoBType
, cmsSigLut8Type
}, DecideLUTtypeA2B
}, &SupportedTags
[2]},
5613 { cmsSigAToB2Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutAtoBType
, cmsSigLut8Type
}, DecideLUTtypeA2B
}, &SupportedTags
[3]},
5614 { cmsSigBToA0Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[4]},
5615 { cmsSigBToA1Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[5]},
5616 { cmsSigBToA2Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[6]},
5618 // Allow corbis and its broken XYZ type
5619 { cmsSigRedColorantTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, DecideXYZtype
}, &SupportedTags
[7]},
5620 { cmsSigGreenColorantTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, DecideXYZtype
}, &SupportedTags
[8]},
5621 { cmsSigBlueColorantTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, DecideXYZtype
}, &SupportedTags
[9]},
5623 { cmsSigRedTRCTag
, { 1, 3, { cmsSigCurveType
, cmsSigParametricCurveType
, cmsMonacoBrokenCurveType
}, DecideCurveType
}, &SupportedTags
[10]},
5624 { cmsSigGreenTRCTag
, { 1, 3, { cmsSigCurveType
, cmsSigParametricCurveType
, cmsMonacoBrokenCurveType
}, DecideCurveType
}, &SupportedTags
[11]},
5625 { cmsSigBlueTRCTag
, { 1, 3, { cmsSigCurveType
, cmsSigParametricCurveType
, cmsMonacoBrokenCurveType
}, DecideCurveType
}, &SupportedTags
[12]},
5627 { cmsSigCalibrationDateTimeTag
, { 1, 1, { cmsSigDateTimeType
}, NULL
}, &SupportedTags
[13]},
5628 { cmsSigCharTargetTag
, { 1, 1, { cmsSigTextType
}, NULL
}, &SupportedTags
[14]},
5630 { cmsSigChromaticAdaptationTag
, { 9, 1, { cmsSigS15Fixed16ArrayType
}, NULL
}, &SupportedTags
[15]},
5631 { cmsSigChromaticityTag
, { 1, 1, { cmsSigChromaticityType
}, NULL
}, &SupportedTags
[16]},
5632 { cmsSigColorantOrderTag
, { 1, 1, { cmsSigColorantOrderType
}, NULL
}, &SupportedTags
[17]},
5633 { cmsSigColorantTableTag
, { 1, 1, { cmsSigColorantTableType
}, NULL
}, &SupportedTags
[18]},
5634 { cmsSigColorantTableOutTag
, { 1, 1, { cmsSigColorantTableType
}, NULL
}, &SupportedTags
[19]},
5636 { cmsSigCopyrightTag
, { 1, 3, { cmsSigTextType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextDescriptionType
}, DecideTextType
}, &SupportedTags
[20]},
5637 { cmsSigDateTimeTag
, { 1, 1, { cmsSigDateTimeType
}, NULL
}, &SupportedTags
[21]},
5639 { cmsSigDeviceMfgDescTag
, { 1, 3, { cmsSigTextDescriptionType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextType
}, DecideTextDescType
}, &SupportedTags
[22]},
5640 { cmsSigDeviceModelDescTag
, { 1, 3, { cmsSigTextDescriptionType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextType
}, DecideTextDescType
}, &SupportedTags
[23]},
5642 { cmsSigGamutTag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[24]},
5644 { cmsSigGrayTRCTag
, { 1, 2, { cmsSigCurveType
, cmsSigParametricCurveType
}, DecideCurveType
}, &SupportedTags
[25]},
5645 { cmsSigLuminanceTag
, { 1, 1, { cmsSigXYZType
}, NULL
}, &SupportedTags
[26]},
5647 { cmsSigMediaBlackPointTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, NULL
}, &SupportedTags
[27]},
5648 { cmsSigMediaWhitePointTag
, { 1, 2, { cmsSigXYZType
, cmsCorbisBrokenXYZtype
}, NULL
}, &SupportedTags
[28]},
5650 { cmsSigNamedColor2Tag
, { 1, 1, { cmsSigNamedColor2Type
}, NULL
}, &SupportedTags
[29]},
5652 { cmsSigPreview0Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[30]},
5653 { cmsSigPreview1Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[31]},
5654 { cmsSigPreview2Tag
, { 1, 3, { cmsSigLut16Type
, cmsSigLutBtoAType
, cmsSigLut8Type
}, DecideLUTtypeB2A
}, &SupportedTags
[32]},
5656 { cmsSigProfileDescriptionTag
, { 1, 3, { cmsSigTextDescriptionType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextType
}, DecideTextDescType
}, &SupportedTags
[33]},
5657 { cmsSigProfileSequenceDescTag
, { 1, 1, { cmsSigProfileSequenceDescType
}, NULL
}, &SupportedTags
[34]},
5658 { cmsSigTechnologyTag
, { 1, 1, { cmsSigSignatureType
}, NULL
}, &SupportedTags
[35]},
5660 { cmsSigColorimetricIntentImageStateTag
, { 1, 1, { cmsSigSignatureType
}, NULL
}, &SupportedTags
[36]},
5661 { cmsSigPerceptualRenderingIntentGamutTag
, { 1, 1, { cmsSigSignatureType
}, NULL
}, &SupportedTags
[37]},
5662 { cmsSigSaturationRenderingIntentGamutTag
, { 1, 1, { cmsSigSignatureType
}, NULL
}, &SupportedTags
[38]},
5664 { cmsSigMeasurementTag
, { 1, 1, { cmsSigMeasurementType
}, NULL
}, &SupportedTags
[39]},
5666 { cmsSigPs2CRD0Tag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[40]},
5667 { cmsSigPs2CRD1Tag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[41]},
5668 { cmsSigPs2CRD2Tag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[42]},
5669 { cmsSigPs2CRD3Tag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[43]},
5670 { cmsSigPs2CSATag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[44]},
5671 { cmsSigPs2RenderingIntentTag
, { 1, 1, { cmsSigDataType
}, NULL
}, &SupportedTags
[45]},
5673 { cmsSigViewingCondDescTag
, { 1, 3, { cmsSigTextDescriptionType
, cmsSigMultiLocalizedUnicodeType
, cmsSigTextType
}, DecideTextDescType
}, &SupportedTags
[46]},
5675 { cmsSigUcrBgTag
, { 1, 1, { cmsSigUcrBgType
}, NULL
}, &SupportedTags
[47]},
5676 { cmsSigCrdInfoTag
, { 1, 1, { cmsSigCrdInfoType
}, NULL
}, &SupportedTags
[48]},
5678 { cmsSigDToB0Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[49]},
5679 { cmsSigDToB1Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[50]},
5680 { cmsSigDToB2Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[51]},
5681 { cmsSigDToB3Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[52]},
5682 { cmsSigBToD0Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[53]},
5683 { cmsSigBToD1Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[54]},
5684 { cmsSigBToD2Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[55]},
5685 { cmsSigBToD3Tag
, { 1, 1, { cmsSigMultiProcessElementType
}, NULL
}, &SupportedTags
[56]},
5687 { cmsSigScreeningDescTag
, { 1, 1, { cmsSigTextDescriptionType
}, NULL
}, &SupportedTags
[57]},
5688 { cmsSigViewingConditionsTag
, { 1, 1, { cmsSigViewingConditionsType
}, NULL
}, &SupportedTags
[58]},
5690 { cmsSigScreeningTag
, { 1, 1, { cmsSigScreeningType
}, NULL
}, &SupportedTags
[59]},
5691 { cmsSigVcgtTag
, { 1, 1, { cmsSigVcgtType
}, NULL
}, &SupportedTags
[60]},
5692 { cmsSigMetaTag
, { 1, 1, { cmsSigDictType
}, NULL
}, &SupportedTags
[61]},
5693 { cmsSigProfileSequenceIdTag
, { 1, 1, { cmsSigProfileSequenceIdType
}, NULL
}, &SupportedTags
[62]},
5695 { cmsSigProfileDescriptionMLTag
,{ 1, 1, { cmsSigMultiLocalizedUnicodeType
}, NULL
}, &SupportedTags
[63]},
5696 { cmsSigcicpTag
, { 1, 1, { cmsSigcicpType
}, NULL
}, &SupportedTags
[64]},
5698 { cmsSigArgyllArtsTag
, { 9, 1, { cmsSigS15Fixed16ArrayType
}, NULL
}, NULL
}
5704 ======================= =========================================
5705 cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
5706 cmsSigNamedColorTag ==> Deprecated
5707 cmsSigDataTag ==> Ancient, unused
5708 cmsSigDeviceSettingsTag ==> Deprecated, useless
5712 _cmsTagPluginChunkType _cmsTagPluginChunk
= { NULL
};
5715 // Duplicates the zone of memory used by the plug-in in the new context
5717 void DupTagList(struct _cmsContext_struct
* ctx
,
5718 const struct _cmsContext_struct
* src
)
5720 _cmsTagPluginChunkType newHead
= { NULL
};
5721 _cmsTagLinkedList
* entry
;
5722 _cmsTagLinkedList
* Anterior
= NULL
;
5723 _cmsTagPluginChunkType
* head
= (_cmsTagPluginChunkType
*) src
->chunks
[TagPlugin
];
5725 // Walk the list copying all nodes
5726 for (entry
= head
->Tag
;
5728 entry
= entry
->Next
) {
5730 _cmsTagLinkedList
*newEntry
= ( _cmsTagLinkedList
*) _cmsSubAllocDup(ctx
->MemPool
, entry
, sizeof(_cmsTagLinkedList
));
5732 if (newEntry
== NULL
)
5735 // We want to keep the linked list order, so this is a little bit tricky
5736 newEntry
-> Next
= NULL
;
5738 Anterior
-> Next
= newEntry
;
5740 Anterior
= newEntry
;
5742 if (newHead
.Tag
== NULL
)
5743 newHead
.Tag
= newEntry
;
5746 ctx
->chunks
[TagPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, &newHead
, sizeof(_cmsTagPluginChunkType
));
5749 void _cmsAllocTagPluginChunk(struct _cmsContext_struct
* ctx
,
5750 const struct _cmsContext_struct
* src
)
5754 DupTagList(ctx
, src
);
5757 static _cmsTagPluginChunkType TagPluginChunk
= { NULL
};
5758 ctx
->chunks
[TagPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, &TagPluginChunk
, sizeof(_cmsTagPluginChunkType
));
5763 cmsBool
_cmsRegisterTagPlugin(cmsContext id
, cmsPluginBase
* Data
)
5765 cmsPluginTag
* Plugin
= (cmsPluginTag
*) Data
;
5766 _cmsTagLinkedList
*pt
;
5767 _cmsTagPluginChunkType
* TagPluginChunk
= ( _cmsTagPluginChunkType
*) _cmsContextGetClientChunk(id
, TagPlugin
);
5771 TagPluginChunk
->Tag
= NULL
;
5775 pt
= (_cmsTagLinkedList
*) _cmsPluginMalloc(id
, sizeof(_cmsTagLinkedList
));
5776 if (pt
== NULL
) return FALSE
;
5778 pt
->Signature
= Plugin
->Signature
;
5779 pt
->Descriptor
= Plugin
->Descriptor
;
5780 pt
->Next
= TagPluginChunk
->Tag
;
5782 TagPluginChunk
->Tag
= pt
;
5787 // Return a descriptor for a given tag or NULL
5788 cmsTagDescriptor
* _cmsGetTagDescriptor(cmsContext ContextID
, cmsTagSignature sig
)
5790 _cmsTagLinkedList
* pt
;
5791 _cmsTagPluginChunkType
* TagPluginChunk
= ( _cmsTagPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, TagPlugin
);
5793 for (pt
= TagPluginChunk
->Tag
;
5797 if (sig
== pt
-> Signature
) return &pt
->Descriptor
;
5800 for (pt
= SupportedTags
;
5804 if (sig
== pt
-> Signature
) return &pt
->Descriptor
;