1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2011 Marti Maria Saguer
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //---------------------------------------------------------------------------------
33 #ifdef CMS_IS_WINDOWS_
37 #define MAX_INPUT_BUFFER 4096
41 static cmsBool InHexa
= FALSE
;
42 static cmsBool GamutCheck
= FALSE
;
43 static cmsBool Width16
= FALSE
;
44 static cmsBool BlackPointCompensation
= FALSE
;
45 static cmsBool lIsDeviceLink
= FALSE
;
46 static cmsBool lQuantize
= FALSE
;
47 static cmsBool lIsFloat
= TRUE
;
49 static cmsUInt32Number Intent
= INTENT_PERCEPTUAL
;
50 static cmsUInt32Number ProofingIntent
= INTENT_PERCEPTUAL
;
52 static int PrecalcMode
= 0;
54 // --------------------------------------------------------------
56 static char *cInProf
= NULL
;
57 static char *cOutProf
= NULL
;
58 static char *cProofing
= NULL
;
60 static char *IncludePart
= NULL
;
62 static cmsHANDLE hIT8in
= NULL
; // CGATS input
63 static cmsHANDLE hIT8out
= NULL
; // CGATS output
65 static char CGATSPatch
[1024]; // Actual Patch Name
66 static char CGATSoutFilename
[cmsMAX_PATH
];
68 static int nMaxPatches
;
70 static cmsHTRANSFORM hTrans
, hTransXYZ
, hTransLab
;
71 static cmsBool InputNamedColor
= FALSE
;
73 static cmsColorSpaceSignature InputColorSpace
, OutputColorSpace
;
75 static cmsNAMEDCOLORLIST
* InputColorant
= NULL
;
76 static cmsNAMEDCOLORLIST
* OutputColorant
= NULL
;
78 static cmsFloat64Number InputRange
, OutputRange
;
83 #define xisatty(x) _isatty( _fileno( (x) ) )
85 #define xisatty(x) isatty( fileno( (x) ) )
88 //---------------------------------------------------------------------------------------------------
90 // Print usage to stderr
95 fprintf(stderr
, "usage: transicc [flags] [CGATS input] [CGATS output]\n\n");
97 fprintf(stderr
, "flags:\n\n");
98 fprintf(stderr
, "%cv<0..3> - Verbosity level\n", SW
);
100 fprintf(stderr
, "%ce[op] - Encoded representation of numbers\n", SW
);
101 fprintf(stderr
, "\t%cw - use 16 bits\n", SW
);
102 fprintf(stderr
, "\t%cx - Hexadecimal\n", SW
);
103 fprintf(stderr
, "%cq - Quantize CGATS to 8 bits\n\n", SW
);
106 fprintf(stderr
, "%ci<profile> - Input profile (defaults to sRGB)\n", SW
);
107 fprintf(stderr
, "%co<profile> - Output profile (defaults to sRGB)\n", SW
);
108 fprintf(stderr
, "%cl<profile> - Transform by device-link profile\n", SW
);
110 fprintf(stderr
, "\nYou can use '*Lab', '*xyz' and others as built-in profiles\n\n");
112 PrintRenderingIntents();
114 fprintf(stderr
, "\n");
116 fprintf(stderr
, "%cd<0..1> - Observer adaptation state (abs.col. only)\n\n", SW
);
118 fprintf(stderr
, "%cb - Black point compensation\n", SW
);
120 fprintf(stderr
, "%cc<0,1,2,3> Precalculates transform (0=Off, 1=Normal, 2=Hi-res, 3=LoRes)\n\n", SW
);
121 fprintf(stderr
, "%cn - Terse output, intended for pipe usage\n", SW
);
123 fprintf(stderr
, "%cp<profile> - Soft proof profile\n", SW
);
124 fprintf(stderr
, "%cm<0,1,2,3> - Soft proof intent\n", SW
);
125 fprintf(stderr
, "%cg - Marks out-of-gamut colors on softproof\n\n", SW
);
129 fprintf(stderr
, "This program is intended to be a demo of the little cms\n"
130 "engine. Both lcms and this program are freeware. You can\n"
131 "obtain both in source code at http://www.littlecms.com\n"
132 "For suggestions, comments, bug reports etc. send mail to\n"
133 "info@littlecms.com\n\n");
141 void HandleSwitches(int argc
, char *argv
[])
145 while ((s
= xgetopt(argc
, argv
,
146 "bBC:c:d:D:eEgGI:i:L:l:m:M:nNO:o:p:P:QqT:t:V:v:WwxX!:")) != EOF
) {
151 IncludePart
= xoptarg
;
156 BlackPointCompensation
= TRUE
;
161 PrecalcMode
= atoi(xoptarg
);
162 if (PrecalcMode
< 0 || PrecalcMode
> 3)
163 FatalError("Unknown precalc mode '%d'", PrecalcMode
);
168 cmsFloat64Number ObserverAdaptationState
= atof(xoptarg
);
169 if (ObserverAdaptationState
< 0 ||
170 ObserverAdaptationState
> 1.0)
171 FatalError("Adaptation states should be between 0 and 1");
173 cmsSetAdaptationState(ObserverAdaptationState
);
190 FatalError("icctrans: Device-link already specified");
198 lIsDeviceLink
= TRUE
;
201 // No extra intents for proofing
204 ProofingIntent
= atoi(xoptarg
);
205 if (ProofingIntent
> 3)
206 FatalError("Unknown Proofing Intent '%d'", ProofingIntent
);
219 FatalError("icctrans: Device-link already specified");
229 // Quantize to 16 bits
238 Intent
= atoi(xoptarg
);
244 Verbose
= atoi(xoptarg
);
245 if (Verbose
< 0 || Verbose
> 3) {
246 FatalError("Unknown verbosity level '%d'", Verbose
);
263 FatalError("Unknown option - run without args to see valid ones.\n");
268 // If output CGATS involved, switch to float
269 if ((argc
- xoptind
) > 2) {
277 void SetRange(cmsFloat64Number range
, cmsBool IsInput
)
285 // Populate a named color list with usual component names.
286 // I am using the first Colorant channel to store the range, but it works since
287 // this space is not used anyway.
289 cmsNAMEDCOLORLIST
* ComponentNames(cmsColorSpaceSignature space
, cmsBool IsInput
)
291 cmsNAMEDCOLORLIST
* out
;
293 char Buffer
[cmsMAX_PATH
];
295 out
= cmsAllocNamedColorList(0, 12, cmsMAXCHANNELS
, "", "");
296 if (out
== NULL
) return NULL
;
301 SetRange(100, IsInput
);
302 cmsAppendNamedColor(out
, "X", NULL
, NULL
);
303 cmsAppendNamedColor(out
, "Y", NULL
, NULL
);
304 cmsAppendNamedColor(out
, "Z", NULL
, NULL
);
308 SetRange(1, IsInput
);
309 cmsAppendNamedColor(out
, "L*", NULL
, NULL
);
310 cmsAppendNamedColor(out
, "a*", NULL
, NULL
);
311 cmsAppendNamedColor(out
, "b*", NULL
, NULL
);
315 SetRange(1, IsInput
);
316 cmsAppendNamedColor(out
, "L", NULL
, NULL
);
317 cmsAppendNamedColor(out
, "u", NULL
, NULL
);
318 cmsAppendNamedColor(out
, "v", NULL
, NULL
);
321 case cmsSigYCbCrData
:
322 SetRange(255, IsInput
);
323 cmsAppendNamedColor(out
, "Y", NULL
, NULL
);
324 cmsAppendNamedColor(out
, "Cb", NULL
, NULL
);
325 cmsAppendNamedColor(out
, "Cr", NULL
, NULL
);
330 SetRange(1, IsInput
);
331 cmsAppendNamedColor(out
, "Y", NULL
, NULL
);
332 cmsAppendNamedColor(out
, "x", NULL
, NULL
);
333 cmsAppendNamedColor(out
, "y", NULL
, NULL
);
337 SetRange(255, IsInput
);
338 cmsAppendNamedColor(out
, "R", NULL
, NULL
);
339 cmsAppendNamedColor(out
, "G", NULL
, NULL
);
340 cmsAppendNamedColor(out
, "B", NULL
, NULL
);
344 SetRange(255, IsInput
);
345 cmsAppendNamedColor(out
, "G", NULL
, NULL
);
349 SetRange(255, IsInput
);
350 cmsAppendNamedColor(out
, "H", NULL
, NULL
);
351 cmsAppendNamedColor(out
, "s", NULL
, NULL
);
352 cmsAppendNamedColor(out
, "v", NULL
, NULL
);
356 SetRange(255, IsInput
);
357 cmsAppendNamedColor(out
, "H", NULL
, NULL
);
358 cmsAppendNamedColor(out
, "l", NULL
, NULL
);
359 cmsAppendNamedColor(out
, "s", NULL
, NULL
);
363 SetRange(1, IsInput
);
364 cmsAppendNamedColor(out
, "C", NULL
, NULL
);
365 cmsAppendNamedColor(out
, "M", NULL
, NULL
);
366 cmsAppendNamedColor(out
, "Y", NULL
, NULL
);
367 cmsAppendNamedColor(out
, "K", NULL
, NULL
);
371 SetRange(1, IsInput
);
372 cmsAppendNamedColor(out
, "C", NULL
, NULL
);
373 cmsAppendNamedColor(out
, "M", NULL
, NULL
);
374 cmsAppendNamedColor(out
, "Y", NULL
, NULL
);
379 SetRange(1, IsInput
);
381 n
= cmsChannelsOf(space
);
383 for (i
=0; i
< n
; i
++) {
385 sprintf(Buffer
, "Channel #%d", i
+ 1);
386 cmsAppendNamedColor(out
, Buffer
, NULL
, NULL
);
395 // Creates all needed color transforms
397 cmsBool
OpenTransforms(void)
399 cmsHPROFILE hInput
, hOutput
, hProof
;
400 cmsUInt32Number dwIn
, dwOut
, dwFlags
;
401 cmsNAMEDCOLORLIST
* List
;
404 // We don't need cache
405 dwFlags
= cmsFLAGS_NOCACHE
;
409 hInput
= OpenStockProfile(0, cInProf
);
410 if (hInput
== NULL
) return FALSE
;
414 if (cmsGetDeviceClass(hInput
) == cmsSigNamedColorClass
) {
415 OutputColorSpace
= cmsGetColorSpace(hInput
);
416 InputColorSpace
= cmsGetPCS(hInput
);
419 InputColorSpace
= cmsGetColorSpace(hInput
);
420 OutputColorSpace
= cmsGetPCS(hInput
);
423 // Read colorant tables if present
424 if (cmsIsTag(hInput
, cmsSigColorantTableTag
)) {
425 List
= cmsReadTag(hInput
, cmsSigColorantTableTag
);
426 InputColorant
= cmsDupNamedColorList(List
);
429 else InputColorant
= ComponentNames(InputColorSpace
, TRUE
);
431 if (cmsIsTag(hInput
, cmsSigColorantTableOutTag
)){
433 List
= cmsReadTag(hInput
, cmsSigColorantTableOutTag
);
434 OutputColorant
= cmsDupNamedColorList(List
);
437 else OutputColorant
= ComponentNames(OutputColorSpace
, FALSE
);
442 hInput
= OpenStockProfile(0, cInProf
);
443 if (hInput
== NULL
) return FALSE
;
445 hOutput
= OpenStockProfile(0, cOutProf
);
446 if (hOutput
== NULL
) return FALSE
;
450 if (cmsGetDeviceClass(hInput
) == cmsSigLinkClass
||
451 cmsGetDeviceClass(hOutput
) == cmsSigLinkClass
)
452 FatalError("Use %cl flag for devicelink profiles!\n", SW
);
455 InputColorSpace
= cmsGetColorSpace(hInput
);
456 OutputColorSpace
= cmsGetColorSpace(hOutput
);
458 // Read colorant tables if present
459 if (cmsIsTag(hInput
, cmsSigColorantTableTag
)) {
460 List
= cmsReadTag(hInput
, cmsSigColorantTableTag
);
461 InputColorant
= cmsDupNamedColorList(List
);
462 if (cmsNamedColorCount(InputColorant
) <= 3)
465 SetRange(1, TRUE
); // Inks are already divided by 100 in the formatter
468 else InputColorant
= ComponentNames(InputColorSpace
, TRUE
);
470 if (cmsIsTag(hOutput
, cmsSigColorantTableTag
)){
472 List
= cmsReadTag(hOutput
, cmsSigColorantTableTag
);
473 OutputColorant
= cmsDupNamedColorList(List
);
474 if (cmsNamedColorCount(OutputColorant
) <= 3)
475 SetRange(255, FALSE
);
477 SetRange(1, FALSE
); // Inks are already divided by 100 in the formatter
479 else OutputColorant
= ComponentNames(OutputColorSpace
, FALSE
);
482 if (cProofing
!= NULL
) {
484 hProof
= OpenStockProfile(0, cProofing
);
485 if (hProof
== NULL
) return FALSE
;
486 dwFlags
|= cmsFLAGS_SOFTPROOFING
;
490 // Print information on profiles
493 printf("Profile:\n");
494 PrintProfileInformation(hInput
);
498 printf("Output profile:\n");
499 PrintProfileInformation(hOutput
);
502 if (hProof
!= NULL
) {
503 printf("Proofing profile:\n");
504 PrintProfileInformation(hProof
);
509 // Input is always in floating point
510 dwIn
= cmsFormatterForColorspaceOfProfile(hInput
, 0, TRUE
);
514 dwOut
= cmsFormatterForPCSOfProfile(hInput
, lIsFloat
? 0 : 2, lIsFloat
);
518 // 16 bits or floating point (only on output)
519 dwOut
= cmsFormatterForColorspaceOfProfile(hOutput
, lIsFloat
? 0 : 2, lIsFloat
);
522 // For named color, there is a specialized formatter
523 if (cmsGetDeviceClass(hInput
) == cmsSigNamedColorClass
) {
525 dwIn
= TYPE_NAMED_COLOR_INDEX
;
526 InputNamedColor
= TRUE
;
530 switch (PrecalcMode
) {
532 case 0: dwFlags
|= cmsFLAGS_NOOPTIMIZE
; break;
533 case 2: dwFlags
|= cmsFLAGS_HIGHRESPRECALC
; break;
534 case 3: dwFlags
|= cmsFLAGS_LOWRESPRECALC
; break;
538 FatalError("Unknown precalculation mode '%d'", PrecalcMode
);
542 if (BlackPointCompensation
)
543 dwFlags
|= cmsFLAGS_BLACKPOINTCOMPENSATION
;
548 cmsUInt16Number Alarm
[cmsMAXCHANNELS
];
551 FatalError("I need proofing profile -p for gamut checking!");
553 for (i
=0; i
< cmsMAXCHANNELS
; i
++)
556 cmsSetAlarmCodes(Alarm
);
557 dwFlags
|= cmsFLAGS_GAMUTCHECK
;
561 // The main transform
562 hTrans
= cmsCreateProofingTransform(hInput
, dwIn
, hOutput
, dwOut
, hProof
, Intent
, ProofingIntent
, dwFlags
);
564 if (hProof
) cmsCloseProfile(hProof
);
566 if (hTrans
== NULL
) return FALSE
;
569 // PCS Dump if requested
570 hTransXYZ
= NULL
; hTransLab
= NULL
;
572 if (hOutput
&& Verbose
> 1) {
574 cmsHPROFILE hXYZ
= cmsCreateXYZProfile();
575 cmsHPROFILE hLab
= cmsCreateLab4Profile(NULL
);
577 hTransXYZ
= cmsCreateTransform(hInput
, dwIn
, hXYZ
, lIsFloat
? TYPE_XYZ_DBL
: TYPE_XYZ_16
, Intent
, cmsFLAGS_NOCACHE
);
578 if (hTransXYZ
== NULL
) return FALSE
;
580 hTransLab
= cmsCreateTransform(hInput
, dwIn
, hLab
, lIsFloat
? TYPE_Lab_DBL
: TYPE_Lab_16
, Intent
, cmsFLAGS_NOCACHE
);
581 if (hTransLab
== NULL
) return FALSE
;
583 cmsCloseProfile(hXYZ
);
584 cmsCloseProfile(hLab
);
587 if (hInput
) cmsCloseProfile(hInput
);
588 if (hOutput
) cmsCloseProfile(hOutput
);
594 // Free open resources
596 void CloseTransforms(void)
598 if (InputColorant
) cmsFreeNamedColorList(InputColorant
);
599 if (OutputColorant
) cmsFreeNamedColorList(OutputColorant
);
601 if (hTrans
) cmsDeleteTransform(hTrans
);
602 if (hTransLab
) cmsDeleteTransform(hTransLab
);
603 if (hTransXYZ
) cmsDeleteTransform(hTransXYZ
);
607 // ---------------------------------------------------------------------------------------------------
609 // Get input from user
611 void GetLine(char* Buffer
, const char* frm
, ...)
620 vfprintf(stderr
, frm
, args
);
622 res
= scanf("%4095s", Buffer
);
624 if (res
< 0 || toupper(Buffer
[0]) == 'Q') { // Quit?
629 fprintf(stderr
, "Done.\n");
639 // Print a value which is given in double floating point
641 void PrintFloatResults(cmsFloat64Number Value
[])
643 cmsUInt32Number i
, n
;
644 char ChannelName
[cmsMAX_PATH
];
647 n
= cmsChannelsOf(OutputColorSpace
);
648 for (i
=0; i
< n
; i
++) {
650 if (OutputColorant
!= NULL
) {
652 cmsNamedColorInfo(OutputColorant
, i
, ChannelName
, NULL
, NULL
, NULL
, NULL
);
656 sprintf(ChannelName
, "Channel #%u", i
+ 1);
659 v
= (cmsFloat64Number
) Value
[i
]* OutputRange
;
667 printf("%s=%.4f ", ChannelName
, v
);
674 // Get a named-color index
676 cmsUInt16Number
GetIndex(void)
678 char Buffer
[4096], Name
[40], Prefix
[40], Suffix
[40];
680 const cmsNAMEDCOLORLIST
* NamedColorList
;
682 NamedColorList
= cmsGetNamedColorList(hTrans
);
683 if (NamedColorList
== NULL
) return 0;
685 max
= cmsNamedColorCount(NamedColorList
)-1;
687 GetLine(Buffer
, "Color index (0..%d)? ", max
);
688 index
= atoi(Buffer
);
691 FatalError("Named color %d out of range!", index
);
693 cmsNamedColorInfo(NamedColorList
, index
, Name
, Prefix
, Suffix
, NULL
, NULL
);
695 printf("\n%s %s %s\n", Prefix
, Name
, Suffix
);
697 return (cmsUInt16Number
) index
;
700 // Read values from a text file or terminal
702 void TakeFloatValues(cmsFloat64Number Float
[])
704 cmsUInt32Number i
, n
;
705 char ChannelName
[cmsMAX_PATH
];
706 char Buffer
[cmsMAX_PATH
];
709 fprintf(stderr
, "\nEnter values, 'q' to quit\n");
711 if (InputNamedColor
) {
713 // This is named color index, which is always cmsUInt16Number
714 cmsUInt16Number index
= GetIndex();
715 memcpy(Float
, &index
, sizeof(cmsUInt16Number
));
719 n
= cmsChannelsOf(InputColorSpace
);
720 for (i
=0; i
< n
; i
++) {
723 cmsNamedColorInfo(InputColorant
, i
, ChannelName
, NULL
, NULL
, NULL
, NULL
);
727 sprintf(ChannelName
, "Channel #%u", i
+1);
730 GetLine(Buffer
, "%s? ", ChannelName
);
732 Float
[i
] = (cmsFloat64Number
) atof(Buffer
) / InputRange
;
736 fprintf(stderr
, "\n");
740 void PrintPCSFloat(cmsFloat64Number Input
[])
742 if (Verbose
> 1 && hTransXYZ
&& hTransLab
) {
744 cmsCIEXYZ XYZ
= { 0, 0, 0 };
745 cmsCIELab Lab
= { 0, 0, 0 };
747 if (hTransXYZ
) cmsDoTransform(hTransXYZ
, Input
, &XYZ
, 1);
748 if (hTransLab
) cmsDoTransform(hTransLab
, Input
, &Lab
, 1);
750 printf("[PCS] Lab=(%.4f,%.4f,%.4f) XYZ=(%.4f,%.4f,%.4f)\n", Lab
.L
, Lab
.a
, Lab
.b
,
751 XYZ
.X
* 100.0, XYZ
.Y
* 100.0, XYZ
.Z
* 100.0);
759 // -----------------------------------------------------------------------------------------------
762 void PrintEncodedResults(cmsUInt16Number Encoded
[])
764 cmsUInt32Number i
, n
;
765 char ChannelName
[cmsMAX_PATH
];
768 n
= cmsChannelsOf(OutputColorSpace
);
769 for (i
=0; i
< n
; i
++) {
771 if (OutputColorant
!= NULL
) {
773 cmsNamedColorInfo(OutputColorant
, i
, ChannelName
, NULL
, NULL
, NULL
, NULL
);
776 sprintf(ChannelName
, "Channel #%u", i
+ 1);
780 printf("%s=", ChannelName
);
787 printf("0x%04X ", (int) floor(v
+ .5));
789 printf("0x%02X ", (int) floor(v
/ 257. + .5));
794 printf("%d ", (int) floor(v
+ .5));
796 printf("%d ", (int) floor(v
/ 257. + .5));
804 // Print XYZ/Lab values on verbose mode
807 void PrintPCSEncoded(cmsFloat64Number Input
[])
809 if (Verbose
> 1 && hTransXYZ
&& hTransLab
) {
811 cmsUInt16Number XYZ
[3], Lab
[3];
813 if (hTransXYZ
) cmsDoTransform(hTransXYZ
, Input
, XYZ
, 1);
814 if (hTransLab
) cmsDoTransform(hTransLab
, Input
, Lab
, 1);
816 printf("[PCS] Lab=(0x%04X,0x%04X,0x%04X) XYZ=(0x%04X,0x%04X,0x%04X)\n", Lab
[0], Lab
[1], Lab
[2],
817 XYZ
[0], XYZ
[1], XYZ
[2]);
823 // --------------------------------------------------------------------------------------
827 // Take a value from IT8 and scale it accordly to fill a cmsUInt16Number (0..FFFF)
830 cmsFloat64Number
GetIT8Val(const char* Name
, cmsFloat64Number Max
)
832 const char* Val
= cmsIT8GetData(hIT8in
, CGATSPatch
, Name
);
835 FatalError("Field '%s' not found", Name
);
837 return atof(Val
) / Max
;
842 // Read input values from CGATS file.
845 void TakeCGATSValues(int nPatch
, cmsFloat64Number Float
[])
848 // At first take the name if SAMPLE_ID is present
849 if (cmsIT8GetPatchName(hIT8in
, nPatch
, CGATSPatch
) == NULL
) {
850 FatalError("Sorry, I need 'SAMPLE_ID' on input CGATS to operate.");
854 // Special handling for named color profiles.
855 // Lookup the name in the names database (the transform)
857 if (InputNamedColor
) {
859 const cmsNAMEDCOLORLIST
* NamedColorList
;
862 NamedColorList
= cmsGetNamedColorList(hTrans
);
863 if (NamedColorList
== NULL
)
864 FatalError("Malformed named color profile");
866 index
= cmsNamedColorIndex(NamedColorList
, CGATSPatch
);
868 FatalError("Named color '%s' not found in the profile", CGATSPatch
);
874 // Color is not a spot color, proceed.
876 switch (InputColorSpace
) {
878 // Encoding should follow CGATS specification.
881 Float
[0] = cmsIT8GetDataDbl(hIT8in
, CGATSPatch
, "XYZ_X") / 100.0;
882 Float
[1] = cmsIT8GetDataDbl(hIT8in
, CGATSPatch
, "XYZ_Y") / 100.0;
883 Float
[2] = cmsIT8GetDataDbl(hIT8in
, CGATSPatch
, "XYZ_Z") / 100.0;
887 Float
[0] = cmsIT8GetDataDbl(hIT8in
, CGATSPatch
, "LAB_L");
888 Float
[1] = cmsIT8GetDataDbl(hIT8in
, CGATSPatch
, "LAB_A");
889 Float
[2] = cmsIT8GetDataDbl(hIT8in
, CGATSPatch
, "LAB_B");
894 Float
[0] = GetIT8Val("RGB_R", 255.0);
895 Float
[1] = GetIT8Val("RGB_G", 255.0);
896 Float
[2] = GetIT8Val("RGB_B", 255.0);
900 Float
[0] = GetIT8Val("GRAY", 255.0);
904 Float
[0] = GetIT8Val("CMYK_C", 1.0);
905 Float
[1] = GetIT8Val("CMYK_M", 1.0);
906 Float
[2] = GetIT8Val("CMYK_Y", 1.0);
907 Float
[3] = GetIT8Val("CMYK_K", 1.0);
911 Float
[0] = GetIT8Val("CMY_C", 1.0);
912 Float
[1] = GetIT8Val("CMY_M", 1.0);
913 Float
[2] = GetIT8Val("CMY_Y", 1.0);
916 case cmsSig1colorData
:
917 case cmsSig2colorData
:
918 case cmsSig3colorData
:
919 case cmsSig4colorData
:
920 case cmsSig5colorData
:
921 case cmsSig6colorData
:
922 case cmsSig7colorData
:
923 case cmsSig8colorData
:
924 case cmsSig9colorData
:
925 case cmsSig10colorData
:
926 case cmsSig11colorData
:
927 case cmsSig12colorData
:
928 case cmsSig13colorData
:
929 case cmsSig14colorData
:
930 case cmsSig15colorData
:
932 cmsUInt32Number i
, n
;
934 n
= cmsChannelsOf(InputColorSpace
);
935 for (i
=0; i
< n
; i
++) {
939 sprintf(Buffer
, "%uCLR_%u", n
, i
+1);
940 Float
[i
] = GetIT8Val(Buffer
, 100.0);
948 cmsUInt32Number i
, n
;
950 n
= cmsChannelsOf(InputColorSpace
);
951 for (i
=0; i
< n
; i
++) {
955 sprintf(Buffer
, "CHAN_%u", i
+1);
956 Float
[i
] = GetIT8Val(Buffer
, 1.0);
965 void SetCGATSfld(const char* Col
, cmsFloat64Number Val
)
968 Val
= floor(Val
+ 0.5);
970 if (!cmsIT8SetDataDbl(hIT8out
, CGATSPatch
, Col
, Val
)) {
971 FatalError("couldn't set '%s' on output cgats '%s'", Col
, CGATSoutFilename
);
978 void PutCGATSValues(cmsFloat64Number Float
[])
980 cmsIT8SetData(hIT8out
, CGATSPatch
, "SAMPLE_ID", CGATSPatch
);
981 switch (OutputColorSpace
) {
984 // Encoding should follow CGATS specification.
988 SetCGATSfld("XYZ_X", Float
[0] * 100.0);
989 SetCGATSfld("XYZ_Y", Float
[1] * 100.0);
990 SetCGATSfld("XYZ_Z", Float
[2] * 100.0);
995 SetCGATSfld("LAB_L", Float
[0]);
996 SetCGATSfld("LAB_A", Float
[1]);
997 SetCGATSfld("LAB_B", Float
[2]);
1002 SetCGATSfld("RGB_R", Float
[0] * 255.0);
1003 SetCGATSfld("RGB_G", Float
[1] * 255.0);
1004 SetCGATSfld("RGB_B", Float
[2] * 255.0);
1007 case cmsSigGrayData
:
1008 SetCGATSfld("GRAY", Float
[0] * 255.0);
1011 case cmsSigCmykData
:
1012 SetCGATSfld("CMYK_C", Float
[0]);
1013 SetCGATSfld("CMYK_M", Float
[1]);
1014 SetCGATSfld("CMYK_Y", Float
[2]);
1015 SetCGATSfld("CMYK_K", Float
[3]);
1019 SetCGATSfld("CMY_C", Float
[0]);
1020 SetCGATSfld("CMY_M", Float
[1]);
1021 SetCGATSfld("CMY_Y", Float
[2]);
1024 case cmsSig1colorData
:
1025 case cmsSig2colorData
:
1026 case cmsSig3colorData
:
1027 case cmsSig4colorData
:
1028 case cmsSig5colorData
:
1029 case cmsSig6colorData
:
1030 case cmsSig7colorData
:
1031 case cmsSig8colorData
:
1032 case cmsSig9colorData
:
1033 case cmsSig10colorData
:
1034 case cmsSig11colorData
:
1035 case cmsSig12colorData
:
1036 case cmsSig13colorData
:
1037 case cmsSig14colorData
:
1038 case cmsSig15colorData
:
1041 cmsUInt32Number i
, n
;
1043 n
= cmsChannelsOf(InputColorSpace
);
1044 for (i
=0; i
< n
; i
++) {
1048 sprintf(Buffer
, "%uCLR_%u", n
, i
+1);
1050 SetCGATSfld(Buffer
, Float
[i
] * 100.0);
1058 cmsUInt32Number i
, n
;
1060 n
= cmsChannelsOf(InputColorSpace
);
1061 for (i
=0; i
< n
; i
++) {
1065 sprintf(Buffer
, "CHAN_%u", i
+1);
1067 SetCGATSfld(Buffer
, Float
[i
]);
1075 // Create data format
1077 void SetOutputDataFormat(void)
1079 cmsIT8DefineDblFormat(hIT8out
, "%.4g");
1080 cmsIT8SetPropertyStr(hIT8out
, "ORIGINATOR", "icctrans");
1082 if (IncludePart
!= NULL
)
1083 cmsIT8SetPropertyStr(hIT8out
, ".INCLUDE", IncludePart
);
1085 cmsIT8SetComment(hIT8out
, "Data follows");
1086 cmsIT8SetPropertyDbl(hIT8out
, "NUMBER_OF_SETS", nMaxPatches
);
1089 switch (OutputColorSpace
) {
1092 // Encoding should follow CGATS specification.
1095 cmsIT8SetPropertyDbl(hIT8out
, "NUMBER_OF_FIELDS", 4);
1096 cmsIT8SetDataFormat(hIT8out
, 0, "SAMPLE_ID");
1097 cmsIT8SetDataFormat(hIT8out
, 1, "XYZ_X");
1098 cmsIT8SetDataFormat(hIT8out
, 2, "XYZ_Y");
1099 cmsIT8SetDataFormat(hIT8out
, 3, "XYZ_Z");
1103 cmsIT8SetPropertyDbl(hIT8out
, "NUMBER_OF_FIELDS", 4);
1104 cmsIT8SetDataFormat(hIT8out
, 0, "SAMPLE_ID");
1105 cmsIT8SetDataFormat(hIT8out
, 1, "LAB_L");
1106 cmsIT8SetDataFormat(hIT8out
, 2, "LAB_A");
1107 cmsIT8SetDataFormat(hIT8out
, 3, "LAB_B");
1112 cmsIT8SetPropertyDbl(hIT8out
, "NUMBER_OF_FIELDS", 4);
1113 cmsIT8SetDataFormat(hIT8out
, 0, "SAMPLE_ID");
1114 cmsIT8SetDataFormat(hIT8out
, 1, "RGB_R");
1115 cmsIT8SetDataFormat(hIT8out
, 2, "RGB_G");
1116 cmsIT8SetDataFormat(hIT8out
, 3, "RGB_B");
1119 case cmsSigGrayData
:
1120 cmsIT8SetPropertyDbl(hIT8out
, "NUMBER_OF_FIELDS", 2);
1121 cmsIT8SetDataFormat(hIT8out
, 0, "SAMPLE_ID");
1122 cmsIT8SetDataFormat(hIT8out
, 1, "GRAY");
1125 case cmsSigCmykData
:
1126 cmsIT8SetPropertyDbl(hIT8out
, "NUMBER_OF_FIELDS", 5);
1127 cmsIT8SetDataFormat(hIT8out
, 0, "SAMPLE_ID");
1128 cmsIT8SetDataFormat(hIT8out
, 1, "CMYK_C");
1129 cmsIT8SetDataFormat(hIT8out
, 2, "CMYK_M");
1130 cmsIT8SetDataFormat(hIT8out
, 3, "CMYK_Y");
1131 cmsIT8SetDataFormat(hIT8out
, 4, "CMYK_K");
1135 cmsIT8SetPropertyDbl(hIT8out
, "NUMBER_OF_FIELDS", 4);
1136 cmsIT8SetDataFormat(hIT8out
, 0, "SAMPLE_ID");
1137 cmsIT8SetDataFormat(hIT8out
, 1, "CMY_C");
1138 cmsIT8SetDataFormat(hIT8out
, 2, "CMY_M");
1139 cmsIT8SetDataFormat(hIT8out
, 3, "CMY_Y");
1142 case cmsSig1colorData
:
1143 case cmsSig2colorData
:
1144 case cmsSig3colorData
:
1145 case cmsSig4colorData
:
1146 case cmsSig5colorData
:
1147 case cmsSig6colorData
:
1148 case cmsSig7colorData
:
1149 case cmsSig8colorData
:
1150 case cmsSig9colorData
:
1151 case cmsSig10colorData
:
1152 case cmsSig11colorData
:
1153 case cmsSig12colorData
:
1154 case cmsSig13colorData
:
1155 case cmsSig14colorData
:
1156 case cmsSig15colorData
:
1161 n
= cmsChannelsOf(OutputColorSpace
);
1162 cmsIT8SetPropertyDbl(hIT8out
, "NUMBER_OF_FIELDS", n
+1);
1163 cmsIT8SetDataFormat(hIT8out
, 0, "SAMPLE_ID");
1165 for (i
=1; i
<= n
; i
++) {
1166 sprintf(Buffer
, "%dCLR_%d", n
, i
);
1167 cmsIT8SetDataFormat(hIT8out
, i
, Buffer
);
1177 n
= cmsChannelsOf(OutputColorSpace
);
1178 cmsIT8SetPropertyDbl(hIT8out
, "NUMBER_OF_FIELDS", n
+1);
1179 cmsIT8SetDataFormat(hIT8out
, 0, "SAMPLE_ID");
1181 for (i
=1; i
<= n
; i
++) {
1182 sprintf(Buffer
, "CHAN_%d", i
);
1183 cmsIT8SetDataFormat(hIT8out
, i
, Buffer
);
1189 // Open CGATS if specified
1192 void OpenCGATSFiles(int argc
, char *argv
[])
1194 int nParams
= argc
- xoptind
;
1198 hIT8in
= cmsIT8LoadFromFile(0, argv
[xoptind
]);
1201 FatalError("'%s' is not recognized as a CGATS file", argv
[xoptind
]);
1203 nMaxPatches
= (int) cmsIT8GetPropertyDbl(hIT8in
, "NUMBER_OF_SETS");
1208 hIT8out
= cmsIT8Alloc(NULL
);
1209 SetOutputDataFormat();
1210 strncpy(CGATSoutFilename
, argv
[xoptind
+1], cmsMAX_PATH
-1);
1213 if (nParams
> 2) FatalError("Too many CGATS files");
1219 int main(int argc
, char *argv
[])
1221 cmsUInt16Number Output
[cmsMAXCHANNELS
];
1222 cmsFloat64Number OutputFloat
[cmsMAXCHANNELS
];
1223 cmsFloat64Number InputFloat
[cmsMAXCHANNELS
];
1227 fprintf(stderr
, "LittleCMS ColorSpace conversion calculator - 4.2 [LittleCMS %2.2f]\n", LCMS_VERSION
/ 1000.0);
1229 InitUtils("transicc");
1239 HandleSwitches(argc
, argv
);
1241 // Open profiles, create transforms
1242 if (!OpenTransforms()) return 1;
1244 // Open CGATS input if specified
1245 OpenCGATSFiles(argc
, argv
);
1247 // Main loop: read all values and convert them
1250 if (hIT8in
!= NULL
) {
1252 if (nPatch
>= nMaxPatches
) break;
1253 TakeCGATSValues(nPatch
++, InputFloat
);
1257 if (feof(stdin
)) break;
1258 TakeFloatValues(InputFloat
);
1263 cmsDoTransform(hTrans
, InputFloat
, OutputFloat
, 1);
1265 cmsDoTransform(hTrans
, InputFloat
, Output
, 1);
1268 if (hIT8out
!= NULL
) {
1270 PutCGATSValues(OutputFloat
);
1275 PrintFloatResults(OutputFloat
); PrintPCSFloat(InputFloat
);
1278 PrintEncodedResults(Output
); PrintPCSEncoded(InputFloat
);
1292 cmsIT8SaveToFile(hIT8out
, CGATSoutFilename
);
1293 cmsIT8Free(hIT8out
);