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(hInput, cmsSigColorantTableTag);
473 OutputColorant = cmsDupNamedColorList(List);
475 else OutputColorant = ComponentNames(OutputColorSpace, FALSE);
478 if (cProofing != NULL) {
480 hProof = OpenStockProfile(0, cProofing);
481 if (hProof == NULL) return FALSE;
482 dwFlags |= cmsFLAGS_SOFTPROOFING;
486 // Print information on profiles
489 printf("Profile:\n");
490 PrintProfileInformation(hInput);
494 printf("Output profile:\n");
495 PrintProfileInformation(hOutput);
498 if (hProof != NULL) {
499 printf("Proofing profile:\n");
500 PrintProfileInformation(hProof);
505 // Input is always in floating point
506 dwIn = cmsFormatterForColorspaceOfProfile(hInput, 0, TRUE);
510 dwOut = cmsFormatterForPCSOfProfile(hInput, lIsFloat ? 0 : 2, lIsFloat);
514 // 16 bits or floating point (only on output)
515 dwOut = cmsFormatterForColorspaceOfProfile(hOutput, lIsFloat ? 0 : 2, lIsFloat);
518 // For named color, there is a specialized formatter
519 if (cmsGetDeviceClass(hInput) == cmsSigNamedColorClass) {
521 dwIn = TYPE_NAMED_COLOR_INDEX;
522 InputNamedColor = TRUE;
526 switch (PrecalcMode) {
528 case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break;
529 case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
530 case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
534 FatalError("Unknown precalculation mode '%d'", PrecalcMode);
538 if (BlackPointCompensation)
539 dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
544 cmsUInt16Number Alarm[cmsMAXCHANNELS];
547 FatalError("I need proofing profile -p for gamut checking!");
549 for (i=0; i < cmsMAXCHANNELS; i++)
552 cmsSetAlarmCodes(Alarm);
553 dwFlags |= cmsFLAGS_GAMUTCHECK;
557 // The main transform
558 hTrans = cmsCreateProofingTransform(hInput, dwIn, hOutput, dwOut, hProof, Intent, ProofingIntent, dwFlags);
560 if (hProof) cmsCloseProfile(hProof);
562 if (hTrans == NULL) return FALSE;
565 // PCS Dump if requested
566 hTransXYZ = NULL; hTransLab = NULL;
568 if (hOutput && Verbose > 1) {
570 cmsHPROFILE hXYZ = cmsCreateXYZProfile();
571 cmsHPROFILE hLab = cmsCreateLab4Profile(NULL);
573 hTransXYZ = cmsCreateTransform(hInput, dwIn, hXYZ, lIsFloat ? TYPE_XYZ_DBL : TYPE_XYZ_16, Intent, cmsFLAGS_NOCACHE);
574 if (hTransXYZ == NULL) return FALSE;
576 hTransLab = cmsCreateTransform(hInput, dwIn, hLab, lIsFloat? TYPE_Lab_DBL : TYPE_Lab_16, Intent, cmsFLAGS_NOCACHE);
577 if (hTransLab == NULL) return FALSE;
579 cmsCloseProfile(hXYZ);
580 cmsCloseProfile(hLab);
583 if (hInput) cmsCloseProfile(hInput);
584 if (hOutput) cmsCloseProfile(hOutput);
590 // Free open resources
592 void CloseTransforms(void)
594 if (InputColorant) cmsFreeNamedColorList(InputColorant);
595 if (OutputColorant) cmsFreeNamedColorList(OutputColorant);
597 if (hTrans) cmsDeleteTransform(hTrans);
598 if (hTransLab) cmsDeleteTransform(hTransLab);
599 if (hTransXYZ) cmsDeleteTransform(hTransXYZ);
603 // ---------------------------------------------------------------------------------------------------
605 // Get input from user
607 void GetLine(char* Buffer, const char* frm, ...)
616 vfprintf(stderr, frm, args);
618 res = scanf("%4095s", Buffer);
620 if (res < 0 || toupper(Buffer[0]) == 'Q') { // Quit?
625 fprintf(stderr, "Done.\n");
635 // Print a value which is given in double floating point
637 void PrintFloatResults(cmsFloat64Number Value[])
639 cmsUInt32Number i, n;
640 char ChannelName[cmsMAX_PATH];
643 n = cmsChannelsOf(OutputColorSpace);
644 for (i=0; i < n; i++) {
646 if (OutputColorant != NULL) {
648 cmsNamedColorInfo(OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
652 sprintf(ChannelName, "Channel #%d", i + 1);
655 v = (cmsFloat64Number) Value[i]* OutputRange;
663 printf("%s=%.4f ", ChannelName, v);
670 // Get a named-color index
672 cmsUInt16Number GetIndex(void)
674 char Buffer[4096], Name[40], Prefix[40], Suffix[40];
676 const cmsNAMEDCOLORLIST* NamedColorList;
678 NamedColorList = cmsGetNamedColorList(hTrans);
679 if (NamedColorList == NULL) return 0;
681 max = cmsNamedColorCount(NamedColorList)-1;
683 GetLine(Buffer, "Color index (0..%d)? ", max);
684 index = atoi(Buffer);
687 FatalError("Named color %d out of range!", index);
689 cmsNamedColorInfo(NamedColorList, index, Name, Prefix, Suffix, NULL, NULL);
691 printf("\n%s %s %s\n", Prefix, Name, Suffix);
693 return (cmsUInt16Number) index;
696 // Read values from a text file or terminal
698 void TakeFloatValues(cmsFloat64Number Float[])
700 cmsUInt32Number i, n;
701 char ChannelName[cmsMAX_PATH];
702 char Buffer[cmsMAX_PATH];
705 fprintf(stderr, "\nEnter values, 'q' to quit\n");
707 if (InputNamedColor) {
709 // This is named color index, which is always cmsUInt16Number
710 cmsUInt16Number index = GetIndex();
711 memcpy(Float, &index, sizeof(cmsUInt16Number));
715 n = cmsChannelsOf(InputColorSpace);
716 for (i=0; i < n; i++) {
719 cmsNamedColorInfo(InputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
723 sprintf(ChannelName, "Channel #%d", i+1);
726 GetLine(Buffer, "%s? ", ChannelName);
728 Float[i] = (cmsFloat64Number) atof(Buffer) / InputRange;
732 fprintf(stderr, "\n");
736 void PrintPCSFloat(cmsFloat64Number Input[])
738 if (Verbose > 1 && hTransXYZ && hTransLab) {
740 cmsCIEXYZ XYZ = { 0, 0, 0 };
741 cmsCIELab Lab = { 0, 0, 0 };
743 if (hTransXYZ) cmsDoTransform(hTransXYZ, Input, &XYZ, 1);
744 if (hTransLab) cmsDoTransform(hTransLab, Input, &Lab, 1);
746 printf("[PCS] Lab=(%.4f,%.4f,%.4f) XYZ=(%.4f,%.4f,%.4f)\n", Lab.L, Lab.a, Lab.b,
747 XYZ.X * 100.0, XYZ.Y * 100.0, XYZ.Z * 100.0);
755 // -----------------------------------------------------------------------------------------------
758 void PrintEncodedResults(cmsUInt16Number Encoded[])
760 cmsUInt32Number i, n;
761 char ChannelName[cmsMAX_PATH];
764 n = cmsChannelsOf(OutputColorSpace);
765 for (i=0; i < n; i++) {
767 if (OutputColorant != NULL) {
769 cmsNamedColorInfo(OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
772 sprintf(ChannelName, "Channel #%d", i + 1);
776 printf("%s=", ChannelName);
783 printf("0x%04X ", (int) floor(v + .5));
785 printf("0x%02X ", (int) floor(v / 257. + .5));
790 printf("%d ", (int) floor(v + .5));
792 printf("%d ", (int) floor(v / 257. + .5));
800 // Print XYZ/Lab values on verbose mode
803 void PrintPCSEncoded(cmsFloat64Number Input[])
805 if (Verbose > 1 && hTransXYZ && hTransLab) {
807 cmsUInt16Number XYZ[3], Lab[3];
809 if (hTransXYZ) cmsDoTransform(hTransXYZ, Input, XYZ, 1);
810 if (hTransLab) cmsDoTransform(hTransLab, Input, Lab, 1);
812 printf("[PCS] Lab=(0x%04X,0x%04X,0x%04X) XYZ=(0x%04X,0x%04X,0x%04X)\n", Lab[0], Lab[1], Lab[2],
813 XYZ[0], XYZ[1], XYZ[2]);
819 // --------------------------------------------------------------------------------------
823 // Take a value from IT8 and scale it accordly to fill a cmsUInt16Number (0..FFFF)
826 cmsFloat64Number GetIT8Val(const char* Name, cmsFloat64Number Max)
828 const char* Val = cmsIT8GetData(hIT8in, CGATSPatch, Name);
831 FatalError("Field '%s' not found", Name);
833 return atof(Val) / Max;
838 // Read input values from CGATS file.
841 void TakeCGATSValues(int nPatch, cmsFloat64Number Float[])
844 // At first take the name if SAMPLE_ID is present
845 if (cmsIT8GetPatchName(hIT8in, nPatch, CGATSPatch) == NULL) {
846 FatalError("Sorry, I need 'SAMPLE_ID' on input CGATS to operate.");
850 // Special handling for named color profiles.
851 // Lookup the name in the names database (the transform)
853 if (InputNamedColor) {
855 const cmsNAMEDCOLORLIST* NamedColorList;
858 NamedColorList = cmsGetNamedColorList(hTrans);
859 if (NamedColorList == NULL)
860 FatalError("Malformed named color profile");
862 index = cmsNamedColorIndex(NamedColorList, CGATSPatch);
864 FatalError("Named color '%s' not found in the profile", CGATSPatch);
870 // Color is not a spot color, proceed.
872 switch (InputColorSpace) {
874 // Encoding should follow CGATS specification.
877 Float[0] = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "XYZ_X") / 100.0;
878 Float[1] = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "XYZ_Y") / 100.0;
879 Float[2] = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "XYZ_Z") / 100.0;
883 Float[0] = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "LAB_L");
884 Float[1] = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "LAB_A");
885 Float[2] = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "LAB_B");
890 Float[0] = GetIT8Val("RGB_R", 255.0);
891 Float[1] = GetIT8Val("RGB_G", 255.0);
892 Float[2] = GetIT8Val("RGB_B", 255.0);
896 Float[0] = GetIT8Val("GRAY", 255.0);
900 Float[0] = GetIT8Val("CMYK_C", 1.0);
901 Float[1] = GetIT8Val("CMYK_M", 1.0);
902 Float[2] = GetIT8Val("CMYK_Y", 1.0);
903 Float[3] = GetIT8Val("CMYK_K", 1.0);
907 Float[0] = GetIT8Val("CMY_C", 1.0);
908 Float[1] = GetIT8Val("CMY_M", 1.0);
909 Float[2] = GetIT8Val("CMY_Y", 1.0);
914 cmsUInt32Number i, n;
916 n = cmsChannelsOf(InputColorSpace);
917 for (i=0; i < n; i++) {
921 sprintf(Buffer, "CHAN_%d", i+1);
922 Float[i] = GetIT8Val(Buffer, 1.0);
931 void SetCGATSfld(const char* Col, cmsFloat64Number Val)
934 Val = floor(Val + 0.5);
936 if (!cmsIT8SetDataDbl(hIT8out, CGATSPatch, Col, Val)) {
937 FatalError("couldn't set '%s' on output cgats '%s'", Col, CGATSoutFilename);
944 void PutCGATSValues(cmsFloat64Number Float[])
946 cmsIT8SetData(hIT8out, CGATSPatch, "SAMPLE_ID", CGATSPatch);
947 switch (OutputColorSpace) {
950 // Encoding should follow CGATS specification.
954 SetCGATSfld("XYZ_X", Float[0] * 100.0);
955 SetCGATSfld("XYZ_Y", Float[1] * 100.0);
956 SetCGATSfld("XYZ_Z", Float[2] * 100.0);
961 SetCGATSfld("LAB_L", Float[0]);
962 SetCGATSfld("LAB_A", Float[1]);
963 SetCGATSfld("LAB_B", Float[2]);
968 SetCGATSfld("RGB_R", Float[0] * 255.0);
969 SetCGATSfld("RGB_G", Float[1] * 255.0);
970 SetCGATSfld("RGB_B", Float[2] * 255.0);
974 SetCGATSfld("GRAY", Float[0] * 255.0);
978 SetCGATSfld("CMYK_C", Float[0]);
979 SetCGATSfld("CMYK_M", Float[1]);
980 SetCGATSfld("CMYK_Y", Float[2]);
981 SetCGATSfld("CMYK_K", Float[3]);
985 SetCGATSfld("CMY_C", Float[0]);
986 SetCGATSfld("CMY_M", Float[1]);
987 SetCGATSfld("CMY_Y", Float[2]);
993 cmsUInt32Number i, n;
995 n = cmsChannelsOf(InputColorSpace);
996 for (i=0; i < n; i++) {
1000 sprintf(Buffer, "CHAN_%d", i+1);
1002 SetCGATSfld(Buffer, Float[i]);
1010 // Create data format
1012 void SetOutputDataFormat(void)
1014 cmsIT8DefineDblFormat(hIT8out, "%.4g");
1015 cmsIT8SetPropertyStr(hIT8out, "ORIGINATOR", "icctrans");
1017 if (IncludePart != NULL)
1018 cmsIT8SetPropertyStr(hIT8out, ".INCLUDE", IncludePart);
1020 cmsIT8SetComment(hIT8out, "Data follows");
1021 cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_SETS", nMaxPatches);
1024 switch (OutputColorSpace) {
1027 // Encoding should follow CGATS specification.
1030 cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 4);
1031 cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
1032 cmsIT8SetDataFormat(hIT8out, 1, "XYZ_X");
1033 cmsIT8SetDataFormat(hIT8out, 2, "XYZ_Y");
1034 cmsIT8SetDataFormat(hIT8out, 3, "XYZ_Z");
1038 cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 4);
1039 cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
1040 cmsIT8SetDataFormat(hIT8out, 1, "LAB_L");
1041 cmsIT8SetDataFormat(hIT8out, 2, "LAB_A");
1042 cmsIT8SetDataFormat(hIT8out, 3, "LAB_B");
1047 cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 4);
1048 cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
1049 cmsIT8SetDataFormat(hIT8out, 1, "RGB_R");
1050 cmsIT8SetDataFormat(hIT8out, 2, "RGB_G");
1051 cmsIT8SetDataFormat(hIT8out, 3, "RGB_B");
1054 case cmsSigGrayData:
1055 cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 2);
1056 cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
1057 cmsIT8SetDataFormat(hIT8out, 1, "GRAY");
1060 case cmsSigCmykData:
1061 cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 5);
1062 cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
1063 cmsIT8SetDataFormat(hIT8out, 1, "CMYK_C");
1064 cmsIT8SetDataFormat(hIT8out, 2, "CMYK_M");
1065 cmsIT8SetDataFormat(hIT8out, 3, "CMYK_Y");
1066 cmsIT8SetDataFormat(hIT8out, 4, "CMYK_K");
1070 cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 4);
1071 cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
1072 cmsIT8SetDataFormat(hIT8out, 1, "CMY_C");
1073 cmsIT8SetDataFormat(hIT8out, 2, "CMY_M");
1074 cmsIT8SetDataFormat(hIT8out, 3, "CMY_Y");
1082 n = cmsChannelsOf(OutputColorSpace);
1083 cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", n+1);
1084 cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
1086 for (i=1; i <= n; i++) {
1087 sprintf(Buffer, "CHAN_%d", i);
1088 cmsIT8SetDataFormat(hIT8out, i, Buffer);
1094 // Open CGATS if specified
1097 void OpenCGATSFiles(int argc, char *argv[])
1099 int nParams = argc - xoptind;
1103 hIT8in = cmsIT8LoadFromFile(0, argv[xoptind]);
1106 FatalError("'%s' is not recognized as a CGATS file", argv[xoptind]);
1108 nMaxPatches = (int) cmsIT8GetPropertyDbl(hIT8in, "NUMBER_OF_SETS");
1113 hIT8out = cmsIT8Alloc(NULL);
1114 SetOutputDataFormat();
1115 strncpy(CGATSoutFilename, argv[xoptind+1], cmsMAX_PATH-1);
1118 if (nParams > 2) FatalError("Too many CGATS files");
1124 int main(int argc, char *argv[])
1126 cmsUInt16Number Output[cmsMAXCHANNELS];
1127 cmsFloat64Number OutputFloat[cmsMAXCHANNELS];
1128 cmsFloat64Number InputFloat[cmsMAXCHANNELS];
1132 fprintf(stderr, "LittleCMS ColorSpace conversion calculator - 4.1 [LittleCMS %2.2f]\n", LCMS_VERSION / 1000.0);
1134 InitUtils("transicc");
1144 HandleSwitches(argc, argv);
1146 // Open profiles, create transforms
1147 if (!OpenTransforms()) return 1;
1149 // Open CGATS input if specified
1150 OpenCGATSFiles(argc, argv);
1152 // Main loop: read all values and convert them
1155 if (hIT8in != NULL) {
1157 if (nPatch >= nMaxPatches) break;
1158 TakeCGATSValues(nPatch++, InputFloat);
1162 if (feof(stdin)) break;
1163 TakeFloatValues(InputFloat);
1168 cmsDoTransform(hTrans, InputFloat, OutputFloat, 1);
1170 cmsDoTransform(hTrans, InputFloat, Output, 1);
1173 if (hIT8out != NULL) {
1175 PutCGATSValues(OutputFloat);
1180 PrintFloatResults(OutputFloat); PrintPCSFloat(InputFloat);
1183 PrintEncodedResults(Output); PrintPCSEncoded(InputFloat);
1197 cmsIT8SaveToFile(hIT8out, CGATSoutFilename);
1198 cmsIT8Free(hIT8out);