311 //The XYZType contains an array of three encoded values for the XYZ tristimulus
312 //values. Tristimulus values must be non-negative. The signed encoding allows for
313 //implementation optimizations by minimizing the number of fixed formats.
314
315
316 static
317 void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
318 {
319 cmsCIEXYZ* xyz;
320
321 *nItems = 0;
322 xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ));
323 if (xyz == NULL) return NULL;
324
325 if (!_cmsReadXYZNumber(io, xyz)) {
326 _cmsFree(self ->ContextID, xyz);
327 return NULL;
328 }
329
330 *nItems = 1;
331 return (void*) xyz;
332
333 cmsUNUSED_PARAMETER(SizeOfTag);
334 }
335
336 static
337 cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
338 {
339 return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr);
340
341 cmsUNUSED_PARAMETER(nItems);
342 cmsUNUSED_PARAMETER(self);
343 }
344
345 static
346 void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
347 {
348 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ));
349
350 cmsUNUSED_PARAMETER(n);
351 }
352
353 static
354 void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr)
355 {
356 _cmsFree(self ->ContextID, Ptr);
357 }
358
359
360 static
361 cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data)
362 {
363 return cmsSigXYZType;
364
365 cmsUNUSED_PARAMETER(ICCVersion);
366 cmsUNUSED_PARAMETER(Data);
367 }
368
369
370 // ********************************************************************************
371 // Type chromaticity. Only one value is allowed
372 // ********************************************************************************
373 // The chromaticity tag type provides basic chromaticity data and type of
374 // phosphors or colorants of a monitor to applications and utilities.
375
376 static
377 void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
378 {
379 cmsCIExyYTRIPLE* chrm;
380 cmsUInt16Number nChans, Table;
381
382 *nItems = 0;
383 chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE));
384 if (chrm == NULL) return NULL;
385
386 if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
399 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error;
400 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error;
401
402 chrm ->Red.Y = 1.0;
403
404 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error;
405 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error;
406
407 chrm ->Green.Y = 1.0;
408
409 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error;
410 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error;
411
412 chrm ->Blue.Y = 1.0;
413
414 *nItems = 1;
415 return (void*) chrm;
416
417 Error:
418 _cmsFree(self ->ContextID, (void*) chrm);
419 return NULL;
420
421 cmsUNUSED_PARAMETER(SizeOfTag);
422 }
423
424 static
425 cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io)
426 {
427 if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE;
428 if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE;
429
430 return TRUE;
431 }
432
433 static
434 cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
435 {
436 cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr;
437
438 if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels
439 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table
440
441 if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE;
442 if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE;
443 if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE;
444
445 return TRUE;
446
447 cmsUNUSED_PARAMETER(nItems);
448 cmsUNUSED_PARAMETER(self);
449 }
450
451 static
452 void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
453 {
454 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE));
455
456 cmsUNUSED_PARAMETER(n);
457 }
458
459 static
460 void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr)
461 {
462 _cmsFree(self ->ContextID, Ptr);
463 }
464
465
466 // ********************************************************************************
467 // Type cmsSigColorantOrderType
468 // ********************************************************************************
469
470 // This is an optional tag which specifies the laydown order in which colorants will
471 // be printed on an n-colorant device. The laydown order may be the same as the
472 // channel generation order listed in the colorantTableTag or the channel order of a
473 // colour space such as CMYK, in which case this tag is not needed. When this is not
474 // the case (for example, ink-towers sometimes use the order KCMY), this tag may be
475 // used to specify the laydown order of the colorants.
476
481 cmsUInt8Number* ColorantOrder;
482 cmsUInt32Number Count;
483
484 *nItems = 0;
485 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
486 if (Count > cmsMAXCHANNELS) return NULL;
487
488 ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number));
489 if (ColorantOrder == NULL) return NULL;
490
491 // We use FF as end marker
492 memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
493
494 if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) {
495
496 _cmsFree(self ->ContextID, (void*) ColorantOrder);
497 return NULL;
498 }
499
500 *nItems = 1;
501 return (void*) ColorantOrder;
502
503 cmsUNUSED_PARAMETER(SizeOfTag);
504 }
505
506 static
507 cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
508 {
509 cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr;
510 cmsUInt32Number i, sz, Count;
511
512 // Get the length
513 for (Count=i=0; i < cmsMAXCHANNELS; i++) {
514 if (ColorantOrder[i] != 0xFF) Count++;
515 }
516
517 if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
518
519 sz = Count * sizeof(cmsUInt8Number);
520 if (!io -> Write(io, sz, ColorantOrder)) return FALSE;
521
522 return TRUE;
523
524 cmsUNUSED_PARAMETER(nItems);
525 cmsUNUSED_PARAMETER(self);
526 }
527
528 static
529 void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
530 {
531 return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
532
533 cmsUNUSED_PARAMETER(n);
534 }
535
536
537 static
538 void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr)
539 {
540 _cmsFree(self ->ContextID, Ptr);
541 }
542
543 // ********************************************************************************
544 // Type cmsSigS15Fixed16ArrayType
545 // ********************************************************************************
546 // This type represents an array of generic 4-byte/32-bit fixed point quantity.
547 // The number of values is determined from the size of the tag.
548
549 static
550 void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
551 {
552 cmsFloat64Number* array_double;
553 cmsUInt32Number i, n;
564 _cmsFree(self ->ContextID, array_double);
565 return NULL;
566 }
567 }
568
569 *nItems = n;
570 return (void*) array_double;
571 }
572
573 static
574 cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
575 {
576 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
577 cmsUInt32Number i;
578
579 for (i=0; i < nItems; i++) {
580
581 if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE;
582 }
583
584 return TRUE;
585
586 cmsUNUSED_PARAMETER(self);
587 }
588
589 static
590 void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
591 {
592 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
593 }
594
595
596 static
597 void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
598 {
599 _cmsFree(self ->ContextID, Ptr);
600 }
601
602 // ********************************************************************************
603 // Type cmsSigU16Fixed16ArrayType
604 // ********************************************************************************
605 // This type represents an array of generic 4-byte/32-bit quantity.
606 // The number of values is determined from the size of the tag.
629 array_double[i] = (cmsFloat64Number) (v / 65536.0);
630 }
631
632 *nItems = n;
633 return (void*) array_double;
634 }
635
636 static
637 cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
638 {
639 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
640 cmsUInt32Number i;
641
642 for (i=0; i < nItems; i++) {
643
644 cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5);
645
646 if (!_cmsWriteUInt32Number(io, v)) return FALSE;
647 }
648
649 return TRUE;
650
651 cmsUNUSED_PARAMETER(self);
652 }
653
654
655 static
656 void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
657 {
658 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
659 }
660
661 static
662 void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
663 {
664 _cmsFree(self ->ContextID, Ptr);
665 }
666
667 // ********************************************************************************
668 // Type cmsSigSignatureType
669 // ********************************************************************************
670 //
671 // The signatureType contains a four-byte sequence, Sequences of less than four
672 // characters are padded at the end with spaces, 20h.
673 // Typically this type is used for registered tags that can be displayed on many
674 // development systems as a sequence of four characters.
675
676 static
677 void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
678 {
679 cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature));
680 if (SigPtr == NULL) return NULL;
681
682 if (!_cmsReadUInt32Number(io, SigPtr)) return NULL;
683 *nItems = 1;
684
685 return SigPtr;
686
687 cmsUNUSED_PARAMETER(SizeOfTag);
688 }
689
690 static
691 cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
692 {
693 cmsSignature* SigPtr = (cmsSignature*) Ptr;
694
695 return _cmsWriteUInt32Number(io, *SigPtr);
696
697 cmsUNUSED_PARAMETER(nItems);
698 cmsUNUSED_PARAMETER(self);
699 }
700
701 static
702 void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
703 {
704 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature));
705 }
706
707 static
708 void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr)
709 {
710 _cmsFree(self ->ContextID, Ptr);
711 }
712
713
714 // ********************************************************************************
715 // Type cmsSigTextType
716 // ********************************************************************************
717 //
718 // The textType is a simple text structure that contains a 7-bit ASCII text string.
764 {
765 cmsMLU* mlu = (cmsMLU*) Ptr;
766 cmsUInt32Number size;
767 cmsBool rc;
768 char* Text;
769
770 // Get the size of the string. Note there is an extra "\0" at the end
771 size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
772 if (size == 0) return FALSE; // Cannot be zero!
773
774 // Create memory
775 Text = (char*) _cmsMalloc(self ->ContextID, size);
776 if (Text == NULL) return FALSE;
777
778 cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
779
780 // Write it, including separator
781 rc = io ->Write(io, size, Text);
782
783 _cmsFree(self ->ContextID, Text);
784 return rc;
785
786 cmsUNUSED_PARAMETER(nItems);
787 }
788
789 static
790 void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
791 {
792 return (void*) cmsMLUdup((cmsMLU*) Ptr);
793
794 cmsUNUSED_PARAMETER(n);
795 cmsUNUSED_PARAMETER(self);
796 }
797
798
799 static
800 void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr)
801 {
802 cmsMLU* mlu = (cmsMLU*) Ptr;
803 cmsMLUfree(mlu);
804 return;
805
806 cmsUNUSED_PARAMETER(self);
807 }
808
809 static
810 cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data)
811 {
812 if (ICCVersion >= 4.0)
813 return cmsSigMultiLocalizedUnicodeType;
814
815 return cmsSigTextType;
816
817 cmsUNUSED_PARAMETER(Data);
818 }
819
820
821 // ********************************************************************************
822 // Type cmsSigDataType
823 // ********************************************************************************
824
825 // General purpose data type
826 static
827 void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
828 {
829 cmsICCData* BinData;
830 cmsUInt32Number LenOfData;
831
832 *nItems = 0;
833
834 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
835
836 LenOfData = SizeOfTag - sizeof(cmsUInt32Number);
837 if (LenOfData > INT_MAX) return NULL;
845 return NULL;
846 }
847
848 if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) {
849
850 _cmsFree(self ->ContextID, BinData);
851 return NULL;
852 }
853
854 *nItems = 1;
855
856 return (void*) BinData;
857 }
858
859
860 static
861 cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
862 {
863 cmsICCData* BinData = (cmsICCData*) Ptr;
864
865 if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE;
866
867 return io ->Write(io, BinData ->len, BinData ->data);
868
869 cmsUNUSED_PARAMETER(nItems);
870 cmsUNUSED_PARAMETER(self);
871 }
872
873
874 static
875 void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
876 {
877 cmsICCData* BinData = (cmsICCData*) Ptr;
878
879 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1);
880
881 cmsUNUSED_PARAMETER(n);
882 }
883
884 static
885 void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr)
886 {
887 _cmsFree(self ->ContextID, Ptr);
888 }
889
890 // ********************************************************************************
891 // Type cmsSigTextDescriptionType
892 // ********************************************************************************
893
894 static
895 void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
896 {
897 char* Text = NULL;
898 cmsMLU* mlu = NULL;
899 cmsUInt32Number AsciiCount;
900 cmsUInt32Number i, UnicodeCode, UnicodeCount;
901 cmsUInt16Number ScriptCodeCode, Dummy;
1040 // takes 70 bytes, so we need 2 extra bytes to do the alignment
1041
1042 if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error;
1043
1044 // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
1045 if (!_cmsWriteWCharArray(io, len, Wide)) goto Error;
1046 if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error;
1047
1048 // ScriptCode Code & count (unused)
1049 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
1050 if (!_cmsWriteUInt8Number(io, 0)) goto Error;
1051
1052 if (!io ->Write(io, 67, Filler)) goto Error;
1053
1054 rc = TRUE;
1055
1056 Error:
1057 if (Text) _cmsFree(self ->ContextID, Text);
1058 if (Wide) _cmsFree(self ->ContextID, Wide);
1059
1060 return rc;
1061
1062 cmsUNUSED_PARAMETER(nItems);
1063 }
1064
1065
1066 static
1067 void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1068 {
1069 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1070
1071 cmsUNUSED_PARAMETER(n);
1072 cmsUNUSED_PARAMETER(self);
1073 }
1074
1075 static
1076 void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr)
1077 {
1078 cmsMLU* mlu = (cmsMLU*) Ptr;
1079
1080 cmsMLUfree(mlu);
1081 return;
1082
1083 cmsUNUSED_PARAMETER(self);
1084 }
1085
1086
1087 static
1088 cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data)
1089 {
1090 if (ICCVersion >= 4.0)
1091 return cmsSigMultiLocalizedUnicodeType;
1092
1093 return cmsSigTextDescriptionType;
1094
1095 cmsUNUSED_PARAMETER(Data);
1096 }
1097
1098
1099 // ********************************************************************************
1100 // Type cmsSigCurveType
1101 // ********************************************************************************
1102
1103 static
1104 void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1105 {
1106 cmsUInt32Number Count;
1107 cmsToneCurve* NewGamma;
1108
1109 *nItems = 0;
1110 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1111
1112 switch (Count) {
1113
1114 case 0: // Linear.
1115 {
1116 cmsFloat64Number SingleGamma = 1.0;
1117
1118 NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1119 if (!NewGamma) return NULL;
1120 *nItems = 1;
1121 return NewGamma;
1122 }
1123
1124 case 1: // Specified as the exponent of gamma function
1125 {
1126 cmsUInt16Number SingleGammaFixed;
1127 cmsFloat64Number SingleGamma;
1128
1129 if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL;
1130 SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed);
1131
1132 *nItems = 1;
1133 return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1134 }
1135
1136 default: // Curve
1137
1138 if (Count > 0x7FFF)
1139 return NULL; // This is to prevent bad guys for doing bad things
1140
1141 NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
1142 if (!NewGamma) return NULL;
1143
1144 if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL;
1145
1146 *nItems = 1;
1147 return NewGamma;
1148 }
1149
1150 cmsUNUSED_PARAMETER(SizeOfTag);
1151 }
1152
1153
1154 static
1155 cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1156 {
1157 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1158
1159 if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) {
1160
1161 // Single gamma, preserve number
1162 cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]);
1163
1164 if (!_cmsWriteUInt32Number(io, 1)) return FALSE;
1165 if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE;
1166 return TRUE;
1167
1168 }
1169
1170 if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE;
1171 return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16);
1172
1173 cmsUNUSED_PARAMETER(nItems);
1174 cmsUNUSED_PARAMETER(self);
1175 }
1176
1177
1178 static
1179 void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1180 {
1181 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1182
1183 cmsUNUSED_PARAMETER(n);
1184 cmsUNUSED_PARAMETER(self);
1185 }
1186
1187 static
1188 void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1189 {
1190 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1191
1192 cmsFreeToneCurve(gamma);
1193 return;
1194
1195 cmsUNUSED_PARAMETER(self);
1196 }
1197
1198
1199 // ********************************************************************************
1200 // Type cmsSigParametricCurveType
1201 // ********************************************************************************
1202
1203
1204 // Decide which curve type to use on writting
1205 static
1206 cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data)
1207 {
1208 cmsToneCurve* Curve = (cmsToneCurve*) Data;
1209
1210 if (ICCVersion < 4.0) return cmsSigCurveType;
1211 if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric
1212 if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves
1213 if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves
1214
1215 return cmsSigParametricCurveType;
1216 }
1217
1218 static
1219 void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1220 {
1221 static const int ParamsByType[] = { 1, 3, 4, 5, 7 };
1222 cmsFloat64Number Params[10];
1223 cmsUInt16Number Type;
1224 int i, n;
1225 cmsToneCurve* NewGamma;
1226
1227 if (!_cmsReadUInt16Number(io, &Type)) return NULL;
1228 if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved
1229
1230 if (Type > 4) {
1231
1232 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type);
1233 return NULL;
1234 }
1235
1236 memset(Params, 0, sizeof(Params));
1237 n = ParamsByType[Type];
1238
1239 for (i=0; i < n; i++) {
1240
1241 if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL;
1242 }
1243
1244 NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params);
1245
1246 *nItems = 1;
1247 return NewGamma;
1248
1249 cmsUNUSED_PARAMETER(SizeOfTag);
1250 }
1251
1252
1253 static
1254 cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1255 {
1256 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1257 int i, nParams, typen;
1258 static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
1259
1260 typen = Curve -> Segments[0].Type;
1261
1262 if (Curve ->nSegments > 1 || typen < 1) {
1263
1264 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written");
1265 return FALSE;
1266 }
1267
1268 if (typen > 5) {
1269 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve");
1270 return FALSE;
1271 }
1272
1273 nParams = ParamsByType[typen];
1274
1275 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE;
1276 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved
1277
1278 for (i=0; i < nParams; i++) {
1279
1280 if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE;
1281 }
1282
1283 return TRUE;
1284
1285 cmsUNUSED_PARAMETER(nItems);
1286 }
1287
1288 static
1289 void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1290 {
1291 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1292
1293 cmsUNUSED_PARAMETER(n);
1294 cmsUNUSED_PARAMETER(self);
1295 }
1296
1297 static
1298 void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1299 {
1300 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1301
1302 cmsFreeToneCurve(gamma);
1303 return;
1304
1305 cmsUNUSED_PARAMETER(self);
1306 }
1307
1308
1309 // ********************************************************************************
1310 // Type cmsSigDateTimeType
1311 // ********************************************************************************
1312
1313 // A 12-byte value representation of the time and date, where the byte usage is assigned
1314 // as specified in table 1. The actual values are encoded as 16-bit unsigned integers
1315 // (uInt16Number - see 5.1.6).
1316 //
1317 // All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
1318 // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
1319 // time to UTC when setting these values. Programmes that display these values may show
1320 // the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
1321 // display both UTC and local versions of the dateTimeNumber.
1322
1323 static
1324 void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1325 {
1326 cmsDateTimeNumber timestamp;
1327 struct tm * NewDateTime;
1328
1329 *nItems = 0;
1330 NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm));
1331 if (NewDateTime == NULL) return NULL;
1332
1333 if (io->Read(io, ×tamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL;
1334
1335 _cmsDecodeDateTimeNumber(×tamp, NewDateTime);
1336
1337 *nItems = 1;
1338 return NewDateTime;
1339
1340 cmsUNUSED_PARAMETER(SizeOfTag);
1341 }
1342
1343
1344 static
1345 cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1346 {
1347 struct tm * DateTime = (struct tm*) Ptr;
1348 cmsDateTimeNumber timestamp;
1349
1350 _cmsEncodeDateTimeNumber(×tamp, DateTime);
1351 if (!io ->Write(io, sizeof(cmsDateTimeNumber), ×tamp)) return FALSE;
1352
1353 return TRUE;
1354
1355 cmsUNUSED_PARAMETER(nItems);
1356 cmsUNUSED_PARAMETER(self);
1357 }
1358
1359 static
1360 void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1361 {
1362 return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm));
1363
1364 cmsUNUSED_PARAMETER(n);
1365 }
1366
1367 static
1368 void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr)
1369 {
1370 _cmsFree(self ->ContextID, Ptr);
1371 }
1372
1373
1374
1375 // ********************************************************************************
1376 // Type icMeasurementType
1377 // ********************************************************************************
1378
1379 /*
1380 The measurementType information refers only to the internal profile data and is
1381 meant to provide profile makers an alternative to the default measurement
1382 specifications.
1383 */
1384
1385 static
1386 void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1387 {
1388 cmsICCMeasurementConditions mc;
1389
1390
1391 memset(&mc, 0, sizeof(mc));
1392
1393 if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
1394 if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL;
1395 if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
1396 if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL;
1397 if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL;
1398
1399 *nItems = 1;
1400 return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions));
1401
1402 cmsUNUSED_PARAMETER(SizeOfTag);
1403 }
1404
1405
1406 static
1407 cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1408 {
1409 cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr;
1410
1411 if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE;
1412 if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE;
1413 if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE;
1414 if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE;
1415 if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE;
1416
1417 return TRUE;
1418
1419 cmsUNUSED_PARAMETER(nItems);
1420 cmsUNUSED_PARAMETER(self);
1421 }
1422
1423 static
1424 void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1425 {
1426 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions));
1427
1428 cmsUNUSED_PARAMETER(n);
1429 }
1430
1431 static
1432 void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr)
1433 {
1434 _cmsFree(self ->ContextID, Ptr);
1435 }
1436
1437
1438 // ********************************************************************************
1439 // Type cmsSigMultiLocalizedUnicodeType
1440 // ********************************************************************************
1441 //
1442 // Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
1443 // Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
1444 // taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
1445 //
1446
1447 static
1448 void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1517 mlu ->MemPool = Block;
1518 mlu ->PoolSize = SizeOfTag;
1519 mlu ->PoolUsed = SizeOfTag;
1520
1521 *nItems = 1;
1522 return (void*) mlu;
1523
1524 Error:
1525 if (mlu) cmsMLUfree(mlu);
1526 return NULL;
1527 }
1528
1529 static
1530 cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1531 {
1532 cmsMLU* mlu =(cmsMLU*) Ptr;
1533 cmsUInt32Number HeaderSize;
1534 cmsUInt32Number Len, Offset;
1535 int i;
1536
1537 if (Ptr == NULL) {
1538
1539 // Empty placeholder
1540 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
1541 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1542 return TRUE;
1543 }
1544
1545 if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
1546 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1547
1548 HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
1549
1550 for (i=0; i < mlu ->UsedEntries; i++) {
1551
1552 Len = mlu ->Entries[i].Len;
1553 Offset = mlu ->Entries[i].StrW;
1554
1555 Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
1556 Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8;
1557
1558 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE;
1559 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE;
1560 if (!_cmsWriteUInt32Number(io, Len)) return FALSE;
1561 if (!_cmsWriteUInt32Number(io, Offset)) return FALSE;
1562 }
1563
1564 if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE;
1565
1566 return TRUE;
1567
1568 cmsUNUSED_PARAMETER(nItems);
1569 cmsUNUSED_PARAMETER(self);
1570 }
1571
1572
1573 static
1574 void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1575 {
1576 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1577
1578 cmsUNUSED_PARAMETER(n);
1579 cmsUNUSED_PARAMETER(self);
1580 }
1581
1582 static
1583 void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr)
1584 {
1585 cmsMLUfree((cmsMLU*) Ptr);
1586 return;
1587
1588 cmsUNUSED_PARAMETER(self);
1589 }
1590
1591
1592 // ********************************************************************************
1593 // Type cmsSigLut8Type
1594 // ********************************************************************************
1595
1596 // Decide which LUT type to use on writting
1597 static
1598 cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data)
1599 {
1600 cmsPipeline* Lut = (cmsPipeline*) Data;
1601
1602 if (ICCVersion < 4.0) {
1603 if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1604 return cmsSigLut16Type;
1605 }
1606 else {
1607 return cmsSigLutAtoBType;
1608 }
1833
1834 *PtrW++ = FROM_8_TO_16(Temp[i]);
1835 }
1836 _cmsFree(self ->ContextID, Temp);
1837 Temp = NULL;
1838
1839 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T)))
1840 goto Error;
1841 _cmsFree(self ->ContextID, T);
1842 }
1843
1844
1845 // Get output tables
1846 if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error;
1847
1848 *nItems = 1;
1849 return NewLUT;
1850
1851 Error:
1852 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
1853 return NULL;
1854
1855 cmsUNUSED_PARAMETER(SizeOfTag);
1856 }
1857
1858 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1859 static
1860 cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1861 {
1862 cmsUInt32Number j, nTabSize;
1863 cmsUInt8Number val;
1864 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
1865 cmsStage* mpe;
1866 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
1867 _cmsStageMatrixData* MatMPE = NULL;
1868 _cmsStageCLutData* clut = NULL;
1869 int clutPoints;
1870
1871 // Disassemble the LUT into components.
1872 mpe = NewLUT -> Elements;
1873 if (mpe ->Type == cmsSigMatrixElemType) {
1874
1875 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
1936 }
1937
1938 // The prelinearization table
1939 if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
1940
1941 nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
1942 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
1943 if (nTabSize > 0) {
1944
1945 // The 3D CLUT.
1946 if (clut != NULL) {
1947
1948 for (j=0; j < nTabSize; j++) {
1949
1950 val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
1951 if (!_cmsWriteUInt8Number(io, val)) return FALSE;
1952 }
1953 }
1954 }
1955
1956 // The postlinearization table
1957 if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE;
1958
1959 return TRUE;
1960
1961 cmsUNUSED_PARAMETER(nItems);
1962 }
1963
1964
1965 static
1966 void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1967 {
1968 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
1969
1970 cmsUNUSED_PARAMETER(n);
1971 cmsUNUSED_PARAMETER(self);
1972 }
1973
1974 static
1975 void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
1976 {
1977 cmsPipelineFree((cmsPipeline*) Ptr);
1978 return;
1979
1980 cmsUNUSED_PARAMETER(self);
1981 }
1982
1983 // ********************************************************************************
1984 // Type cmsSigLut16Type
1985 // ********************************************************************************
1986
1987 // Read 16 bit tables as gamma functions
1988 static
1989 cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries)
1990 {
1991 int i;
1992 cmsToneCurve* Tables[cmsMAXCHANNELS];
1993
1994 // Maybe an empty table? (this is a lcms extension)
1995 if (nEntries <= 0) return TRUE;
1996
1997 // Check for malicious profiles
1998 if (nEntries < 2) return FALSE;
1999 if (nChannels > cmsMAXCHANNELS) return FALSE;
2000
2022 Error:
2023 for (i=0; i < nChannels; i++) {
2024 if (Tables[i]) cmsFreeToneCurve(Tables[i]);
2025 }
2026
2027 return FALSE;
2028 }
2029
2030 static
2031 cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables)
2032 {
2033 int j;
2034 cmsUInt32Number i;
2035 cmsUInt16Number val;
2036 int nEntries;
2037
2038 _cmsAssert(Tables != NULL);
2039
2040 nEntries = Tables->TheCurves[0]->nEntries;
2041
2042 for (i=0; i < Tables ->nCurves; i++) {
2043
2044 for (j=0; j < nEntries; j++) {
2045
2046 val = Tables->TheCurves[i]->Table16[j];
2047 if (!_cmsWriteUInt16Number(io, val)) return FALSE;
2048 }
2049 }
2050 return TRUE;
2051
2052 cmsUNUSED_PARAMETER(ContextID);
2053 }
2054
2055 static
2056 void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2057 {
2058 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
2059 cmsPipeline* NewLUT = NULL;
2060 cmsUInt32Number nTabSize;
2061 cmsFloat64Number Matrix[3*3];
2062 cmsUInt16Number InputEntries, OutputEntries;
2063
2064 *nItems = 0;
2065
2066 if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL;
2067 if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL;
2068 if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum
2069
2070 // Padding
2071 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2072
2120 _cmsFree(self ->ContextID, T);
2121 goto Error;
2122 }
2123
2124 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) {
2125 _cmsFree(self ->ContextID, T);
2126 goto Error;
2127 }
2128 _cmsFree(self ->ContextID, T);
2129 }
2130
2131
2132 // Get output tables
2133 if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error;
2134
2135 *nItems = 1;
2136 return NewLUT;
2137
2138 Error:
2139 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
2140 return NULL;
2141
2142 cmsUNUSED_PARAMETER(SizeOfTag);
2143 }
2144
2145 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
2146 // Some empty defaults are created for missing parts
2147
2148 static
2149 cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2150 {
2151 cmsUInt32Number nTabSize;
2152 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
2153 cmsStage* mpe;
2154 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
2155 _cmsStageMatrixData* MatMPE = NULL;
2156 _cmsStageCLutData* clut = NULL;
2157 int i, InputChannels, OutputChannels, clutPoints;
2158
2159 // Disassemble the LUT into components.
2160 mpe = NewLUT -> Elements;
2161 if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
2162
2256 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
2257 if (nTabSize > 0) {
2258 // The 3D CLUT.
2259 if (clut != NULL) {
2260 if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
2261 }
2262 }
2263
2264 // The postlinearization table
2265 if (PostMPE != NULL) {
2266 if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE;
2267 }
2268 else {
2269 for (i=0; i < OutputChannels; i++) {
2270
2271 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2272 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
2273 }
2274 }
2275
2276 return TRUE;
2277
2278 cmsUNUSED_PARAMETER(nItems);
2279 }
2280
2281 static
2282 void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2283 {
2284 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2285
2286 cmsUNUSED_PARAMETER(n);
2287 cmsUNUSED_PARAMETER(self);
2288 }
2289
2290 static
2291 void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr)
2292 {
2293 cmsPipelineFree((cmsPipeline*) Ptr);
2294 return;
2295
2296 cmsUNUSED_PARAMETER(self);
2297 }
2298
2299
2300 // ********************************************************************************
2301 // Type cmsSigLutAToBType
2302 // ********************************************************************************
2303
2304
2305 // V4 stuff. Read matrix for LutAtoB and LutBtoA
2306
2307 static
2308 cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset)
2309 {
2310 cmsFloat64Number dMat[3*3];
2311 cmsFloat64Number dOff[3];
2312 cmsStage* Mat;
2313
2314 // Go to address
2315 if (!io -> Seek(io, Offset)) return NULL;
2316
2522
2523 if (offsetM != 0) {
2524 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan)))
2525 goto Error;
2526 }
2527
2528 if (offsetMat != 0) {
2529 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
2530 goto Error;
2531 }
2532
2533 if (offsetB != 0) {
2534 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
2535 goto Error;
2536 }
2537
2538 *nItems = 1;
2539 return NewLUT;
2540 Error:
2541 cmsPipelineFree(NewLUT);
2542 return NULL;
2543
2544 cmsUNUSED_PARAMETER(SizeOfTag);
2545 }
2546
2547 // Write a set of curves
2548 static
2549 cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
2550 {
2551 _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
2552
2553 // Write the Matrix
2554 if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE;
2555 if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE;
2556 if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE;
2557 if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE;
2558 if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE;
2559 if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE;
2560 if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE;
2561 if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE;
2562 if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE;
2563
2564 if (m ->Offset != NULL) {
2565
2566 if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE;
2567 if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE;
2568 if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE;
2569 }
2570 else {
2571 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2572 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2573 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2574
2575 }
2576
2577
2578 return TRUE;
2579
2580 cmsUNUSED_PARAMETER(self);
2581 }
2582
2583
2584 // Write a set of curves
2585 static
2586 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
2587 {
2588 cmsUInt32Number i, n;
2589 cmsTagTypeSignature CurrentType;
2590 cmsToneCurve** Curves;
2591
2592
2593 n = cmsStageOutputChannels(mpe);
2594 Curves = _cmsStageGetPtrToCurveSet(mpe);
2595
2596 for (i=0; i < n; i++) {
2597
2598 // If this is a table-based curve, use curve type even on V4
2599 CurrentType = Type;
2600
2751 }
2752
2753 if (B != NULL) {
2754
2755 offsetB = io ->Tell(io) - BaseOffset;
2756 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2757 }
2758
2759 CurrentPos = io ->Tell(io);
2760
2761 if (!io ->Seek(io, DirectoryPos)) return FALSE;
2762
2763 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2764 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2765 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2766 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2767 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2768
2769 if (!io ->Seek(io, CurrentPos)) return FALSE;
2770
2771 return TRUE;
2772
2773 cmsUNUSED_PARAMETER(nItems);
2774 }
2775
2776
2777 static
2778 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2779 {
2780 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2781
2782 cmsUNUSED_PARAMETER(n);
2783 cmsUNUSED_PARAMETER(self);
2784 }
2785
2786 static
2787 void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr)
2788 {
2789 cmsPipelineFree((cmsPipeline*) Ptr);
2790 return;
2791
2792 cmsUNUSED_PARAMETER(self);
2793 }
2794
2795
2796 // LutBToA type
2797
2798 static
2799 void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2800 {
2801 cmsUInt8Number inputChan; // Number of input channels
2802 cmsUInt8Number outputChan; // Number of output channels
2803 cmsUInt32Number BaseOffset; // Actual position in file
2804 cmsUInt32Number offsetB; // Offset to first "B" curve
2805 cmsUInt32Number offsetMat; // Offset to matrix
2806 cmsUInt32Number offsetM; // Offset to first "M" curve
2807 cmsUInt32Number offsetC; // Offset to CLUT
2808 cmsUInt32Number offsetA; // Offset to first "A" curve
2809 cmsPipeline* NewLUT = NULL;
2810
2811
2812 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2839
2840 if (offsetM != 0) {
2841 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan)))
2842 goto Error;
2843 }
2844
2845 if (offsetC != 0) {
2846 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
2847 goto Error;
2848 }
2849
2850 if (offsetA!= 0) {
2851 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan)))
2852 goto Error;
2853 }
2854
2855 *nItems = 1;
2856 return NewLUT;
2857 Error:
2858 cmsPipelineFree(NewLUT);
2859 return NULL;
2860
2861 cmsUNUSED_PARAMETER(SizeOfTag);
2862 }
2863
2864
2865 /*
2866 B
2867 B - Matrix - M
2868 B - CLUT - A
2869 B - Matrix - M - CLUT - A
2870 */
2871
2872 static
2873 cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2874 {
2875 cmsPipeline* Lut = (cmsPipeline*) Ptr;
2876 int inputChan, outputChan;
2877 cmsStage *A = NULL, *B = NULL, *M = NULL;
2878 cmsStage *Matrix = NULL;
2879 cmsStage *CLUT = NULL;
2880 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2881 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2930 }
2931
2932 if (B != NULL) {
2933
2934 offsetB = io ->Tell(io) - BaseOffset;
2935 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2936 }
2937
2938 CurrentPos = io ->Tell(io);
2939
2940 if (!io ->Seek(io, DirectoryPos)) return FALSE;
2941
2942 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2943 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2944 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2945 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2946 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2947
2948 if (!io ->Seek(io, CurrentPos)) return FALSE;
2949
2950 return TRUE;
2951
2952 cmsUNUSED_PARAMETER(nItems);
2953 }
2954
2955
2956
2957 static
2958 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2959 {
2960 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2961
2962 cmsUNUSED_PARAMETER(n);
2963 cmsUNUSED_PARAMETER(self);
2964 }
2965
2966 static
2967 void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr)
2968 {
2969 cmsPipelineFree((cmsPipeline*) Ptr);
2970 return;
2971
2972 cmsUNUSED_PARAMETER(self);
2973 }
2974
2975
2976
2977 // ********************************************************************************
2978 // Type cmsSigColorantTableType
2979 // ********************************************************************************
2980 /*
2981 The purpose of this tag is to identify the colorants used in the profile by a
2982 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
2983 value. The first colorant listed is the colorant of the first device channel of
2984 a lut tag. The second colorant listed is the colorant of the second device channel
2985 of a lut tag, and so on.
2986 */
2987
2988 static
2989 void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2990 {
2991 cmsUInt32Number i, Count;
2992 cmsNAMEDCOLORLIST* List;
3002 }
3003
3004 List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", "");
3005 for (i=0; i < Count; i++) {
3006
3007 if (io ->Read(io, Name, 32, 1) != 1) goto Error;
3008 Name[33] = 0;
3009
3010 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3011
3012 if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error;
3013
3014 }
3015
3016 *nItems = 1;
3017 return List;
3018
3019 Error:
3020 *nItems = 0;
3021 cmsFreeNamedColorList(List);
3022 return NULL;
3023
3024 cmsUNUSED_PARAMETER(SizeOfTag);
3025 }
3026
3027
3028
3029 // Saves a colorant table. It is using the named color structure for simplicity sake
3030 static
3031 cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3032 {
3033 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3034 int i, nColors;
3035
3036 nColors = cmsNamedColorCount(NamedColorList);
3037
3038 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3039
3040 for (i=0; i < nColors; i++) {
3041
3042 char root[33];
3043 cmsUInt16Number PCS[3];
3044
3045 if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0;
3046 root[32] = 0;
3047
3048 if (!io ->Write(io, 32, root)) return FALSE;
3049 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3050 }
3051
3052 return TRUE;
3053
3054 cmsUNUSED_PARAMETER(nItems);
3055 cmsUNUSED_PARAMETER(self);
3056 }
3057
3058
3059 static
3060 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3061 {
3062 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3063 return (void*) cmsDupNamedColorList(nc);
3064
3065 cmsUNUSED_PARAMETER(n);
3066 cmsUNUSED_PARAMETER(self);
3067 }
3068
3069
3070 static
3071 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
3072 {
3073 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3074 return;
3075
3076 cmsUNUSED_PARAMETER(self);
3077 }
3078
3079
3080 // ********************************************************************************
3081 // Type cmsSigNamedColor2Type
3082 // ********************************************************************************
3083 //
3084 //The namedColor2Type is a count value and array of structures that provide color
3085 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3086 //device representation of the color are given. Both representations are 16-bit values.
3087 //The device representation corresponds to the header’s “color space of data” field.
3088 //This representation should be consistent with the “number of device components”
3089 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3090 //The PCS representation corresponds to the header’s PCS field. The PCS representation
3091 //is always provided. Color names are fixed-length, 32-byte fields including null
3092 //termination. In order to maintain maximum portability, it is strongly recommended
3093 //that special characters of the 7-bit ASCII set not be used.
3094
3095 static
3096 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3127 }
3128 for (i=0; i < count; i++) {
3129
3130 cmsUInt16Number PCS[3];
3131 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3132 char Root[33];
3133
3134 memset(Colorant, 0, sizeof(Colorant));
3135 if (io -> Read(io, Root, 32, 1) != 1) return NULL;
3136 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3137 if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
3138
3139 if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
3140 }
3141
3142 *nItems = 1;
3143 return (void*) v ;
3144
3145 Error:
3146 cmsFreeNamedColorList(v);
3147 return NULL;
3148
3149 cmsUNUSED_PARAMETER(SizeOfTag);
3150 }
3151
3152
3153 // Saves a named color list into a named color profile
3154 static
3155 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3156 {
3157 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3158 char prefix[32]; // Prefix for each color name
3159 char suffix[32]; // Suffix for each color name
3160 int i, nColors;
3161
3162 nColors = cmsNamedColorCount(NamedColorList);
3163
3164 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
3165 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3166 if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
3167
3168 strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
3169 strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
3170
3171 suffix[31] = prefix[31] = 0;
3172
3173 if (!io ->Write(io, 32, prefix)) return FALSE;
3174 if (!io ->Write(io, 32, suffix)) return FALSE;
3175
3176 for (i=0; i < nColors; i++) {
3177
3178 cmsUInt16Number PCS[3];
3179 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3180 char Root[33];
3181
3182 if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
3183 if (!io ->Write(io, 32 , Root)) return FALSE;
3184 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3185 if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
3186 }
3187
3188 return TRUE;
3189
3190 cmsUNUSED_PARAMETER(nItems);
3191 cmsUNUSED_PARAMETER(self);
3192 }
3193
3194 static
3195 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3196 {
3197 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3198
3199 return (void*) cmsDupNamedColorList(nc);
3200
3201 cmsUNUSED_PARAMETER(n);
3202 cmsUNUSED_PARAMETER(self);
3203 }
3204
3205
3206 static
3207 void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr)
3208 {
3209 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3210 return;
3211
3212 cmsUNUSED_PARAMETER(self);
3213 }
3214
3215
3216 // ********************************************************************************
3217 // Type cmsSigProfileSequenceDescType
3218 // ********************************************************************************
3219
3220 // This type is an array of structures, each of which contains information from the
3221 // header fields and tags from the original profiles which were combined to create
3222 // the final profile. The order of the structures is the order in which the profiles
3223 // were combined and includes a structure for the final profile. This provides a
3224 // description of the profile sequence from source to destination,
3225 // typically used with the DeviceLink profile.
3226
3227 static
3228 cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag)
3229 {
3230 cmsTagTypeSignature BaseType;
3231 cmsUInt32Number nItems;
3232
3333 cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3334 {
3335 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3336 cmsUInt32Number i;
3337
3338 if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE;
3339
3340 for (i=0; i < Seq ->n; i++) {
3341
3342 cmsPSEQDESC* sec = &Seq -> seq[i];
3343
3344 if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE;
3345 if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE;
3346 if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE;
3347 if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE;
3348
3349 if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE;
3350 if (!SaveDescription(self, io, sec ->Model)) return FALSE;
3351 }
3352
3353 return TRUE;
3354
3355 cmsUNUSED_PARAMETER(nItems);
3356 }
3357
3358
3359 static
3360 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3361 {
3362 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3363
3364 cmsUNUSED_PARAMETER(n);
3365 cmsUNUSED_PARAMETER(self);
3366 }
3367
3368 static
3369 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr)
3370 {
3371 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3372 return;
3373
3374 cmsUNUSED_PARAMETER(self);
3375 }
3376
3377
3378 // ********************************************************************************
3379 // Type cmsSigProfileSequenceIdType
3380 // ********************************************************************************
3381 /*
3382 In certain workflows using ICC Device Link Profiles, it is necessary to identify the
3383 original profiles that were combined to create the Device Link Profile.
3384 This type is an array of structures, each of which contains information for
3385 identification of a profile used in a sequence
3386 */
3387
3388
3389 static
3390 cmsBool ReadSeqID(struct _cms_typehandler_struct* self,
3391 cmsIOHANDLER* io,
3392 void* Cargo,
3393 cmsUInt32Number n,
3394 cmsUInt32Number SizeOfTag)
3436 *nItems = 1;
3437 return OutSeq;
3438
3439 }
3440
3441
3442 static
3443 cmsBool WriteSeqID(struct _cms_typehandler_struct* self,
3444 cmsIOHANDLER* io,
3445 void* Cargo,
3446 cmsUInt32Number n,
3447 cmsUInt32Number SizeOfTag)
3448 {
3449 cmsSEQ* Seq = (cmsSEQ*) Cargo;
3450
3451 if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE;
3452
3453 // Store here the MLU
3454 if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE;
3455
3456 return TRUE;
3457
3458 cmsUNUSED_PARAMETER(SizeOfTag);
3459 }
3460
3461 static
3462 cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3463 {
3464 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3465 cmsUInt32Number BaseOffset;
3466
3467 // Keep the base offset
3468 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3469
3470 // This is the table count
3471 if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE;
3472
3473 // This is the position table and content
3474 if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE;
3475
3476 return TRUE;
3477
3478 cmsUNUSED_PARAMETER(nItems);
3479 }
3480
3481 static
3482 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3483 {
3484 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3485
3486 cmsUNUSED_PARAMETER(n);
3487 cmsUNUSED_PARAMETER(self);
3488 }
3489
3490 static
3491 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr)
3492 {
3493 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3494 return;
3495
3496 cmsUNUSED_PARAMETER(self);
3497 }
3498
3499
3500 // ********************************************************************************
3501 // Type cmsSigUcrBgType
3502 // ********************************************************************************
3503 /*
3504 This type contains curves representing the under color removal and black
3505 generation and a text string which is a general description of the method used
3506 for the ucr/bg.
3507 */
3508
3509 static
3510 void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3511 {
3512 cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3513 cmsUInt32Number CountUcr, CountBg;
3514 char* ASCIIString;
3515
3516 *nItems = 0;
3560 cmsUcrBg* Value = (cmsUcrBg*) Ptr;
3561 cmsUInt32Number TextSize;
3562 char* Text;
3563
3564 // First curve is Under color removal
3565 if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE;
3566 if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE;
3567
3568 // Then black generation
3569 if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE;
3570 if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE;
3571
3572 // Now comes the text. The length is specified by the tag size
3573 TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0);
3574 Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
3575 if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE;
3576
3577 if (!io ->Write(io, TextSize, Text)) return FALSE;
3578 _cmsFree(self ->ContextID, Text);
3579
3580 return TRUE;
3581
3582 cmsUNUSED_PARAMETER(nItems);
3583 }
3584
3585 static
3586 void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3587 {
3588 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3589 cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3590
3591 if (NewUcrBg == NULL) return NULL;
3592
3593 NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg);
3594 NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr);
3595 NewUcrBg ->Desc = cmsMLUdup(Src ->Desc);
3596
3597 return (void*) NewUcrBg;
3598
3599 cmsUNUSED_PARAMETER(n);
3600 }
3601
3602 static
3603 void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr)
3604 {
3605 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3606
3607 if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr);
3608 if (Src ->Bg) cmsFreeToneCurve(Src ->Bg);
3609 if (Src ->Desc) cmsMLUfree(Src ->Desc);
3610
3611 _cmsFree(self ->ContextID, Ptr);
3612 }
3613
3614 // ********************************************************************************
3615 // Type cmsSigCrdInfoType
3616 // ********************************************************************************
3617
3618 /*
3619 This type contains the PostScript product name to which this profile corresponds
3699 cmsMLUfree(mlu);
3700 return NULL;
3701
3702 }
3703
3704 static
3705 cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3706 {
3707
3708 cmsMLU* mlu = (cmsMLU*) Ptr;
3709
3710 if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error;
3711 if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error;
3712 if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error;
3713 if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error;
3714 if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error;
3715
3716 return TRUE;
3717
3718 Error:
3719 return FALSE;
3720
3721 cmsUNUSED_PARAMETER(nItems);
3722 }
3723
3724
3725 static
3726 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3727 {
3728 return (void*) cmsMLUdup((cmsMLU*) Ptr);
3729
3730 cmsUNUSED_PARAMETER(n);
3731 cmsUNUSED_PARAMETER(self);
3732 }
3733
3734 static
3735 void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr)
3736 {
3737 cmsMLUfree((cmsMLU*) Ptr);
3738 return;
3739
3740 cmsUNUSED_PARAMETER(self);
3741 }
3742
3743 // ********************************************************************************
3744 // Type cmsSigScreeningType
3745 // ********************************************************************************
3746 //
3747 //The screeningType describes various screening parameters including screen
3748 //frequency, screening angle, and spot shape.
3749
3750 static
3751 void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3752 {
3753 cmsScreening* sc = NULL;
3754 cmsUInt32Number i;
3755
3756 sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening));
3757 if (sc == NULL) return NULL;
3758
3759 *nItems = 0;
3760
3763
3764 if (sc ->nChannels > cmsMAXCHANNELS - 1)
3765 sc ->nChannels = cmsMAXCHANNELS - 1;
3766
3767 for (i=0; i < sc ->nChannels; i++) {
3768
3769 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error;
3770 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error;
3771 if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error;
3772 }
3773
3774
3775 *nItems = 1;
3776
3777 return (void*) sc;
3778
3779 Error:
3780 if (sc != NULL)
3781 _cmsFree(self ->ContextID, sc);
3782
3783 return NULL;
3784
3785 cmsUNUSED_PARAMETER(SizeOfTag);
3786 }
3787
3788
3789 static
3790 cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3791 {
3792 cmsScreening* sc = (cmsScreening* ) Ptr;
3793 cmsUInt32Number i;
3794
3795 if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE;
3796 if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE;
3797
3798 for (i=0; i < sc ->nChannels; i++) {
3799
3800 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE;
3801 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE;
3802 if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE;
3803 }
3804
3805 return TRUE;
3806
3807 cmsUNUSED_PARAMETER(nItems);
3808 cmsUNUSED_PARAMETER(self);
3809 }
3810
3811
3812 static
3813 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3814 {
3815 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3816
3817 cmsUNUSED_PARAMETER(n);
3818 }
3819
3820
3821 static
3822 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
3823 {
3824 _cmsFree(self ->ContextID, Ptr);
3825 }
3826
3827 // ********************************************************************************
3828 // Type cmsSigViewingConditionsType
3829 // ********************************************************************************
3830 //
3831 //This type represents a set of viewing condition parameters including:
3832 //CIE ’absolute’ illuminant white point tristimulus values and CIE ’absolute’
3833 //surround tristimulus values.
3834
3835 static
3836 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3837 {
3838 cmsICCViewingConditions* vc = NULL;
3839
3840 vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
3841 if (vc == NULL) return NULL;
3842
3843 *nItems = 0;
3844
3845 if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
3846 if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
3847 if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
3848
3849 *nItems = 1;
3850
3851 return (void*) vc;
3852
3853 Error:
3854 if (vc != NULL)
3855 _cmsFree(self ->ContextID, vc);
3856
3857 return NULL;
3858
3859 cmsUNUSED_PARAMETER(SizeOfTag);
3860 }
3861
3862
3863 static
3864 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3865 {
3866 cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
3867
3868 if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
3869 if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
3870 if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
3871
3872 return TRUE;
3873
3874 cmsUNUSED_PARAMETER(nItems);
3875 cmsUNUSED_PARAMETER(self);
3876 }
3877
3878
3879 static
3880 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3881 {
3882 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3883
3884 cmsUNUSED_PARAMETER(n);
3885 }
3886
3887
3888 static
3889 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
3890 {
3891 _cmsFree(self ->ContextID, Ptr);
3892 }
3893
3894
3895 // ********************************************************************************
3896 // Type cmsSigMultiProcessElementType
3897 // ********************************************************************************
3898
3899
3900 static
3901 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3902 {
3903 return (void*) cmsStageDup((cmsStage*) Ptr);
3904
3905 cmsUNUSED_PARAMETER(n);
3906 cmsUNUSED_PARAMETER(self);
3907 }
3908
3909 static
3910 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
3911 {
3912 cmsStageFree((cmsStage*) Ptr);
3913 return;
3914
3915 cmsUNUSED_PARAMETER(self);
3916 }
3917
3918 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
3919 // The first curve segment always starts at –Infinity, and the last curve segment always ends at +Infinity. The
3920 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
3921 // specified either in terms of a formula, or by a sampled curve.
3922
3923
3924 // Read an embedded segmented curve
3925 static
3926 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
3927 {
3928 cmsCurveSegSignature ElementSig;
3929 cmsUInt32Number i, j;
3930 cmsUInt16Number nSegments;
3931 cmsCurveSegment* Segments;
3932 cmsToneCurve* Curve;
3933 cmsFloat32Number PrevBreak = -1E22F; // - infinite
3934
3935 // Take signature and channels for each element.
4020 }
4021 _cmsFree(self ->ContextID, Segments);
4022 return Curve;
4023
4024 Error:
4025 if (Segments) _cmsFree(self ->ContextID, Segments);
4026 return NULL;
4027 }
4028
4029
4030 static
4031 cmsBool ReadMPECurve(struct _cms_typehandler_struct* self,
4032 cmsIOHANDLER* io,
4033 void* Cargo,
4034 cmsUInt32Number n,
4035 cmsUInt32Number SizeOfTag)
4036 {
4037 cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo;
4038
4039 GammaTables[n] = ReadSegmentedCurve(self, io);
4040 return (GammaTables[n] != NULL);
4041
4042 cmsUNUSED_PARAMETER(SizeOfTag);
4043 }
4044
4045 static
4046 void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4047 {
4048 cmsStage* mpe = NULL;
4049 cmsUInt16Number InputChans, OutputChans;
4050 cmsUInt32Number i, BaseOffset;
4051 cmsToneCurve** GammaTables;
4052
4053 *nItems = 0;
4054
4055 // Get actual position as a basis for element offsets
4056 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4057
4058 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4059 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4060
4061 if (InputChans != OutputChans) return NULL;
4062
4063 GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*));
4064 if (GammaTables == NULL) return NULL;
4065
4066 if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) {
4067
4068 mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables);
4069 }
4070 else {
4071 mpe = NULL;
4072 }
4073
4074 for (i=0; i < InputChans; i++) {
4075 if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]);
4076 }
4077
4078 _cmsFree(self ->ContextID, GammaTables);
4079 *nItems = (mpe != NULL) ? 1 : 0;
4080 return mpe;
4081
4082 cmsUNUSED_PARAMETER(SizeOfTag);
4083 }
4084
4085
4086 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
4087 static
4088 cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g)
4089 {
4090 cmsUInt32Number i, j;
4091 cmsCurveSegment* Segments = g ->Segments;
4092 cmsUInt32Number nSegments = g ->nSegments;
4093
4094 if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error;
4095 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4096 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error;
4097 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4098
4099 // Write the break-points
4100 for (i=0; i < nSegments - 1; i++) {
4101 if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error;
4102 }
4141 // It seems there is no need to align. Code is here, and for safety commented out
4142 // if (!_cmsWriteAlignment(io)) goto Error;
4143 }
4144
4145 return TRUE;
4146
4147 Error:
4148 return FALSE;
4149 }
4150
4151
4152 static
4153 cmsBool WriteMPECurve(struct _cms_typehandler_struct* self,
4154 cmsIOHANDLER* io,
4155 void* Cargo,
4156 cmsUInt32Number n,
4157 cmsUInt32Number SizeOfTag)
4158 {
4159 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo;
4160
4161 return WriteSegmentedCurve(io, Curves ->TheCurves[n]);
4162
4163 cmsUNUSED_PARAMETER(SizeOfTag);
4164 cmsUNUSED_PARAMETER(self);
4165 }
4166
4167 // Write a curve, checking first for validity
4168 static
4169 cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4170 {
4171 cmsUInt32Number BaseOffset;
4172 cmsStage* mpe = (cmsStage*) Ptr;
4173 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data;
4174
4175 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4176
4177 // Write the header. Since those are curves, input and output channels are same
4178 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4179 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4180
4181 if (!WritePositionTable(self, io, 0,
4182 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
4183
4184
4185 return TRUE;
4186
4187 cmsUNUSED_PARAMETER(nItems);
4188 }
4189
4190
4191
4192 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4193 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4194 // is organized as follows:
4195 // array = [e11, e12, …, e1P, e21, e22, …, e2P, …, eQ1, eQ2, …, eQP, e1, e2, …, eQ]
4196
4197 static
4198 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4199 {
4200 cmsStage* mpe;
4201 cmsUInt16Number InputChans, OutputChans;
4202 cmsUInt32Number nElems, i;
4203 cmsFloat64Number* Matrix;
4204 cmsFloat64Number* Offsets;
4205
4206 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4207 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4227 if (!_cmsReadFloat32Number(io, &v)) return NULL;
4228 Matrix[i] = v;
4229 }
4230
4231
4232 for (i=0; i < OutputChans; i++) {
4233
4234 cmsFloat32Number v;
4235
4236 if (!_cmsReadFloat32Number(io, &v)) return NULL;
4237 Offsets[i] = v;
4238 }
4239
4240
4241 mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets);
4242 _cmsFree(self ->ContextID, Matrix);
4243 _cmsFree(self ->ContextID, Offsets);
4244
4245 *nItems = 1;
4246
4247 return mpe;
4248
4249 cmsUNUSED_PARAMETER(SizeOfTag);
4250 }
4251
4252 static
4253 cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4254 {
4255 cmsUInt32Number i, nElems;
4256 cmsStage* mpe = (cmsStage*) Ptr;
4257 _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data;
4258
4259 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4260 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4261
4262 nElems = mpe ->InputChannels * mpe ->OutputChannels;
4263
4264 for (i=0; i < nElems; i++) {
4265 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE;
4266 }
4267
4268
4269 for (i=0; i < mpe ->OutputChannels; i++) {
4270
4271 if (Matrix ->Offset == NULL) {
4272
4273 if (!_cmsWriteFloat32Number(io, 0)) return FALSE;
4274 }
4275 else {
4276 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE;
4277 }
4278 }
4279
4280 return TRUE;
4281
4282 cmsUNUSED_PARAMETER(nItems);
4283 cmsUNUSED_PARAMETER(self);
4284 }
4285
4286
4287
4288 static
4289 void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4290 {
4291 cmsStage* mpe = NULL;
4292 cmsUInt16Number InputChans, OutputChans;
4293 cmsUInt8Number Dimensions8[16];
4294 cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS];
4295 _cmsStageCLutData* clut;
4296
4297 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4298 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4299
4300 if (InputChans == 0) goto Error;
4301 if (OutputChans == 0) goto Error;
4302
4303 if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
4307 nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans;
4308 for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i];
4309
4310 // Allocate the true CLUT
4311 mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
4312 if (mpe == NULL) goto Error;
4313
4314 // Read the data
4315 clut = (_cmsStageCLutData*) mpe ->Data;
4316 for (i=0; i < clut ->nEntries; i++) {
4317
4318 if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
4319 }
4320
4321 *nItems = 1;
4322 return mpe;
4323
4324 Error:
4325 *nItems = 0;
4326 if (mpe != NULL) cmsStageFree(mpe);
4327 return NULL;
4328
4329 cmsUNUSED_PARAMETER(SizeOfTag);
4330 }
4331
4332 // Write a CLUT in floating point
4333 static
4334 cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4335 {
4336 cmsUInt8Number Dimensions8[16];
4337 cmsUInt32Number i;
4338 cmsStage* mpe = (cmsStage*) Ptr;
4339 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
4340
4341 // Check for maximum number of channels
4342 if (mpe -> InputChannels > 15) return FALSE;
4343
4344 // Only floats are supported in MPE
4345 if (clut ->HasFloatValues == FALSE) return FALSE;
4346
4347 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4348 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4349
4350 memset(Dimensions8, 0, sizeof(Dimensions8));
4351
4352 for (i=0; i < mpe ->InputChannels; i++)
4353 Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
4354
4355 if (!io ->Write(io, 16, Dimensions8)) return FALSE;
4356
4357 for (i=0; i < clut ->nEntries; i++) {
4358
4359 if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
4360 }
4361
4362 return TRUE;
4363
4364 cmsUNUSED_PARAMETER(nItems);
4365 cmsUNUSED_PARAMETER(self);
4366 }
4367
4368
4369
4370 // This is the list of built-in MPE types
4371 static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
4372
4373 {{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now
4374 {{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says)
4375
4376 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] },
4377 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] },
4378 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL },
4379 };
4380
4381 _cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL };
4382
4383 static
4384 cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
4385 cmsIOHANDLER* io,
4405 if (TypeHandler == NULL) {
4406
4407 char String[5];
4408
4409 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4410
4411 // An unknown element was found.
4412 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String);
4413 return FALSE;
4414 }
4415
4416 // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
4417 // Read the MPE. No size is given
4418 if (TypeHandler ->ReadPtr != NULL) {
4419
4420 // This is a real element which should be read and processed
4421 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag)))
4422 return FALSE;
4423 }
4424
4425 return TRUE;
4426
4427 cmsUNUSED_PARAMETER(SizeOfTag);
4428 cmsUNUSED_PARAMETER(n);
4429 }
4430
4431
4432 // This is the main dispatcher for MPE
4433 static
4434 void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4435 {
4436 cmsUInt16Number InputChans, OutputChans;
4437 cmsUInt32Number ElementCount;
4438 cmsPipeline *NewLUT = NULL;
4439 cmsUInt32Number BaseOffset;
4440
4441 // Get actual position as a basis for element offsets
4442 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4443
4444 // Read channels and element count
4445 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4446 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4447
4448 // Allocates an empty LUT
4449 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
4450 if (NewLUT == NULL) return NULL;
4451
4452 if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL;
4453
4454 if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) {
4455 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
4456 *nItems = 0;
4457 return NULL;
4458 }
4459
4460 // Success
4461 *nItems = 1;
4462 return NewLUT;
4463
4464 cmsUNUSED_PARAMETER(SizeOfTag);
4465 }
4466
4467
4468
4469 // This one is a liitle bit more complex, so we don't use position tables this time.
4470 static
4471 cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4472 {
4473 cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos;
4474 int inputChan, outputChan;
4475 cmsUInt32Number ElemCount;
4476 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before;
4477 cmsStageSignature ElementSig;
4478 cmsPipeline* Lut = (cmsPipeline*) Ptr;
4479 cmsStage* Elem = Lut ->Elements;
4480 cmsTagTypeHandler* TypeHandler;
4481 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
4482
4483 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4484
4537
4538 // Write the directory
4539 CurrentPos = io ->Tell(io);
4540
4541 if (!io ->Seek(io, DirectoryPos)) goto Error;
4542
4543 for (i=0; i < ElemCount; i++) {
4544 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
4545 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
4546 }
4547
4548 if (!io ->Seek(io, CurrentPos)) goto Error;
4549
4550 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4551 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4552 return TRUE;
4553
4554 Error:
4555 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4556 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4557 return FALSE;
4558
4559 cmsUNUSED_PARAMETER(nItems);
4560 }
4561
4562
4563 static
4564 void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4565 {
4566 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
4567
4568 cmsUNUSED_PARAMETER(n);
4569 cmsUNUSED_PARAMETER(self);
4570 }
4571
4572 static
4573 void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr)
4574 {
4575 cmsPipelineFree((cmsPipeline*) Ptr);
4576 return;
4577
4578 cmsUNUSED_PARAMETER(self);
4579 }
4580
4581
4582 // ********************************************************************************
4583 // Type cmsSigVcgtType
4584 // ********************************************************************************
4585
4586
4587 #define cmsVideoCardGammaTableType 0
4588 #define cmsVideoCardGammaFormulaType 1
4589
4590 // Used internally
4591 typedef struct {
4592 double Gamma;
4593 double Min;
4594 double Max;
4595 } _cmsVCGTGAMMA;
4596
4597
4598 static
4709 Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
4710 if (Curves[n] == NULL) goto Error;
4711 }
4712 }
4713 break;
4714
4715 // Unsupported
4716 default:
4717 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
4718 goto Error;
4719 }
4720
4721 *nItems = 1;
4722 return (void*) Curves;
4723
4724 // Regret, free all resources
4725 Error:
4726
4727 cmsFreeToneCurveTriple(Curves);
4728 _cmsFree(self ->ContextID, Curves);
4729 return NULL;
4730
4731 cmsUNUSED_PARAMETER(SizeOfTag);
4732 }
4733
4734
4735 // We don't support all flavors, only 16bits tables and formula
4736 static
4737 cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4738 {
4739 cmsToneCurve** Curves = (cmsToneCurve**) Ptr;
4740 cmsUInt32Number i, j;
4741
4742 if (cmsGetToneCurveParametricType(Curves[0]) == 5 &&
4743 cmsGetToneCurveParametricType(Curves[1]) == 5 &&
4744 cmsGetToneCurveParametricType(Curves[2]) == 5) {
4745
4746 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
4747
4748 // Save parameters
4749 for (i=0; i < 3; i++) {
4750
4751 _cmsVCGTGAMMA v;
4762
4763 else {
4764
4765 // Always store as a table of 256 words
4766 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE;
4767 if (!_cmsWriteUInt16Number(io, 3)) return FALSE;
4768 if (!_cmsWriteUInt16Number(io, 256)) return FALSE;
4769 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
4770
4771 for (i=0; i < 3; i++) {
4772 for (j=0; j < 256; j++) {
4773
4774 cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0));
4775 cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0);
4776
4777 if (!_cmsWriteUInt16Number(io, n)) return FALSE;
4778 }
4779 }
4780 }
4781
4782 return TRUE;
4783
4784 cmsUNUSED_PARAMETER(self);
4785 cmsUNUSED_PARAMETER(nItems);
4786 }
4787
4788 static
4789 void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4790 {
4791 cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr;
4792 cmsToneCurve** NewCurves;
4793
4794 NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4795 if (NewCurves == NULL) return NULL;
4796
4797 NewCurves[0] = cmsDupToneCurve(OldCurves[0]);
4798 NewCurves[1] = cmsDupToneCurve(OldCurves[1]);
4799 NewCurves[2] = cmsDupToneCurve(OldCurves[2]);
4800
4801 return (void*) NewCurves;
4802
4803 cmsUNUSED_PARAMETER(n);
4804 }
4805
4806
4807 static
4808 void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr)
4809 {
4810 cmsFreeToneCurveTriple((cmsToneCurve**) Ptr);
4811 _cmsFree(self ->ContextID, Ptr);
4812 }
4813
4814
4815 // ********************************************************************************
4816 // Type cmsSigDictType
4817 // ********************************************************************************
4818
4819 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data
4820 typedef struct {
4821 cmsContext ContextID;
4822 cmsUInt32Number *Offsets;
4823 cmsUInt32Number *Sizes;
5207 if (p ->DisplayValue != NULL) {
5208 if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error;
5209 }
5210
5211 p = cmsDictNextEntry(p);
5212 }
5213
5214 // Write the directory
5215 CurrentPos = io ->Tell(io);
5216 if (!io ->Seek(io, DirectoryPos)) goto Error;
5217
5218 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5219
5220 if (!io ->Seek(io, CurrentPos)) goto Error;
5221
5222 FreeArray(&a);
5223 return TRUE;
5224
5225 Error:
5226 FreeArray(&a);
5227 return FALSE;
5228
5229 cmsUNUSED_PARAMETER(nItems);
5230 }
5231
5232
5233 static
5234 void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
5235 {
5236 return (void*) cmsDictDup((cmsHANDLE) Ptr);
5237
5238 cmsUNUSED_PARAMETER(n);
5239 cmsUNUSED_PARAMETER(self);
5240 }
5241
5242
5243 static
5244 void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr)
5245 {
5246 cmsDictFree((cmsHANDLE) Ptr);
5247 cmsUNUSED_PARAMETER(self);
5248 }
5249
5250
5251 // ********************************************************************************
5252 // Type support main routines
5253 // ********************************************************************************
5254
5255
5256 // This is the list of built-in types
5257 static _cmsTagTypeLinkedList SupportedTagTypes[] = {
5258
5259 {TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] },
|
311 //The XYZType contains an array of three encoded values for the XYZ tristimulus
312 //values. Tristimulus values must be non-negative. The signed encoding allows for
313 //implementation optimizations by minimizing the number of fixed formats.
314
315
316 static
317 void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
318 {
319 cmsCIEXYZ* xyz;
320
321 *nItems = 0;
322 xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ));
323 if (xyz == NULL) return NULL;
324
325 if (!_cmsReadXYZNumber(io, xyz)) {
326 _cmsFree(self ->ContextID, xyz);
327 return NULL;
328 }
329
330 *nItems = 1;
331
332 cmsUNUSED_PARAMETER(SizeOfTag);
333
334 return (void*) xyz;
335
336 }
337
338 static
339 cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
340 {
341 cmsUNUSED_PARAMETER(nItems);
342 cmsUNUSED_PARAMETER(self);
343
344 return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr);
345
346 }
347
348 static
349 void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
350 {
351 cmsUNUSED_PARAMETER(n);
352
353 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ));
354
355 }
356
357 static
358 void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr)
359 {
360 _cmsFree(self ->ContextID, Ptr);
361 }
362
363
364 static
365 cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data)
366 {
367 cmsUNUSED_PARAMETER(ICCVersion);
368 cmsUNUSED_PARAMETER(Data);
369
370 return cmsSigXYZType;
371
372 }
373
374
375 // ********************************************************************************
376 // Type chromaticity. Only one value is allowed
377 // ********************************************************************************
378 // The chromaticity tag type provides basic chromaticity data and type of
379 // phosphors or colorants of a monitor to applications and utilities.
380
381 static
382 void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
383 {
384 cmsCIExyYTRIPLE* chrm;
385 cmsUInt16Number nChans, Table;
386
387 *nItems = 0;
388 chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE));
389 if (chrm == NULL) return NULL;
390
391 if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
404 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error;
405 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error;
406
407 chrm ->Red.Y = 1.0;
408
409 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error;
410 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error;
411
412 chrm ->Green.Y = 1.0;
413
414 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error;
415 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error;
416
417 chrm ->Blue.Y = 1.0;
418
419 *nItems = 1;
420 return (void*) chrm;
421
422 Error:
423 _cmsFree(self ->ContextID, (void*) chrm);
424 cmsUNUSED_PARAMETER(SizeOfTag);
425
426 return NULL;
427
428 }
429
430 static
431 cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io)
432 {
433 if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE;
434 if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE;
435
436 return TRUE;
437 }
438
439 static
440 cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
441 {
442 cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr;
443
444 if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels
445 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table
446
447 if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE;
448 if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE;
449 if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE;
450
451 cmsUNUSED_PARAMETER(nItems);
452 cmsUNUSED_PARAMETER(self);
453
454 return TRUE;
455
456 }
457
458 static
459 void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
460 {
461 cmsUNUSED_PARAMETER(n);
462
463 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE));
464
465 }
466
467 static
468 void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr)
469 {
470 _cmsFree(self ->ContextID, Ptr);
471 }
472
473
474 // ********************************************************************************
475 // Type cmsSigColorantOrderType
476 // ********************************************************************************
477
478 // This is an optional tag which specifies the laydown order in which colorants will
479 // be printed on an n-colorant device. The laydown order may be the same as the
480 // channel generation order listed in the colorantTableTag or the channel order of a
481 // colour space such as CMYK, in which case this tag is not needed. When this is not
482 // the case (for example, ink-towers sometimes use the order KCMY), this tag may be
483 // used to specify the laydown order of the colorants.
484
489 cmsUInt8Number* ColorantOrder;
490 cmsUInt32Number Count;
491
492 *nItems = 0;
493 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
494 if (Count > cmsMAXCHANNELS) return NULL;
495
496 ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number));
497 if (ColorantOrder == NULL) return NULL;
498
499 // We use FF as end marker
500 memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
501
502 if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) {
503
504 _cmsFree(self ->ContextID, (void*) ColorantOrder);
505 return NULL;
506 }
507
508 *nItems = 1;
509 cmsUNUSED_PARAMETER(SizeOfTag);
510
511 return (void*) ColorantOrder;
512
513 }
514
515 static
516 cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
517 {
518 cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr;
519 cmsUInt32Number i, sz, Count;
520
521 // Get the length
522 for (Count=i=0; i < cmsMAXCHANNELS; i++) {
523 if (ColorantOrder[i] != 0xFF) Count++;
524 }
525
526 if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
527
528 sz = Count * sizeof(cmsUInt8Number);
529 if (!io -> Write(io, sz, ColorantOrder)) return FALSE;
530
531 cmsUNUSED_PARAMETER(nItems);
532 cmsUNUSED_PARAMETER(self);
533
534 return TRUE;
535
536 }
537
538 static
539 void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
540 {
541 cmsUNUSED_PARAMETER(n);
542
543 return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
544
545 }
546
547
548 static
549 void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr)
550 {
551 _cmsFree(self ->ContextID, Ptr);
552 }
553
554 // ********************************************************************************
555 // Type cmsSigS15Fixed16ArrayType
556 // ********************************************************************************
557 // This type represents an array of generic 4-byte/32-bit fixed point quantity.
558 // The number of values is determined from the size of the tag.
559
560 static
561 void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
562 {
563 cmsFloat64Number* array_double;
564 cmsUInt32Number i, n;
575 _cmsFree(self ->ContextID, array_double);
576 return NULL;
577 }
578 }
579
580 *nItems = n;
581 return (void*) array_double;
582 }
583
584 static
585 cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
586 {
587 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
588 cmsUInt32Number i;
589
590 for (i=0; i < nItems; i++) {
591
592 if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE;
593 }
594
595 cmsUNUSED_PARAMETER(self);
596
597 return TRUE;
598
599 }
600
601 static
602 void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
603 {
604 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
605 }
606
607
608 static
609 void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
610 {
611 _cmsFree(self ->ContextID, Ptr);
612 }
613
614 // ********************************************************************************
615 // Type cmsSigU16Fixed16ArrayType
616 // ********************************************************************************
617 // This type represents an array of generic 4-byte/32-bit quantity.
618 // The number of values is determined from the size of the tag.
641 array_double[i] = (cmsFloat64Number) (v / 65536.0);
642 }
643
644 *nItems = n;
645 return (void*) array_double;
646 }
647
648 static
649 cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
650 {
651 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
652 cmsUInt32Number i;
653
654 for (i=0; i < nItems; i++) {
655
656 cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5);
657
658 if (!_cmsWriteUInt32Number(io, v)) return FALSE;
659 }
660
661 cmsUNUSED_PARAMETER(self);
662
663 return TRUE;
664
665 }
666
667
668 static
669 void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
670 {
671 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
672 }
673
674 static
675 void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
676 {
677 _cmsFree(self ->ContextID, Ptr);
678 }
679
680 // ********************************************************************************
681 // Type cmsSigSignatureType
682 // ********************************************************************************
683 //
684 // The signatureType contains a four-byte sequence, Sequences of less than four
685 // characters are padded at the end with spaces, 20h.
686 // Typically this type is used for registered tags that can be displayed on many
687 // development systems as a sequence of four characters.
688
689 static
690 void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
691 {
692 cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature));
693 if (SigPtr == NULL) return NULL;
694
695 if (!_cmsReadUInt32Number(io, SigPtr)) return NULL;
696 *nItems = 1;
697
698 cmsUNUSED_PARAMETER(SizeOfTag);
699
700 return SigPtr;
701
702 }
703
704 static
705 cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
706 {
707 cmsSignature* SigPtr = (cmsSignature*) Ptr;
708
709 cmsUNUSED_PARAMETER(nItems);
710 cmsUNUSED_PARAMETER(self);
711
712 return _cmsWriteUInt32Number(io, *SigPtr);
713
714 }
715
716 static
717 void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
718 {
719 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature));
720 }
721
722 static
723 void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr)
724 {
725 _cmsFree(self ->ContextID, Ptr);
726 }
727
728
729 // ********************************************************************************
730 // Type cmsSigTextType
731 // ********************************************************************************
732 //
733 // The textType is a simple text structure that contains a 7-bit ASCII text string.
779 {
780 cmsMLU* mlu = (cmsMLU*) Ptr;
781 cmsUInt32Number size;
782 cmsBool rc;
783 char* Text;
784
785 // Get the size of the string. Note there is an extra "\0" at the end
786 size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
787 if (size == 0) return FALSE; // Cannot be zero!
788
789 // Create memory
790 Text = (char*) _cmsMalloc(self ->ContextID, size);
791 if (Text == NULL) return FALSE;
792
793 cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
794
795 // Write it, including separator
796 rc = io ->Write(io, size, Text);
797
798 _cmsFree(self ->ContextID, Text);
799 cmsUNUSED_PARAMETER(nItems);
800
801 return rc;
802
803 }
804
805 static
806 void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
807 {
808 cmsUNUSED_PARAMETER(n);
809 cmsUNUSED_PARAMETER(self);
810
811 return (void*) cmsMLUdup((cmsMLU*) Ptr);
812
813 }
814
815
816 static
817 void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr)
818 {
819 cmsMLU* mlu = (cmsMLU*) Ptr;
820 cmsMLUfree(mlu);
821 cmsUNUSED_PARAMETER(self);
822
823 return;
824
825 }
826
827 static
828 cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data)
829 {
830 cmsUNUSED_PARAMETER(Data);
831
832 if (ICCVersion >= 4.0)
833 return cmsSigMultiLocalizedUnicodeType;
834
835 return cmsSigTextType;
836
837 }
838
839
840 // ********************************************************************************
841 // Type cmsSigDataType
842 // ********************************************************************************
843
844 // General purpose data type
845 static
846 void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
847 {
848 cmsICCData* BinData;
849 cmsUInt32Number LenOfData;
850
851 *nItems = 0;
852
853 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
854
855 LenOfData = SizeOfTag - sizeof(cmsUInt32Number);
856 if (LenOfData > INT_MAX) return NULL;
864 return NULL;
865 }
866
867 if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) {
868
869 _cmsFree(self ->ContextID, BinData);
870 return NULL;
871 }
872
873 *nItems = 1;
874
875 return (void*) BinData;
876 }
877
878
879 static
880 cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
881 {
882 cmsICCData* BinData = (cmsICCData*) Ptr;
883
884 cmsUNUSED_PARAMETER(nItems);
885 cmsUNUSED_PARAMETER(self);
886
887 if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE;
888
889 return io ->Write(io, BinData ->len, BinData ->data);
890
891 }
892
893
894 static
895 void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
896 {
897 cmsICCData* BinData = (cmsICCData*) Ptr;
898
899 cmsUNUSED_PARAMETER(n);
900
901 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1);
902
903 }
904
905 static
906 void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr)
907 {
908 _cmsFree(self ->ContextID, Ptr);
909 }
910
911 // ********************************************************************************
912 // Type cmsSigTextDescriptionType
913 // ********************************************************************************
914
915 static
916 void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
917 {
918 char* Text = NULL;
919 cmsMLU* mlu = NULL;
920 cmsUInt32Number AsciiCount;
921 cmsUInt32Number i, UnicodeCode, UnicodeCount;
922 cmsUInt16Number ScriptCodeCode, Dummy;
1061 // takes 70 bytes, so we need 2 extra bytes to do the alignment
1062
1063 if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error;
1064
1065 // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
1066 if (!_cmsWriteWCharArray(io, len, Wide)) goto Error;
1067 if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error;
1068
1069 // ScriptCode Code & count (unused)
1070 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
1071 if (!_cmsWriteUInt8Number(io, 0)) goto Error;
1072
1073 if (!io ->Write(io, 67, Filler)) goto Error;
1074
1075 rc = TRUE;
1076
1077 Error:
1078 if (Text) _cmsFree(self ->ContextID, Text);
1079 if (Wide) _cmsFree(self ->ContextID, Wide);
1080
1081 cmsUNUSED_PARAMETER(nItems);
1082
1083 return rc;
1084
1085 }
1086
1087
1088 static
1089 void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1090 {
1091 cmsUNUSED_PARAMETER(n);
1092 cmsUNUSED_PARAMETER(self);
1093
1094 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1095
1096 }
1097
1098 static
1099 void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr)
1100 {
1101 cmsMLU* mlu = (cmsMLU*) Ptr;
1102
1103 cmsMLUfree(mlu);
1104 cmsUNUSED_PARAMETER(self);
1105
1106 return;
1107
1108 }
1109
1110
1111 static
1112 cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data)
1113 {
1114 cmsUNUSED_PARAMETER(Data);
1115
1116 if (ICCVersion >= 4.0)
1117 return cmsSigMultiLocalizedUnicodeType;
1118
1119 return cmsSigTextDescriptionType;
1120
1121 }
1122
1123
1124 // ********************************************************************************
1125 // Type cmsSigCurveType
1126 // ********************************************************************************
1127
1128 static
1129 void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1130 {
1131 cmsUInt32Number Count;
1132 cmsToneCurve* NewGamma;
1133
1134 *nItems = 0;
1135 cmsUNUSED_PARAMETER(SizeOfTag);
1136
1137 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1138
1139 switch (Count) {
1140
1141 case 0: // Linear.
1142 {
1143 cmsFloat64Number SingleGamma = 1.0;
1144
1145 NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1146 if (!NewGamma) return NULL;
1147 *nItems = 1;
1148 return NewGamma;
1149 }
1150
1151 case 1: // Specified as the exponent of gamma function
1152 {
1153 cmsUInt16Number SingleGammaFixed;
1154 cmsFloat64Number SingleGamma;
1155
1156 if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL;
1157 SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed);
1158
1159 *nItems = 1;
1160 return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1161 }
1162
1163 default: // Curve
1164
1165 if (Count > 0x7FFF)
1166 return NULL; // This is to prevent bad guys for doing bad things
1167
1168 NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
1169 if (!NewGamma) return NULL;
1170
1171 if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL;
1172
1173 *nItems = 1;
1174 return NewGamma;
1175 }
1176
1177 }
1178
1179
1180 static
1181 cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1182 {
1183 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1184
1185 cmsUNUSED_PARAMETER(nItems);
1186 cmsUNUSED_PARAMETER(self);
1187
1188 if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) {
1189
1190 // Single gamma, preserve number
1191 cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]);
1192
1193 if (!_cmsWriteUInt32Number(io, 1)) return FALSE;
1194 if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE;
1195 return TRUE;
1196
1197 }
1198
1199 if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE;
1200 return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16);
1201
1202 }
1203
1204
1205 static
1206 void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1207 {
1208 cmsUNUSED_PARAMETER(n);
1209 cmsUNUSED_PARAMETER(self);
1210
1211 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1212
1213 }
1214
1215 static
1216 void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1217 {
1218 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1219
1220 cmsFreeToneCurve(gamma);
1221 cmsUNUSED_PARAMETER(self);
1222
1223 return;
1224
1225 }
1226
1227
1228 // ********************************************************************************
1229 // Type cmsSigParametricCurveType
1230 // ********************************************************************************
1231
1232
1233 // Decide which curve type to use on writting
1234 static
1235 cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data)
1236 {
1237 cmsToneCurve* Curve = (cmsToneCurve*) Data;
1238
1239 if (ICCVersion < 4.0) return cmsSigCurveType;
1240 if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric
1241 if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves
1242 if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves
1243
1244 return cmsSigParametricCurveType;
1245 }
1246
1247 static
1248 void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1249 {
1250 static const int ParamsByType[] = { 1, 3, 4, 5, 7 };
1251 cmsFloat64Number Params[10];
1252 cmsUInt16Number Type;
1253 int i, n;
1254 cmsToneCurve* NewGamma;
1255
1256 cmsUNUSED_PARAMETER(SizeOfTag);
1257
1258 if (!_cmsReadUInt16Number(io, &Type)) return NULL;
1259 if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved
1260
1261 if (Type > 4) {
1262
1263 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type);
1264 return NULL;
1265 }
1266
1267 memset(Params, 0, sizeof(Params));
1268 n = ParamsByType[Type];
1269
1270 for (i=0; i < n; i++) {
1271
1272 if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL;
1273 }
1274
1275 NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params);
1276
1277 *nItems = 1;
1278
1279 return NewGamma;
1280
1281 }
1282
1283
1284 static
1285 cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1286 {
1287 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1288 int i, nParams, typen;
1289 static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
1290
1291 typen = Curve -> Segments[0].Type;
1292
1293 cmsUNUSED_PARAMETER(nItems);
1294
1295 if (Curve ->nSegments > 1 || typen < 1) {
1296
1297 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written");
1298 return FALSE;
1299 }
1300
1301 if (typen > 5) {
1302 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve");
1303 return FALSE;
1304 }
1305
1306 nParams = ParamsByType[typen];
1307
1308 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE;
1309 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved
1310
1311 for (i=0; i < nParams; i++) {
1312
1313 if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE;
1314 }
1315
1316 return TRUE;
1317
1318 }
1319
1320 static
1321 void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1322 {
1323 cmsUNUSED_PARAMETER(n);
1324 cmsUNUSED_PARAMETER(self);
1325
1326 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1327
1328 }
1329
1330 static
1331 void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1332 {
1333 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1334
1335 cmsFreeToneCurve(gamma);
1336 cmsUNUSED_PARAMETER(self);
1337
1338 return;
1339
1340 }
1341
1342
1343 // ********************************************************************************
1344 // Type cmsSigDateTimeType
1345 // ********************************************************************************
1346
1347 // A 12-byte value representation of the time and date, where the byte usage is assigned
1348 // as specified in table 1. The actual values are encoded as 16-bit unsigned integers
1349 // (uInt16Number - see 5.1.6).
1350 //
1351 // All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
1352 // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
1353 // time to UTC when setting these values. Programmes that display these values may show
1354 // the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
1355 // display both UTC and local versions of the dateTimeNumber.
1356
1357 static
1358 void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1359 {
1360 cmsDateTimeNumber timestamp;
1361 struct tm * NewDateTime;
1362
1363 *nItems = 0;
1364 NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm));
1365 cmsUNUSED_PARAMETER(SizeOfTag);
1366
1367 if (NewDateTime == NULL) return NULL;
1368
1369 if (io->Read(io, ×tamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL;
1370
1371 _cmsDecodeDateTimeNumber(×tamp, NewDateTime);
1372
1373 *nItems = 1;
1374 return NewDateTime;
1375
1376 }
1377
1378
1379 static
1380 cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1381 {
1382 struct tm * DateTime = (struct tm*) Ptr;
1383 cmsDateTimeNumber timestamp;
1384
1385 _cmsEncodeDateTimeNumber(×tamp, DateTime);
1386 cmsUNUSED_PARAMETER(nItems);
1387 cmsUNUSED_PARAMETER(self);
1388
1389 if (!io ->Write(io, sizeof(cmsDateTimeNumber), ×tamp)) return FALSE;
1390
1391 return TRUE;
1392
1393 }
1394
1395 static
1396 void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1397 {
1398 cmsUNUSED_PARAMETER(n);
1399
1400 return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm));
1401
1402 }
1403
1404 static
1405 void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr)
1406 {
1407 _cmsFree(self ->ContextID, Ptr);
1408 }
1409
1410
1411
1412 // ********************************************************************************
1413 // Type icMeasurementType
1414 // ********************************************************************************
1415
1416 /*
1417 The measurementType information refers only to the internal profile data and is
1418 meant to provide profile makers an alternative to the default measurement
1419 specifications.
1420 */
1421
1422 static
1423 void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1424 {
1425 cmsICCMeasurementConditions mc;
1426
1427
1428 memset(&mc, 0, sizeof(mc));
1429
1430 cmsUNUSED_PARAMETER(SizeOfTag);
1431
1432 if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
1433 if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL;
1434 if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
1435 if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL;
1436 if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL;
1437
1438 *nItems = 1;
1439 return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions));
1440
1441 }
1442
1443
1444 static
1445 cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1446 {
1447 cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr;
1448
1449 cmsUNUSED_PARAMETER(nItems);
1450 cmsUNUSED_PARAMETER(self);
1451
1452 if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE;
1453 if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE;
1454 if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE;
1455 if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE;
1456 if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE;
1457
1458 return TRUE;
1459
1460 }
1461
1462 static
1463 void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1464 {
1465 cmsUNUSED_PARAMETER(n);
1466
1467 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions));
1468
1469 }
1470
1471 static
1472 void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr)
1473 {
1474 _cmsFree(self ->ContextID, Ptr);
1475 }
1476
1477
1478 // ********************************************************************************
1479 // Type cmsSigMultiLocalizedUnicodeType
1480 // ********************************************************************************
1481 //
1482 // Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
1483 // Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
1484 // taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
1485 //
1486
1487 static
1488 void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1557 mlu ->MemPool = Block;
1558 mlu ->PoolSize = SizeOfTag;
1559 mlu ->PoolUsed = SizeOfTag;
1560
1561 *nItems = 1;
1562 return (void*) mlu;
1563
1564 Error:
1565 if (mlu) cmsMLUfree(mlu);
1566 return NULL;
1567 }
1568
1569 static
1570 cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1571 {
1572 cmsMLU* mlu =(cmsMLU*) Ptr;
1573 cmsUInt32Number HeaderSize;
1574 cmsUInt32Number Len, Offset;
1575 int i;
1576
1577 cmsUNUSED_PARAMETER(nItems);
1578 cmsUNUSED_PARAMETER(self);
1579 if (Ptr == NULL) {
1580
1581 // Empty placeholder
1582 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
1583 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1584 return TRUE;
1585 }
1586
1587 if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
1588 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1589
1590 HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
1591
1592 for (i=0; i < mlu ->UsedEntries; i++) {
1593
1594 Len = mlu ->Entries[i].Len;
1595 Offset = mlu ->Entries[i].StrW;
1596
1597 Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
1598 Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8;
1599
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;
1604 }
1605
1606 if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE;
1607
1608 return TRUE;
1609
1610 }
1611
1612
1613 static
1614 void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1615 {
1616 cmsUNUSED_PARAMETER(n);
1617 cmsUNUSED_PARAMETER(self);
1618
1619 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1620
1621 }
1622
1623 static
1624 void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr)
1625 {
1626 cmsMLUfree((cmsMLU*) Ptr);
1627 cmsUNUSED_PARAMETER(self);
1628
1629 return;
1630
1631 }
1632
1633
1634 // ********************************************************************************
1635 // Type cmsSigLut8Type
1636 // ********************************************************************************
1637
1638 // Decide which LUT type to use on writting
1639 static
1640 cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data)
1641 {
1642 cmsPipeline* Lut = (cmsPipeline*) Data;
1643
1644 if (ICCVersion < 4.0) {
1645 if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1646 return cmsSigLut16Type;
1647 }
1648 else {
1649 return cmsSigLutAtoBType;
1650 }
1875
1876 *PtrW++ = FROM_8_TO_16(Temp[i]);
1877 }
1878 _cmsFree(self ->ContextID, Temp);
1879 Temp = NULL;
1880
1881 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T)))
1882 goto Error;
1883 _cmsFree(self ->ContextID, T);
1884 }
1885
1886
1887 // Get output tables
1888 if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error;
1889
1890 *nItems = 1;
1891 return NewLUT;
1892
1893 Error:
1894 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
1895 cmsUNUSED_PARAMETER(SizeOfTag);
1896
1897 return NULL;
1898
1899 }
1900
1901 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1902 static
1903 cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1904 {
1905 cmsUInt32Number j, nTabSize;
1906 cmsUInt8Number val;
1907 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
1908 cmsStage* mpe;
1909 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
1910 _cmsStageMatrixData* MatMPE = NULL;
1911 _cmsStageCLutData* clut = NULL;
1912 int clutPoints;
1913
1914 // Disassemble the LUT into components.
1915 mpe = NewLUT -> Elements;
1916 if (mpe ->Type == cmsSigMatrixElemType) {
1917
1918 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
1979 }
1980
1981 // The prelinearization table
1982 if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
1983
1984 nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
1985 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
1986 if (nTabSize > 0) {
1987
1988 // The 3D CLUT.
1989 if (clut != NULL) {
1990
1991 for (j=0; j < nTabSize; j++) {
1992
1993 val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
1994 if (!_cmsWriteUInt8Number(io, val)) return FALSE;
1995 }
1996 }
1997 }
1998
1999 cmsUNUSED_PARAMETER(nItems);
2000 // The postlinearization table
2001 if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE;
2002
2003 return TRUE;
2004
2005 }
2006
2007
2008 static
2009 void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2010 {
2011 cmsUNUSED_PARAMETER(n);
2012 cmsUNUSED_PARAMETER(self);
2013
2014 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2015
2016 }
2017
2018 static
2019 void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
2020 {
2021 cmsPipelineFree((cmsPipeline*) Ptr);
2022 cmsUNUSED_PARAMETER(self);
2023
2024 return;
2025
2026 }
2027
2028 // ********************************************************************************
2029 // Type cmsSigLut16Type
2030 // ********************************************************************************
2031
2032 // Read 16 bit tables as gamma functions
2033 static
2034 cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries)
2035 {
2036 int i;
2037 cmsToneCurve* Tables[cmsMAXCHANNELS];
2038
2039 // Maybe an empty table? (this is a lcms extension)
2040 if (nEntries <= 0) return TRUE;
2041
2042 // Check for malicious profiles
2043 if (nEntries < 2) return FALSE;
2044 if (nChannels > cmsMAXCHANNELS) return FALSE;
2045
2067 Error:
2068 for (i=0; i < nChannels; i++) {
2069 if (Tables[i]) cmsFreeToneCurve(Tables[i]);
2070 }
2071
2072 return FALSE;
2073 }
2074
2075 static
2076 cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables)
2077 {
2078 int j;
2079 cmsUInt32Number i;
2080 cmsUInt16Number val;
2081 int nEntries;
2082
2083 _cmsAssert(Tables != NULL);
2084
2085 nEntries = Tables->TheCurves[0]->nEntries;
2086
2087 cmsUNUSED_PARAMETER(ContextID);
2088 for (i=0; i < Tables ->nCurves; i++) {
2089
2090 for (j=0; j < nEntries; j++) {
2091
2092 val = Tables->TheCurves[i]->Table16[j];
2093 if (!_cmsWriteUInt16Number(io, val)) return FALSE;
2094 }
2095 }
2096 return TRUE;
2097
2098 }
2099
2100 static
2101 void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2102 {
2103 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
2104 cmsPipeline* NewLUT = NULL;
2105 cmsUInt32Number nTabSize;
2106 cmsFloat64Number Matrix[3*3];
2107 cmsUInt16Number InputEntries, OutputEntries;
2108
2109 *nItems = 0;
2110
2111 if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL;
2112 if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL;
2113 if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum
2114
2115 // Padding
2116 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2117
2165 _cmsFree(self ->ContextID, T);
2166 goto Error;
2167 }
2168
2169 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) {
2170 _cmsFree(self ->ContextID, T);
2171 goto Error;
2172 }
2173 _cmsFree(self ->ContextID, T);
2174 }
2175
2176
2177 // Get output tables
2178 if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error;
2179
2180 *nItems = 1;
2181 return NewLUT;
2182
2183 Error:
2184 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
2185 cmsUNUSED_PARAMETER(SizeOfTag);
2186
2187 return NULL;
2188
2189 }
2190
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
2193
2194 static
2195 cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2196 {
2197 cmsUInt32Number nTabSize;
2198 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
2199 cmsStage* mpe;
2200 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
2201 _cmsStageMatrixData* MatMPE = NULL;
2202 _cmsStageCLutData* clut = NULL;
2203 int i, InputChannels, OutputChannels, clutPoints;
2204
2205 // Disassemble the LUT into components.
2206 mpe = NewLUT -> Elements;
2207 if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
2208
2302 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
2303 if (nTabSize > 0) {
2304 // The 3D CLUT.
2305 if (clut != NULL) {
2306 if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
2307 }
2308 }
2309
2310 // The postlinearization table
2311 if (PostMPE != NULL) {
2312 if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE;
2313 }
2314 else {
2315 for (i=0; i < OutputChannels; i++) {
2316
2317 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2318 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
2319 }
2320 }
2321
2322 cmsUNUSED_PARAMETER(nItems);
2323 return TRUE;
2324
2325 }
2326
2327 static
2328 void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2329 {
2330 cmsUNUSED_PARAMETER(n);
2331 cmsUNUSED_PARAMETER(self);
2332
2333 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2334
2335 }
2336
2337 static
2338 void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr)
2339 {
2340 cmsPipelineFree((cmsPipeline*) Ptr);
2341 cmsUNUSED_PARAMETER(self);
2342
2343 return;
2344
2345 }
2346
2347
2348 // ********************************************************************************
2349 // Type cmsSigLutAToBType
2350 // ********************************************************************************
2351
2352
2353 // V4 stuff. Read matrix for LutAtoB and LutBtoA
2354
2355 static
2356 cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset)
2357 {
2358 cmsFloat64Number dMat[3*3];
2359 cmsFloat64Number dOff[3];
2360 cmsStage* Mat;
2361
2362 // Go to address
2363 if (!io -> Seek(io, Offset)) return NULL;
2364
2570
2571 if (offsetM != 0) {
2572 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan)))
2573 goto Error;
2574 }
2575
2576 if (offsetMat != 0) {
2577 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
2578 goto Error;
2579 }
2580
2581 if (offsetB != 0) {
2582 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
2583 goto Error;
2584 }
2585
2586 *nItems = 1;
2587 return NewLUT;
2588 Error:
2589 cmsPipelineFree(NewLUT);
2590 cmsUNUSED_PARAMETER(SizeOfTag);
2591 return NULL;
2592
2593 }
2594
2595 // Write a set of curves
2596 static
2597 cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
2598 {
2599 _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
2600
2601 // Write the Matrix
2602 if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE;
2603 if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE;
2604 if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE;
2605 if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE;
2606 if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE;
2607 if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE;
2608 if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE;
2609 if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE;
2610 if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE;
2611
2612 if (m ->Offset != NULL) {
2613
2614 if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE;
2615 if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE;
2616 if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE;
2617 }
2618 else {
2619 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2620 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2621 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2622
2623 }
2624
2625
2626 cmsUNUSED_PARAMETER(self);
2627 return TRUE;
2628
2629 }
2630
2631
2632 // Write a set of curves
2633 static
2634 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
2635 {
2636 cmsUInt32Number i, n;
2637 cmsTagTypeSignature CurrentType;
2638 cmsToneCurve** Curves;
2639
2640
2641 n = cmsStageOutputChannels(mpe);
2642 Curves = _cmsStageGetPtrToCurveSet(mpe);
2643
2644 for (i=0; i < n; i++) {
2645
2646 // If this is a table-based curve, use curve type even on V4
2647 CurrentType = Type;
2648
2799 }
2800
2801 if (B != NULL) {
2802
2803 offsetB = io ->Tell(io) - BaseOffset;
2804 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2805 }
2806
2807 CurrentPos = io ->Tell(io);
2808
2809 if (!io ->Seek(io, DirectoryPos)) return FALSE;
2810
2811 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2812 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2813 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2814 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2815 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2816
2817 if (!io ->Seek(io, CurrentPos)) return FALSE;
2818
2819 cmsUNUSED_PARAMETER(nItems);
2820 return TRUE;
2821
2822 }
2823
2824
2825 static
2826 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2827 {
2828 cmsUNUSED_PARAMETER(n);
2829 cmsUNUSED_PARAMETER(self);
2830
2831 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2832
2833 }
2834
2835 static
2836 void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr)
2837 {
2838 cmsPipelineFree((cmsPipeline*) Ptr);
2839 cmsUNUSED_PARAMETER(self);
2840
2841 return;
2842
2843 }
2844
2845
2846 // LutBToA type
2847
2848 static
2849 void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2850 {
2851 cmsUInt8Number inputChan; // Number of input channels
2852 cmsUInt8Number outputChan; // Number of output channels
2853 cmsUInt32Number BaseOffset; // Actual position in file
2854 cmsUInt32Number offsetB; // Offset to first "B" curve
2855 cmsUInt32Number offsetMat; // Offset to matrix
2856 cmsUInt32Number offsetM; // Offset to first "M" curve
2857 cmsUInt32Number offsetC; // Offset to CLUT
2858 cmsUInt32Number offsetA; // Offset to first "A" curve
2859 cmsPipeline* NewLUT = NULL;
2860
2861
2862 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2889
2890 if (offsetM != 0) {
2891 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan)))
2892 goto Error;
2893 }
2894
2895 if (offsetC != 0) {
2896 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
2897 goto Error;
2898 }
2899
2900 if (offsetA!= 0) {
2901 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan)))
2902 goto Error;
2903 }
2904
2905 *nItems = 1;
2906 return NewLUT;
2907 Error:
2908 cmsPipelineFree(NewLUT);
2909 cmsUNUSED_PARAMETER(SizeOfTag);
2910
2911 return NULL;
2912
2913 }
2914
2915
2916 /*
2917 B
2918 B - Matrix - M
2919 B - CLUT - A
2920 B - Matrix - M - CLUT - A
2921 */
2922
2923 static
2924 cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2925 {
2926 cmsPipeline* Lut = (cmsPipeline*) Ptr;
2927 int inputChan, outputChan;
2928 cmsStage *A = NULL, *B = NULL, *M = NULL;
2929 cmsStage *Matrix = NULL;
2930 cmsStage *CLUT = NULL;
2931 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2932 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2981 }
2982
2983 if (B != NULL) {
2984
2985 offsetB = io ->Tell(io) - BaseOffset;
2986 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2987 }
2988
2989 CurrentPos = io ->Tell(io);
2990
2991 if (!io ->Seek(io, DirectoryPos)) return FALSE;
2992
2993 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2994 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2995 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2996 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2997 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2998
2999 if (!io ->Seek(io, CurrentPos)) return FALSE;
3000
3001 cmsUNUSED_PARAMETER(nItems);
3002
3003 return TRUE;
3004
3005 }
3006
3007
3008
3009 static
3010 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3011 {
3012 cmsUNUSED_PARAMETER(n);
3013 cmsUNUSED_PARAMETER(self);
3014
3015 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
3016
3017 }
3018
3019 static
3020 void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr)
3021 {
3022 cmsPipelineFree((cmsPipeline*) Ptr);
3023 cmsUNUSED_PARAMETER(self);
3024
3025 return;
3026
3027 }
3028
3029
3030
3031 // ********************************************************************************
3032 // Type cmsSigColorantTableType
3033 // ********************************************************************************
3034 /*
3035 The purpose of this tag is to identify the colorants used in the profile by a
3036 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
3037 value. The first colorant listed is the colorant of the first device channel of
3038 a lut tag. The second colorant listed is the colorant of the second device channel
3039 of a lut tag, and so on.
3040 */
3041
3042 static
3043 void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3044 {
3045 cmsUInt32Number i, Count;
3046 cmsNAMEDCOLORLIST* List;
3056 }
3057
3058 List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", "");
3059 for (i=0; i < Count; i++) {
3060
3061 if (io ->Read(io, Name, 32, 1) != 1) goto Error;
3062 Name[33] = 0;
3063
3064 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3065
3066 if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error;
3067
3068 }
3069
3070 *nItems = 1;
3071 return List;
3072
3073 Error:
3074 *nItems = 0;
3075 cmsFreeNamedColorList(List);
3076 cmsUNUSED_PARAMETER(SizeOfTag);
3077
3078 return NULL;
3079
3080 }
3081
3082
3083
3084 // Saves a colorant table. It is using the named color structure for simplicity sake
3085 static
3086 cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3087 {
3088 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3089 int i, nColors;
3090
3091 nColors = cmsNamedColorCount(NamedColorList);
3092
3093 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3094
3095 for (i=0; i < nColors; i++) {
3096
3097 char root[33];
3098 cmsUInt16Number PCS[3];
3099
3100 if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0;
3101 root[32] = 0;
3102
3103 if (!io ->Write(io, 32, root)) return FALSE;
3104 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3105 }
3106
3107 cmsUNUSED_PARAMETER(nItems);
3108 cmsUNUSED_PARAMETER(self);
3109
3110 return TRUE;
3111
3112 }
3113
3114
3115 static
3116 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3117 {
3118 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3119 cmsUNUSED_PARAMETER(n);
3120 cmsUNUSED_PARAMETER(self);
3121
3122 return (void*) cmsDupNamedColorList(nc);
3123
3124 }
3125
3126
3127 static
3128 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
3129 {
3130 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3131 cmsUNUSED_PARAMETER(self);
3132 return;
3133
3134 }
3135
3136
3137 // ********************************************************************************
3138 // Type cmsSigNamedColor2Type
3139 // ********************************************************************************
3140 //
3141 //The namedColor2Type is a count value and array of structures that provide color
3142 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3143 //device representation of the color are given. Both representations are 16-bit values.
3144 //The device representation corresponds to the header’s “color space of data” field.
3145 //This representation should be consistent with the “number of device components”
3146 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3147 //The PCS representation corresponds to the header’s PCS field. The PCS representation
3148 //is always provided. Color names are fixed-length, 32-byte fields including null
3149 //termination. In order to maintain maximum portability, it is strongly recommended
3150 //that special characters of the 7-bit ASCII set not be used.
3151
3152 static
3153 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3184 }
3185 for (i=0; i < count; i++) {
3186
3187 cmsUInt16Number PCS[3];
3188 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3189 char Root[33];
3190
3191 memset(Colorant, 0, sizeof(Colorant));
3192 if (io -> Read(io, Root, 32, 1) != 1) return NULL;
3193 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3194 if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
3195
3196 if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
3197 }
3198
3199 *nItems = 1;
3200 return (void*) v ;
3201
3202 Error:
3203 cmsFreeNamedColorList(v);
3204 cmsUNUSED_PARAMETER(SizeOfTag);
3205
3206 return NULL;
3207
3208 }
3209
3210
3211 // Saves a named color list into a named color profile
3212 static
3213 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3214 {
3215 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3216 char prefix[32]; // Prefix for each color name
3217 char suffix[32]; // Suffix for each color name
3218 int i, nColors;
3219
3220 nColors = cmsNamedColorCount(NamedColorList);
3221
3222 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
3223 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3224 if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
3225
3226 strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
3227 strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
3228
3229 suffix[31] = prefix[31] = 0;
3230
3231 if (!io ->Write(io, 32, prefix)) return FALSE;
3232 if (!io ->Write(io, 32, suffix)) return FALSE;
3233
3234 for (i=0; i < nColors; i++) {
3235
3236 cmsUInt16Number PCS[3];
3237 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3238 char Root[33];
3239
3240 if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
3241 if (!io ->Write(io, 32 , Root)) return FALSE;
3242 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3243 if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
3244 }
3245
3246 cmsUNUSED_PARAMETER(nItems);
3247 cmsUNUSED_PARAMETER(self);
3248
3249 return TRUE;
3250
3251 }
3252
3253 static
3254 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3255 {
3256 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3257
3258 cmsUNUSED_PARAMETER(n);
3259 cmsUNUSED_PARAMETER(self);
3260
3261 return (void*) cmsDupNamedColorList(nc);
3262
3263 }
3264
3265
3266 static
3267 void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr)
3268 {
3269 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3270 cmsUNUSED_PARAMETER(self);
3271
3272 return;
3273
3274 }
3275
3276
3277 // ********************************************************************************
3278 // Type cmsSigProfileSequenceDescType
3279 // ********************************************************************************
3280
3281 // This type is an array of structures, each of which contains information from the
3282 // header fields and tags from the original profiles which were combined to create
3283 // the final profile. The order of the structures is the order in which the profiles
3284 // were combined and includes a structure for the final profile. This provides a
3285 // description of the profile sequence from source to destination,
3286 // typically used with the DeviceLink profile.
3287
3288 static
3289 cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag)
3290 {
3291 cmsTagTypeSignature BaseType;
3292 cmsUInt32Number nItems;
3293
3394 cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3395 {
3396 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3397 cmsUInt32Number i;
3398
3399 if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE;
3400
3401 for (i=0; i < Seq ->n; i++) {
3402
3403 cmsPSEQDESC* sec = &Seq -> seq[i];
3404
3405 if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE;
3406 if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE;
3407 if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE;
3408 if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE;
3409
3410 if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE;
3411 if (!SaveDescription(self, io, sec ->Model)) return FALSE;
3412 }
3413
3414 cmsUNUSED_PARAMETER(nItems);
3415
3416 return TRUE;
3417
3418 }
3419
3420
3421 static
3422 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3423 {
3424 cmsUNUSED_PARAMETER(n);
3425 cmsUNUSED_PARAMETER(self);
3426
3427 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3428
3429 }
3430
3431 static
3432 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr)
3433 {
3434 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3435 cmsUNUSED_PARAMETER(self);
3436
3437 return;
3438
3439 }
3440
3441
3442 // ********************************************************************************
3443 // Type cmsSigProfileSequenceIdType
3444 // ********************************************************************************
3445 /*
3446 In certain workflows using ICC Device Link Profiles, it is necessary to identify the
3447 original profiles that were combined to create the Device Link Profile.
3448 This type is an array of structures, each of which contains information for
3449 identification of a profile used in a sequence
3450 */
3451
3452
3453 static
3454 cmsBool ReadSeqID(struct _cms_typehandler_struct* self,
3455 cmsIOHANDLER* io,
3456 void* Cargo,
3457 cmsUInt32Number n,
3458 cmsUInt32Number SizeOfTag)
3500 *nItems = 1;
3501 return OutSeq;
3502
3503 }
3504
3505
3506 static
3507 cmsBool WriteSeqID(struct _cms_typehandler_struct* self,
3508 cmsIOHANDLER* io,
3509 void* Cargo,
3510 cmsUInt32Number n,
3511 cmsUInt32Number SizeOfTag)
3512 {
3513 cmsSEQ* Seq = (cmsSEQ*) Cargo;
3514
3515 if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE;
3516
3517 // Store here the MLU
3518 if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE;
3519
3520 cmsUNUSED_PARAMETER(SizeOfTag);
3521
3522 return TRUE;
3523
3524 }
3525
3526 static
3527 cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3528 {
3529 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3530 cmsUInt32Number BaseOffset;
3531
3532 // Keep the base offset
3533 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3534
3535 // This is the table count
3536 if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE;
3537
3538 // This is the position table and content
3539 if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE;
3540
3541 cmsUNUSED_PARAMETER(nItems);
3542
3543 return TRUE;
3544
3545 }
3546
3547 static
3548 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3549 {
3550 cmsUNUSED_PARAMETER(n);
3551 cmsUNUSED_PARAMETER(self);
3552
3553 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3554
3555 }
3556
3557 static
3558 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr)
3559 {
3560 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3561 cmsUNUSED_PARAMETER(self);
3562
3563 return;
3564
3565 }
3566
3567
3568 // ********************************************************************************
3569 // Type cmsSigUcrBgType
3570 // ********************************************************************************
3571 /*
3572 This type contains curves representing the under color removal and black
3573 generation and a text string which is a general description of the method used
3574 for the ucr/bg.
3575 */
3576
3577 static
3578 void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3579 {
3580 cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3581 cmsUInt32Number CountUcr, CountBg;
3582 char* ASCIIString;
3583
3584 *nItems = 0;
3628 cmsUcrBg* Value = (cmsUcrBg*) Ptr;
3629 cmsUInt32Number TextSize;
3630 char* Text;
3631
3632 // First curve is Under color removal
3633 if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE;
3634 if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE;
3635
3636 // Then black generation
3637 if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE;
3638 if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE;
3639
3640 // Now comes the text. The length is specified by the tag size
3641 TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0);
3642 Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
3643 if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE;
3644
3645 if (!io ->Write(io, TextSize, Text)) return FALSE;
3646 _cmsFree(self ->ContextID, Text);
3647
3648 cmsUNUSED_PARAMETER(nItems);
3649
3650 return TRUE;
3651
3652 }
3653
3654 static
3655 void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3656 {
3657 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3658 cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3659
3660 if (NewUcrBg == NULL) return NULL;
3661
3662 NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg);
3663 NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr);
3664 NewUcrBg ->Desc = cmsMLUdup(Src ->Desc);
3665
3666 cmsUNUSED_PARAMETER(n);
3667
3668 return (void*) NewUcrBg;
3669
3670 }
3671
3672 static
3673 void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr)
3674 {
3675 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3676
3677 if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr);
3678 if (Src ->Bg) cmsFreeToneCurve(Src ->Bg);
3679 if (Src ->Desc) cmsMLUfree(Src ->Desc);
3680
3681 _cmsFree(self ->ContextID, Ptr);
3682 }
3683
3684 // ********************************************************************************
3685 // Type cmsSigCrdInfoType
3686 // ********************************************************************************
3687
3688 /*
3689 This type contains the PostScript product name to which this profile corresponds
3769 cmsMLUfree(mlu);
3770 return NULL;
3771
3772 }
3773
3774 static
3775 cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3776 {
3777
3778 cmsMLU* mlu = (cmsMLU*) Ptr;
3779
3780 if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error;
3781 if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error;
3782 if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error;
3783 if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error;
3784 if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error;
3785
3786 return TRUE;
3787
3788 Error:
3789 cmsUNUSED_PARAMETER(nItems);
3790 return FALSE;
3791
3792 }
3793
3794
3795 static
3796 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3797 {
3798 cmsUNUSED_PARAMETER(n);
3799 cmsUNUSED_PARAMETER(self);
3800
3801 return (void*) cmsMLUdup((cmsMLU*) Ptr);
3802
3803 }
3804
3805 static
3806 void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr)
3807 {
3808 cmsMLUfree((cmsMLU*) Ptr);
3809 cmsUNUSED_PARAMETER(self);
3810
3811 return;
3812
3813 }
3814
3815 // ********************************************************************************
3816 // Type cmsSigScreeningType
3817 // ********************************************************************************
3818 //
3819 //The screeningType describes various screening parameters including screen
3820 //frequency, screening angle, and spot shape.
3821
3822 static
3823 void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3824 {
3825 cmsScreening* sc = NULL;
3826 cmsUInt32Number i;
3827
3828 sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening));
3829 if (sc == NULL) return NULL;
3830
3831 *nItems = 0;
3832
3835
3836 if (sc ->nChannels > cmsMAXCHANNELS - 1)
3837 sc ->nChannels = cmsMAXCHANNELS - 1;
3838
3839 for (i=0; i < sc ->nChannels; i++) {
3840
3841 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error;
3842 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error;
3843 if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error;
3844 }
3845
3846
3847 *nItems = 1;
3848
3849 return (void*) sc;
3850
3851 Error:
3852 if (sc != NULL)
3853 _cmsFree(self ->ContextID, sc);
3854
3855 cmsUNUSED_PARAMETER(SizeOfTag);
3856 return NULL;
3857
3858 }
3859
3860
3861 static
3862 cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3863 {
3864 cmsScreening* sc = (cmsScreening* ) Ptr;
3865 cmsUInt32Number i;
3866
3867 if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE;
3868 if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE;
3869
3870 for (i=0; i < sc ->nChannels; i++) {
3871
3872 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE;
3873 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE;
3874 if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE;
3875 }
3876
3877 cmsUNUSED_PARAMETER(nItems);
3878 return TRUE;
3879
3880 }
3881
3882
3883 static
3884 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3885 {
3886 cmsUNUSED_PARAMETER(n);
3887 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3888
3889 }
3890
3891
3892 static
3893 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
3894 {
3895 _cmsFree(self ->ContextID, Ptr);
3896 }
3897
3898 // ********************************************************************************
3899 // Type cmsSigViewingConditionsType
3900 // ********************************************************************************
3901 //
3902 //This type represents a set of viewing condition parameters including:
3903 //CIE ’absolute’ illuminant white point tristimulus values and CIE ’absolute’
3904 //surround tristimulus values.
3905
3906 static
3907 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3908 {
3909 cmsICCViewingConditions* vc = NULL;
3910
3911 vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
3912 if (vc == NULL) return NULL;
3913
3914 *nItems = 0;
3915
3916 if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
3917 if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
3918 if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
3919
3920 *nItems = 1;
3921
3922 return (void*) vc;
3923
3924 Error:
3925 if (vc != NULL)
3926 _cmsFree(self ->ContextID, vc);
3927
3928 cmsUNUSED_PARAMETER(SizeOfTag);
3929 return NULL;
3930
3931 }
3932
3933
3934 static
3935 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3936 {
3937 cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
3938
3939 if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
3940 if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
3941 if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
3942
3943 cmsUNUSED_PARAMETER(nItems);
3944 cmsUNUSED_PARAMETER(self);
3945 return TRUE;
3946
3947 }
3948
3949
3950 static
3951 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3952 {
3953 cmsUNUSED_PARAMETER(n);
3954 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3955
3956 }
3957
3958
3959 static
3960 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
3961 {
3962 _cmsFree(self ->ContextID, Ptr);
3963 }
3964
3965
3966 // ********************************************************************************
3967 // Type cmsSigMultiProcessElementType
3968 // ********************************************************************************
3969
3970
3971 static
3972 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3973 {
3974 cmsUNUSED_PARAMETER(n);
3975 cmsUNUSED_PARAMETER(self);
3976 return (void*) cmsStageDup((cmsStage*) Ptr);
3977
3978 }
3979
3980 static
3981 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
3982 {
3983 cmsStageFree((cmsStage*) Ptr);
3984 cmsUNUSED_PARAMETER(self);
3985 return;
3986
3987 }
3988
3989 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
3990 // The first curve segment always starts at –Infinity, and the last curve segment always ends at +Infinity. The
3991 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
3992 // specified either in terms of a formula, or by a sampled curve.
3993
3994
3995 // Read an embedded segmented curve
3996 static
3997 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
3998 {
3999 cmsCurveSegSignature ElementSig;
4000 cmsUInt32Number i, j;
4001 cmsUInt16Number nSegments;
4002 cmsCurveSegment* Segments;
4003 cmsToneCurve* Curve;
4004 cmsFloat32Number PrevBreak = -1E22F; // - infinite
4005
4006 // Take signature and channels for each element.
4091 }
4092 _cmsFree(self ->ContextID, Segments);
4093 return Curve;
4094
4095 Error:
4096 if (Segments) _cmsFree(self ->ContextID, Segments);
4097 return NULL;
4098 }
4099
4100
4101 static
4102 cmsBool ReadMPECurve(struct _cms_typehandler_struct* self,
4103 cmsIOHANDLER* io,
4104 void* Cargo,
4105 cmsUInt32Number n,
4106 cmsUInt32Number SizeOfTag)
4107 {
4108 cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo;
4109
4110 GammaTables[n] = ReadSegmentedCurve(self, io);
4111 cmsUNUSED_PARAMETER(SizeOfTag);
4112 return (GammaTables[n] != NULL);
4113
4114 }
4115
4116 static
4117 void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4118 {
4119 cmsStage* mpe = NULL;
4120 cmsUInt16Number InputChans, OutputChans;
4121 cmsUInt32Number i, BaseOffset;
4122 cmsToneCurve** GammaTables;
4123
4124 *nItems = 0;
4125
4126 // Get actual position as a basis for element offsets
4127 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4128
4129 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4130 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4131
4132 if (InputChans != OutputChans) return NULL;
4133
4134 GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*));
4135 if (GammaTables == NULL) return NULL;
4136
4137 if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) {
4138
4139 mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables);
4140 }
4141 else {
4142 mpe = NULL;
4143 }
4144
4145 for (i=0; i < InputChans; i++) {
4146 if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]);
4147 }
4148
4149 _cmsFree(self ->ContextID, GammaTables);
4150 *nItems = (mpe != NULL) ? 1 : 0;
4151 cmsUNUSED_PARAMETER(SizeOfTag);
4152 return mpe;
4153
4154 }
4155
4156
4157 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
4158 static
4159 cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g)
4160 {
4161 cmsUInt32Number i, j;
4162 cmsCurveSegment* Segments = g ->Segments;
4163 cmsUInt32Number nSegments = g ->nSegments;
4164
4165 if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error;
4166 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4167 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error;
4168 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4169
4170 // Write the break-points
4171 for (i=0; i < nSegments - 1; i++) {
4172 if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error;
4173 }
4212 // It seems there is no need to align. Code is here, and for safety commented out
4213 // if (!_cmsWriteAlignment(io)) goto Error;
4214 }
4215
4216 return TRUE;
4217
4218 Error:
4219 return FALSE;
4220 }
4221
4222
4223 static
4224 cmsBool WriteMPECurve(struct _cms_typehandler_struct* self,
4225 cmsIOHANDLER* io,
4226 void* Cargo,
4227 cmsUInt32Number n,
4228 cmsUInt32Number SizeOfTag)
4229 {
4230 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo;
4231
4232 cmsUNUSED_PARAMETER(SizeOfTag);
4233 cmsUNUSED_PARAMETER(self);
4234 return WriteSegmentedCurve(io, Curves ->TheCurves[n]);
4235
4236 }
4237
4238 // Write a curve, checking first for validity
4239 static
4240 cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4241 {
4242 cmsUInt32Number BaseOffset;
4243 cmsStage* mpe = (cmsStage*) Ptr;
4244 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data;
4245
4246 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4247
4248 // Write the header. Since those are curves, input and output channels are same
4249 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4250 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4251
4252 if (!WritePositionTable(self, io, 0,
4253 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
4254
4255
4256 cmsUNUSED_PARAMETER(nItems);
4257 return TRUE;
4258
4259 }
4260
4261
4262
4263 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4264 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4265 // is organized as follows:
4266 // array = [e11, e12, …, e1P, e21, e22, …, e2P, …, eQ1, eQ2, …, eQP, e1, e2, …, eQ]
4267
4268 static
4269 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4270 {
4271 cmsStage* mpe;
4272 cmsUInt16Number InputChans, OutputChans;
4273 cmsUInt32Number nElems, i;
4274 cmsFloat64Number* Matrix;
4275 cmsFloat64Number* Offsets;
4276
4277 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4278 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4298 if (!_cmsReadFloat32Number(io, &v)) return NULL;
4299 Matrix[i] = v;
4300 }
4301
4302
4303 for (i=0; i < OutputChans; i++) {
4304
4305 cmsFloat32Number v;
4306
4307 if (!_cmsReadFloat32Number(io, &v)) return NULL;
4308 Offsets[i] = v;
4309 }
4310
4311
4312 mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets);
4313 _cmsFree(self ->ContextID, Matrix);
4314 _cmsFree(self ->ContextID, Offsets);
4315
4316 *nItems = 1;
4317
4318 cmsUNUSED_PARAMETER(SizeOfTag);
4319 return mpe;
4320
4321 }
4322
4323 static
4324 cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4325 {
4326 cmsUInt32Number i, nElems;
4327 cmsStage* mpe = (cmsStage*) Ptr;
4328 _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data;
4329
4330 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4331 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4332
4333 nElems = mpe ->InputChannels * mpe ->OutputChannels;
4334
4335 for (i=0; i < nElems; i++) {
4336 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE;
4337 }
4338
4339
4340 for (i=0; i < mpe ->OutputChannels; i++) {
4341
4342 if (Matrix ->Offset == NULL) {
4343
4344 if (!_cmsWriteFloat32Number(io, 0)) return FALSE;
4345 }
4346 else {
4347 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE;
4348 }
4349 }
4350
4351 cmsUNUSED_PARAMETER(nItems);
4352 cmsUNUSED_PARAMETER(self);
4353 return TRUE;
4354
4355 }
4356
4357
4358
4359 static
4360 void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4361 {
4362 cmsStage* mpe = NULL;
4363 cmsUInt16Number InputChans, OutputChans;
4364 cmsUInt8Number Dimensions8[16];
4365 cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS];
4366 _cmsStageCLutData* clut;
4367
4368 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4369 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4370
4371 if (InputChans == 0) goto Error;
4372 if (OutputChans == 0) goto Error;
4373
4374 if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
4378 nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans;
4379 for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i];
4380
4381 // Allocate the true CLUT
4382 mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
4383 if (mpe == NULL) goto Error;
4384
4385 // Read the data
4386 clut = (_cmsStageCLutData*) mpe ->Data;
4387 for (i=0; i < clut ->nEntries; i++) {
4388
4389 if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
4390 }
4391
4392 *nItems = 1;
4393 return mpe;
4394
4395 Error:
4396 *nItems = 0;
4397 if (mpe != NULL) cmsStageFree(mpe);
4398 cmsUNUSED_PARAMETER(SizeOfTag);
4399 return NULL;
4400
4401 }
4402
4403 // Write a CLUT in floating point
4404 static
4405 cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4406 {
4407 cmsUInt8Number Dimensions8[16];
4408 cmsUInt32Number i;
4409 cmsStage* mpe = (cmsStage*) Ptr;
4410 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
4411
4412 // Check for maximum number of channels
4413 if (mpe -> InputChannels > 15) return FALSE;
4414
4415 // Only floats are supported in MPE
4416 if (clut ->HasFloatValues == FALSE) return FALSE;
4417
4418 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4419 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4420
4421 memset(Dimensions8, 0, sizeof(Dimensions8));
4422
4423 for (i=0; i < mpe ->InputChannels; i++)
4424 Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
4425
4426 if (!io ->Write(io, 16, Dimensions8)) return FALSE;
4427
4428 for (i=0; i < clut ->nEntries; i++) {
4429
4430 if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
4431 }
4432
4433 cmsUNUSED_PARAMETER(nItems);
4434 cmsUNUSED_PARAMETER(self);
4435 return TRUE;
4436
4437 }
4438
4439
4440
4441 // This is the list of built-in MPE types
4442 static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
4443
4444 {{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now
4445 {{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says)
4446
4447 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] },
4448 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] },
4449 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL },
4450 };
4451
4452 _cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL };
4453
4454 static
4455 cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
4456 cmsIOHANDLER* io,
4476 if (TypeHandler == NULL) {
4477
4478 char String[5];
4479
4480 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4481
4482 // An unknown element was found.
4483 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String);
4484 return FALSE;
4485 }
4486
4487 // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
4488 // Read the MPE. No size is given
4489 if (TypeHandler ->ReadPtr != NULL) {
4490
4491 // This is a real element which should be read and processed
4492 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag)))
4493 return FALSE;
4494 }
4495
4496 cmsUNUSED_PARAMETER(SizeOfTag);
4497 cmsUNUSED_PARAMETER(n);
4498 return TRUE;
4499
4500 }
4501
4502
4503 // This is the main dispatcher for MPE
4504 static
4505 void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4506 {
4507 cmsUInt16Number InputChans, OutputChans;
4508 cmsUInt32Number ElementCount;
4509 cmsPipeline *NewLUT = NULL;
4510 cmsUInt32Number BaseOffset;
4511
4512 // Get actual position as a basis for element offsets
4513 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4514
4515 // Read channels and element count
4516 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4517 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4518
4519 // Allocates an empty LUT
4520 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
4521 if (NewLUT == NULL) return NULL;
4522
4523 if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL;
4524
4525 if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) {
4526 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
4527 *nItems = 0;
4528 return NULL;
4529 }
4530
4531 // Success
4532 *nItems = 1;
4533 cmsUNUSED_PARAMETER(SizeOfTag);
4534 return NewLUT;
4535
4536 }
4537
4538
4539
4540 // This one is a liitle bit more complex, so we don't use position tables this time.
4541 static
4542 cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4543 {
4544 cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos;
4545 int inputChan, outputChan;
4546 cmsUInt32Number ElemCount;
4547 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before;
4548 cmsStageSignature ElementSig;
4549 cmsPipeline* Lut = (cmsPipeline*) Ptr;
4550 cmsStage* Elem = Lut ->Elements;
4551 cmsTagTypeHandler* TypeHandler;
4552 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
4553
4554 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4555
4608
4609 // Write the directory
4610 CurrentPos = io ->Tell(io);
4611
4612 if (!io ->Seek(io, DirectoryPos)) goto Error;
4613
4614 for (i=0; i < ElemCount; i++) {
4615 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
4616 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
4617 }
4618
4619 if (!io ->Seek(io, CurrentPos)) goto Error;
4620
4621 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4622 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4623 return TRUE;
4624
4625 Error:
4626 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4627 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4628 cmsUNUSED_PARAMETER(nItems);
4629 return FALSE;
4630
4631 }
4632
4633
4634 static
4635 void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4636 {
4637 cmsUNUSED_PARAMETER(n);
4638 cmsUNUSED_PARAMETER(self);
4639
4640 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
4641
4642 }
4643
4644 static
4645 void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr)
4646 {
4647 cmsPipelineFree((cmsPipeline*) Ptr);
4648 cmsUNUSED_PARAMETER(self);
4649 return;
4650
4651 }
4652
4653
4654 // ********************************************************************************
4655 // Type cmsSigVcgtType
4656 // ********************************************************************************
4657
4658
4659 #define cmsVideoCardGammaTableType 0
4660 #define cmsVideoCardGammaFormulaType 1
4661
4662 // Used internally
4663 typedef struct {
4664 double Gamma;
4665 double Min;
4666 double Max;
4667 } _cmsVCGTGAMMA;
4668
4669
4670 static
4781 Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
4782 if (Curves[n] == NULL) goto Error;
4783 }
4784 }
4785 break;
4786
4787 // Unsupported
4788 default:
4789 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
4790 goto Error;
4791 }
4792
4793 *nItems = 1;
4794 return (void*) Curves;
4795
4796 // Regret, free all resources
4797 Error:
4798
4799 cmsFreeToneCurveTriple(Curves);
4800 _cmsFree(self ->ContextID, Curves);
4801 cmsUNUSED_PARAMETER(SizeOfTag);
4802 return NULL;
4803
4804 }
4805
4806
4807 // We don't support all flavors, only 16bits tables and formula
4808 static
4809 cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4810 {
4811 cmsToneCurve** Curves = (cmsToneCurve**) Ptr;
4812 cmsUInt32Number i, j;
4813
4814 if (cmsGetToneCurveParametricType(Curves[0]) == 5 &&
4815 cmsGetToneCurveParametricType(Curves[1]) == 5 &&
4816 cmsGetToneCurveParametricType(Curves[2]) == 5) {
4817
4818 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
4819
4820 // Save parameters
4821 for (i=0; i < 3; i++) {
4822
4823 _cmsVCGTGAMMA v;
4834
4835 else {
4836
4837 // Always store as a table of 256 words
4838 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE;
4839 if (!_cmsWriteUInt16Number(io, 3)) return FALSE;
4840 if (!_cmsWriteUInt16Number(io, 256)) return FALSE;
4841 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
4842
4843 for (i=0; i < 3; i++) {
4844 for (j=0; j < 256; j++) {
4845
4846 cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0));
4847 cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0);
4848
4849 if (!_cmsWriteUInt16Number(io, n)) return FALSE;
4850 }
4851 }
4852 }
4853
4854 cmsUNUSED_PARAMETER(self);
4855 cmsUNUSED_PARAMETER(nItems);
4856 return TRUE;
4857
4858 }
4859
4860 static
4861 void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4862 {
4863 cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr;
4864 cmsToneCurve** NewCurves;
4865
4866 NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4867 if (NewCurves == NULL) return NULL;
4868
4869 NewCurves[0] = cmsDupToneCurve(OldCurves[0]);
4870 NewCurves[1] = cmsDupToneCurve(OldCurves[1]);
4871 NewCurves[2] = cmsDupToneCurve(OldCurves[2]);
4872
4873 cmsUNUSED_PARAMETER(n);
4874 return (void*) NewCurves;
4875
4876 }
4877
4878
4879 static
4880 void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr)
4881 {
4882 cmsFreeToneCurveTriple((cmsToneCurve**) Ptr);
4883 _cmsFree(self ->ContextID, Ptr);
4884 }
4885
4886
4887 // ********************************************************************************
4888 // Type cmsSigDictType
4889 // ********************************************************************************
4890
4891 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data
4892 typedef struct {
4893 cmsContext ContextID;
4894 cmsUInt32Number *Offsets;
4895 cmsUInt32Number *Sizes;
5279 if (p ->DisplayValue != NULL) {
5280 if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error;
5281 }
5282
5283 p = cmsDictNextEntry(p);
5284 }
5285
5286 // Write the directory
5287 CurrentPos = io ->Tell(io);
5288 if (!io ->Seek(io, DirectoryPos)) goto Error;
5289
5290 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5291
5292 if (!io ->Seek(io, CurrentPos)) goto Error;
5293
5294 FreeArray(&a);
5295 return TRUE;
5296
5297 Error:
5298 FreeArray(&a);
5299 cmsUNUSED_PARAMETER(nItems);
5300 return FALSE;
5301
5302 }
5303
5304
5305 static
5306 void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
5307 {
5308 cmsUNUSED_PARAMETER(n);
5309 cmsUNUSED_PARAMETER(self);
5310
5311 return (void*) cmsDictDup((cmsHANDLE) Ptr);
5312
5313 }
5314
5315
5316 static
5317 void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr)
5318 {
5319 cmsDictFree((cmsHANDLE) Ptr);
5320 cmsUNUSED_PARAMETER(self);
5321 }
5322
5323
5324 // ********************************************************************************
5325 // Type support main routines
5326 // ********************************************************************************
5327
5328
5329 // This is the list of built-in types
5330 static _cmsTagTypeLinkedList SupportedTagTypes[] = {
5331
5332 {TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] },
|