check for -Wreturn-type
[AROS.git] / workbench / libs / lcms2 / utils / transicc / transicc.c
blob332696a2ee4464e2e1b7d281e7c4127131290211
1 //---------------------------------------------------------------------------------
2 //
3 // Little Color Management System
4 // Copyright (c) 1998-2011 Marti Maria Saguer
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //---------------------------------------------------------------------------------
27 #include "utils.h"
29 #ifndef _MSC_VER
30 # include <unistd.h>
31 #endif
33 #ifdef CMS_IS_WINDOWS_
34 # include <io.h>
35 #endif
37 #define MAX_INPUT_BUFFER 4096
39 // Global options
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;
81 // isatty replacement
82 #ifdef _MSC_VER
83 #define xisatty(x) _isatty( _fileno( (x) ) )
84 #else
85 #define xisatty(x) isatty( fileno( (x) ) )
86 #endif
88 //---------------------------------------------------------------------------------------------------
90 // Print usage to stderr
91 static
92 void Help(void)
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");
138 // The toggles stuff
140 static
141 void HandleSwitches(int argc, char *argv[])
143 int s;
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) {
148 switch (s){
150 case '!':
151 IncludePart = xoptarg;
152 break;
154 case 'b':
155 case 'B':
156 BlackPointCompensation = TRUE;
157 break;
159 case 'c':
160 case 'C':
161 PrecalcMode = atoi(xoptarg);
162 if (PrecalcMode < 0 || PrecalcMode > 3)
163 FatalError("Unknown precalc mode '%d'", PrecalcMode);
164 break;
166 case 'd':
167 case 'D': {
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);
175 break;
177 case 'e':
178 case 'E':
179 lIsFloat = FALSE;
180 break;
182 case 'g':
183 case 'G':
184 GamutCheck = TRUE;
185 break;
187 case 'i':
188 case 'I':
189 if (lIsDeviceLink)
190 FatalError("icctrans: Device-link already specified");
192 cInProf = xoptarg;
193 break;
195 case 'l':
196 case 'L':
197 cInProf = xoptarg;
198 lIsDeviceLink = TRUE;
199 break;
201 // No extra intents for proofing
202 case 'm':
203 case 'M':
204 ProofingIntent = atoi(xoptarg);
205 if (ProofingIntent > 3)
206 FatalError("Unknown Proofing Intent '%d'", ProofingIntent);
207 break;
209 // For compatibility
210 case 'n':
211 case 'N':
212 Verbose = 0;
213 break;
215 // Output profile
216 case 'o':
217 case 'O':
218 if (lIsDeviceLink)
219 FatalError("icctrans: Device-link already specified");
220 cOutProf = xoptarg;
221 break;
223 // Proofing profile
224 case 'p':
225 case 'P':
226 cProofing = xoptarg;
227 break;
229 // Quantize to 16 bits
230 case 'q':
231 case 'Q':
232 lQuantize = TRUE;
233 break;
235 // The intent
236 case 't':
237 case 'T':
238 Intent = atoi(xoptarg);
239 break;
241 // Verbosity level
242 case 'V':
243 case 'v':
244 Verbose = atoi(xoptarg);
245 if (Verbose < 0 || Verbose > 3) {
246 FatalError("Unknown verbosity level '%d'", Verbose);
248 break;
250 // Wide (16 bits)
251 case 'W':
252 case 'w':
253 Width16 = TRUE;
254 break;
256 // Hexadecimal
257 case 'x':
258 case 'X':
259 InHexa = TRUE;
260 break;
262 default:
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) {
270 lIsFloat = TRUE;
276 static
277 void SetRange(cmsFloat64Number range, cmsBool IsInput)
279 if (IsInput)
280 InputRange = range;
281 else
282 OutputRange = range;
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.
288 static
289 cmsNAMEDCOLORLIST* ComponentNames(cmsColorSpaceSignature space, cmsBool IsInput)
291 cmsNAMEDCOLORLIST* out;
292 int i, n;
293 char Buffer[cmsMAX_PATH];
295 out = cmsAllocNamedColorList(0, 12, cmsMAXCHANNELS, "", "");
296 if (out == NULL) return NULL;
298 switch (space) {
300 case cmsSigXYZData:
301 SetRange(100, IsInput);
302 cmsAppendNamedColor(out, "X", NULL, NULL);
303 cmsAppendNamedColor(out, "Y", NULL, NULL);
304 cmsAppendNamedColor(out, "Z", NULL, NULL);
305 break;
307 case cmsSigLabData:
308 SetRange(1, IsInput);
309 cmsAppendNamedColor(out, "L*", NULL, NULL);
310 cmsAppendNamedColor(out, "a*", NULL, NULL);
311 cmsAppendNamedColor(out, "b*", NULL, NULL);
312 break;
314 case cmsSigLuvData:
315 SetRange(1, IsInput);
316 cmsAppendNamedColor(out, "L", NULL, NULL);
317 cmsAppendNamedColor(out, "u", NULL, NULL);
318 cmsAppendNamedColor(out, "v", NULL, NULL);
319 break;
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);
326 break;
329 case cmsSigYxyData:
330 SetRange(1, IsInput);
331 cmsAppendNamedColor(out, "Y", NULL, NULL);
332 cmsAppendNamedColor(out, "x", NULL, NULL);
333 cmsAppendNamedColor(out, "y", NULL, NULL);
334 break;
336 case cmsSigRgbData:
337 SetRange(255, IsInput);
338 cmsAppendNamedColor(out, "R", NULL, NULL);
339 cmsAppendNamedColor(out, "G", NULL, NULL);
340 cmsAppendNamedColor(out, "B", NULL, NULL);
341 break;
343 case cmsSigGrayData:
344 SetRange(255, IsInput);
345 cmsAppendNamedColor(out, "G", NULL, NULL);
346 break;
348 case cmsSigHsvData:
349 SetRange(255, IsInput);
350 cmsAppendNamedColor(out, "H", NULL, NULL);
351 cmsAppendNamedColor(out, "s", NULL, NULL);
352 cmsAppendNamedColor(out, "v", NULL, NULL);
353 break;
355 case cmsSigHlsData:
356 SetRange(255, IsInput);
357 cmsAppendNamedColor(out, "H", NULL, NULL);
358 cmsAppendNamedColor(out, "l", NULL, NULL);
359 cmsAppendNamedColor(out, "s", NULL, NULL);
360 break;
362 case cmsSigCmykData:
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);
368 break;
370 case cmsSigCmyData:
371 SetRange(1, IsInput);
372 cmsAppendNamedColor(out, "C", NULL, NULL);
373 cmsAppendNamedColor(out, "M", NULL, NULL);
374 cmsAppendNamedColor(out, "Y", NULL, NULL);
375 break;
377 default:
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);
390 return out;
395 // Creates all needed color transforms
396 static
397 cmsBool OpenTransforms(void)
399 cmsHPROFILE hInput, hOutput, hProof;
400 cmsUInt32Number dwIn, dwOut, dwFlags;
401 cmsNAMEDCOLORLIST* List;
402 int i;
404 // We don't need cache
405 dwFlags = cmsFLAGS_NOCACHE;
407 if (lIsDeviceLink) {
409 hInput = OpenStockProfile(0, cInProf);
410 if (hInput == NULL) return FALSE;
411 hOutput = NULL;
412 hProof = NULL;
414 if (cmsGetDeviceClass(hInput) == cmsSigNamedColorClass) {
415 OutputColorSpace = cmsGetColorSpace(hInput);
416 InputColorSpace = cmsGetPCS(hInput);
418 else {
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);
427 InputRange = 1;
429 else InputColorant = ComponentNames(InputColorSpace, TRUE);
431 if (cmsIsTag(hInput, cmsSigColorantTableOutTag)){
433 List = cmsReadTag(hInput, cmsSigColorantTableOutTag);
434 OutputColorant = cmsDupNamedColorList(List);
435 OutputRange = 1;
437 else OutputColorant = ComponentNames(OutputColorSpace, FALSE);
440 else {
442 hInput = OpenStockProfile(0, cInProf);
443 if (hInput == NULL) return FALSE;
445 hOutput = OpenStockProfile(0, cOutProf);
446 if (hOutput == NULL) return FALSE;
447 hProof = NULL;
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)
463 SetRange(255, TRUE);
464 else
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);
476 else
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
491 if (Verbose > 2) {
493 printf("Profile:\n");
494 PrintProfileInformation(hInput);
496 if (hOutput) {
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);
512 if (lIsDeviceLink) {
514 dwOut = cmsFormatterForPCSOfProfile(hInput, lIsFloat ? 0 : 2, lIsFloat);
516 else {
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) {
524 dwOut = dwIn;
525 dwIn = TYPE_NAMED_COLOR_INDEX;
526 InputNamedColor = TRUE;
529 // Precision mode
530 switch (PrecalcMode) {
532 case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break;
533 case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
534 case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
535 case 1: break;
537 default:
538 FatalError("Unknown precalculation mode '%d'", PrecalcMode);
542 if (BlackPointCompensation)
543 dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
546 if (GamutCheck) {
548 cmsUInt16Number Alarm[cmsMAXCHANNELS];
550 if (hProof == NULL)
551 FatalError("I need proofing profile -p for gamut checking!");
553 for (i=0; i < cmsMAXCHANNELS; i++)
554 Alarm[i] = 0xFFFF;
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);
590 return TRUE;
594 // Free open resources
595 static
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
610 static
611 void GetLine(char* Buffer, const char* frm, ...)
613 int res;
614 va_list args;
616 va_start(args, frm);
618 do {
619 if (xisatty(stdin))
620 vfprintf(stderr, frm, args);
622 res = scanf("%4095s", Buffer);
624 if (res < 0 || toupper(Buffer[0]) == 'Q') { // Quit?
626 CloseTransforms();
628 if (xisatty(stdin))
629 fprintf(stderr, "Done.\n");
631 exit(0);
633 } while (res == 0);
635 va_end(args);
639 // Print a value which is given in double floating point
640 static
641 void PrintFloatResults(cmsFloat64Number Value[])
643 cmsUInt32Number i, n;
644 char ChannelName[cmsMAX_PATH];
645 cmsFloat64Number v;
647 n = cmsChannelsOf(OutputColorSpace);
648 for (i=0; i < n; i++) {
650 if (OutputColorant != NULL) {
652 cmsNamedColorInfo(OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
654 else {
655 OutputRange = 1;
656 sprintf(ChannelName, "Channel #%u", i + 1);
659 v = (cmsFloat64Number) Value[i]* OutputRange;
661 if (lQuantize)
662 v = floor(v + 0.5);
664 if (Verbose <= 0)
665 printf("%.4f ", v);
666 else
667 printf("%s=%.4f ", ChannelName, v);
670 printf("\n");
674 // Get a named-color index
675 static
676 cmsUInt16Number GetIndex(void)
678 char Buffer[4096], Name[40], Prefix[40], Suffix[40];
679 int index, max;
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);
690 if (index > max)
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
701 static
702 void TakeFloatValues(cmsFloat64Number Float[])
704 cmsUInt32Number i, n;
705 char ChannelName[cmsMAX_PATH];
706 char Buffer[cmsMAX_PATH];
708 if (xisatty(stdin))
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));
716 return;
719 n = cmsChannelsOf(InputColorSpace);
720 for (i=0; i < n; i++) {
722 if (InputColorant) {
723 cmsNamedColorInfo(InputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
725 else {
726 InputRange = 1;
727 sprintf(ChannelName, "Channel #%u", i+1);
730 GetLine(Buffer, "%s? ", ChannelName);
732 Float[i] = (cmsFloat64Number) atof(Buffer) / InputRange;
735 if (xisatty(stdin))
736 fprintf(stderr, "\n");
739 static
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 // -----------------------------------------------------------------------------------------------
761 static
762 void PrintEncodedResults(cmsUInt16Number Encoded[])
764 cmsUInt32Number i, n;
765 char ChannelName[cmsMAX_PATH];
766 cmsUInt32Number v;
768 n = cmsChannelsOf(OutputColorSpace);
769 for (i=0; i < n; i++) {
771 if (OutputColorant != NULL) {
773 cmsNamedColorInfo(OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
775 else {
776 sprintf(ChannelName, "Channel #%u", i + 1);
779 if (Verbose > 0)
780 printf("%s=", ChannelName);
782 v = Encoded[i];
784 if (InHexa) {
786 if (Width16)
787 printf("0x%04X ", (int) floor(v + .5));
788 else
789 printf("0x%02X ", (int) floor(v / 257. + .5));
791 } else {
793 if (Width16)
794 printf("%d ", (int) floor(v + .5));
795 else
796 printf("%d ", (int) floor(v / 257. + .5));
801 printf("\n");
804 // Print XYZ/Lab values on verbose mode
806 static
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)
829 static
830 cmsFloat64Number GetIT8Val(const char* Name, cmsFloat64Number Max)
832 const char* Val = cmsIT8GetData(hIT8in, CGATSPatch, Name);
834 if (Val == NULL)
835 FatalError("Field '%s' not found", Name);
837 return atof(Val) / Max;
842 // Read input values from CGATS file.
844 static
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;
860 int index;
862 NamedColorList = cmsGetNamedColorList(hTrans);
863 if (NamedColorList == NULL)
864 FatalError("Malformed named color profile");
866 index = cmsNamedColorIndex(NamedColorList, CGATSPatch);
867 if (index < 0)
868 FatalError("Named color '%s' not found in the profile", CGATSPatch);
870 Float[0] = index;
871 return;
874 // Color is not a spot color, proceed.
876 switch (InputColorSpace) {
878 // Encoding should follow CGATS specification.
880 case cmsSigXYZData:
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;
884 break;
886 case cmsSigLabData:
887 Float[0] = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "LAB_L");
888 Float[1] = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "LAB_A");
889 Float[2] = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "LAB_B");
890 break;
893 case cmsSigRgbData:
894 Float[0] = GetIT8Val("RGB_R", 255.0);
895 Float[1] = GetIT8Val("RGB_G", 255.0);
896 Float[2] = GetIT8Val("RGB_B", 255.0);
897 break;
899 case cmsSigGrayData:
900 Float[0] = GetIT8Val("GRAY", 255.0);
901 break;
903 case cmsSigCmykData:
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);
908 break;
910 case cmsSigCmyData:
911 Float[0] = GetIT8Val("CMY_C", 1.0);
912 Float[1] = GetIT8Val("CMY_M", 1.0);
913 Float[2] = GetIT8Val("CMY_Y", 1.0);
914 break;
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++) {
937 char Buffer[255];
939 sprintf(Buffer, "%uCLR_%u", n, i+1);
940 Float[i] = GetIT8Val(Buffer, 100.0);
944 break;
946 default:
948 cmsUInt32Number i, n;
950 n = cmsChannelsOf(InputColorSpace);
951 for (i=0; i < n; i++) {
953 char Buffer[255];
955 sprintf(Buffer, "CHAN_%u", i+1);
956 Float[i] = GetIT8Val(Buffer, 1.0);
964 static
965 void SetCGATSfld(const char* Col, cmsFloat64Number Val)
967 if (lQuantize)
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);
977 static
978 void PutCGATSValues(cmsFloat64Number Float[])
980 cmsIT8SetData(hIT8out, CGATSPatch, "SAMPLE_ID", CGATSPatch);
981 switch (OutputColorSpace) {
984 // Encoding should follow CGATS specification.
986 case cmsSigXYZData:
988 SetCGATSfld("XYZ_X", Float[0] * 100.0);
989 SetCGATSfld("XYZ_Y", Float[1] * 100.0);
990 SetCGATSfld("XYZ_Z", Float[2] * 100.0);
991 break;
993 case cmsSigLabData:
995 SetCGATSfld("LAB_L", Float[0]);
996 SetCGATSfld("LAB_A", Float[1]);
997 SetCGATSfld("LAB_B", Float[2]);
998 break;
1001 case cmsSigRgbData:
1002 SetCGATSfld("RGB_R", Float[0] * 255.0);
1003 SetCGATSfld("RGB_G", Float[1] * 255.0);
1004 SetCGATSfld("RGB_B", Float[2] * 255.0);
1005 break;
1007 case cmsSigGrayData:
1008 SetCGATSfld("GRAY", Float[0] * 255.0);
1009 break;
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]);
1016 break;
1018 case cmsSigCmyData:
1019 SetCGATSfld("CMY_C", Float[0]);
1020 SetCGATSfld("CMY_M", Float[1]);
1021 SetCGATSfld("CMY_Y", Float[2]);
1022 break;
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++) {
1046 char Buffer[255];
1048 sprintf(Buffer, "%uCLR_%u", n, i+1);
1050 SetCGATSfld(Buffer, Float[i] * 100.0);
1053 break;
1055 default:
1058 cmsUInt32Number i, n;
1060 n = cmsChannelsOf(InputColorSpace);
1061 for (i=0; i < n; i++) {
1063 char Buffer[255];
1065 sprintf(Buffer, "CHAN_%u", i+1);
1067 SetCGATSfld(Buffer, Float[i]);
1075 // Create data format
1076 static
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.
1094 case cmsSigXYZData:
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");
1100 break;
1102 case cmsSigLabData:
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");
1108 break;
1111 case cmsSigRgbData:
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");
1117 break;
1119 case cmsSigGrayData:
1120 cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 2);
1121 cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
1122 cmsIT8SetDataFormat(hIT8out, 1, "GRAY");
1123 break;
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");
1132 break;
1134 case cmsSigCmyData:
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");
1140 break;
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:
1158 int i, n;
1159 char Buffer[255];
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);
1170 break;
1172 default: {
1174 int i, n;
1175 char Buffer[255];
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
1191 static
1192 void OpenCGATSFiles(int argc, char *argv[])
1194 int nParams = argc - xoptind;
1196 if (nParams >= 1) {
1198 hIT8in = cmsIT8LoadFromFile(0, argv[xoptind]);
1200 if (hIT8in == NULL)
1201 FatalError("'%s' is not recognized as a CGATS file", argv[xoptind]);
1203 nMaxPatches = (int) cmsIT8GetPropertyDbl(hIT8in, "NUMBER_OF_SETS");
1206 if (nParams == 2) {
1208 hIT8out = cmsIT8Alloc(NULL);
1209 SetOutputDataFormat();
1210 strncpy(CGATSoutFilename, argv[xoptind+1], cmsMAX_PATH-1);
1213 if (nParams > 2) FatalError("Too many CGATS files");
1218 // The main sink
1219 int main(int argc, char *argv[])
1221 cmsUInt16Number Output[cmsMAXCHANNELS];
1222 cmsFloat64Number OutputFloat[cmsMAXCHANNELS];
1223 cmsFloat64Number InputFloat[cmsMAXCHANNELS];
1225 int nPatch = 0;
1227 fprintf(stderr, "LittleCMS ColorSpace conversion calculator - 4.2 [LittleCMS %2.2f]\n", LCMS_VERSION / 1000.0);
1229 InitUtils("transicc");
1231 Verbose = 1;
1233 if (argc == 1) {
1235 Help();
1236 return 0;
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
1248 for(;;) {
1250 if (hIT8in != NULL) {
1252 if (nPatch >= nMaxPatches) break;
1253 TakeCGATSValues(nPatch++, InputFloat);
1255 } else {
1257 if (feof(stdin)) break;
1258 TakeFloatValues(InputFloat);
1262 if (lIsFloat)
1263 cmsDoTransform(hTrans, InputFloat, OutputFloat, 1);
1264 else
1265 cmsDoTransform(hTrans, InputFloat, Output, 1);
1268 if (hIT8out != NULL) {
1270 PutCGATSValues(OutputFloat);
1272 else {
1274 if (lIsFloat) {
1275 PrintFloatResults(OutputFloat); PrintPCSFloat(InputFloat);
1277 else {
1278 PrintEncodedResults(Output); PrintPCSEncoded(InputFloat);
1285 // Cleanup
1286 CloseTransforms();
1288 if (hIT8in)
1289 cmsIT8Free(hIT8in);
1291 if (hIT8out) {
1292 cmsIT8SaveToFile(hIT8out, CGATSoutFilename);
1293 cmsIT8Free(hIT8out);
1296 // All is ok
1297 return 0;