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 #%d", 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 #%d", 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 #%d", 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, "%dCLR_%d", 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_%d", 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, "%dCLR_%d", 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_%d", 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);