summaryrefslogtreecommitdiffstats
path: root/debian/lcms/lcms-1.19.dfsg2/samples/icctrans.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/lcms/lcms-1.19.dfsg2/samples/icctrans.c')
-rwxr-xr-xdebian/lcms/lcms-1.19.dfsg2/samples/icctrans.c1288
1 files changed, 1288 insertions, 0 deletions
diff --git a/debian/lcms/lcms-1.19.dfsg2/samples/icctrans.c b/debian/lcms/lcms-1.19.dfsg2/samples/icctrans.c
new file mode 100755
index 00000000..67fc63f0
--- /dev/null
+++ b/debian/lcms/lcms-1.19.dfsg2/samples/icctrans.c
@@ -0,0 +1,1288 @@
+//
+// Little cms
+// Copyright (C) 1998-2007 Marti Maria
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+#include "lcms.h"
+
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifndef NON_WINDOWS
+#include <io.h>
+#endif
+
+// xgetopt() interface -----------------------------------------------------
+
+extern int xoptind;
+extern char *xoptarg;
+extern int xopterr;
+extern char SW;
+int cdecl xgetopt(int argc, char *argv[], char *optionS);
+
+// ------------------------------------------------------------------------
+
+// Stock profiles function
+extern cmsHPROFILE OpenStockProfile(const char* File);
+
+
+// Globals
+
+static LCMSBOOL InHexa = FALSE;
+static LCMSBOOL Verbose = FALSE;
+static LCMSBOOL GamutCheck = FALSE;
+static LCMSBOOL Width16 = FALSE;
+static LCMSBOOL BlackPointCompensation = FALSE;
+static LCMSBOOL PreserveBlack = FALSE;
+static LCMSBOOL lIsDeviceLink = FALSE;
+static LCMSBOOL lTerse = FALSE;
+static LCMSBOOL lQuantize = FALSE;
+static LCMSBOOL lUse255always = FALSE;
+
+static char *cInProf = NULL;
+static char *cOutProf = NULL;
+static char *cProofing = NULL;
+
+static char *IncludePart = NULL;
+
+static LCMSHANDLE hIT8in = NULL; // CGATS input
+static LCMSHANDLE hIT8out = NULL; // CGATS output
+
+static char CGATSPatch[1024]; // Actual Patch Name
+static char CGATSoutFilename[MAX_PATH];
+
+
+static int Intent = INTENT_PERCEPTUAL;
+static int ProofingIntent = INTENT_PERCEPTUAL;
+static int PrecalcMode = 0;
+static int nMaxPatches;
+
+static cmsHPROFILE hInput, hOutput, hProof, hLab = NULL, hXYZ = NULL;
+static cmsHTRANSFORM hTrans, hTransXYZ, hTransLab;
+
+static icColorSpaceSignature InputColorSpace, OutputColorSpace;
+static cmsCIEXYZ xyz;
+static cmsCIELab Lab;
+
+
+static LPcmsNAMEDCOLORLIST InputColorant = NULL;
+static LPcmsNAMEDCOLORLIST OutputColorant = NULL;
+
+
+// isatty replacement
+
+#ifdef _MSC_VER
+#define xisatty(x) _isatty( _fileno( (x) ) )
+#else
+#define xisatty(x) isatty( fileno( (x) ) )
+#endif
+
+
+// Give up
+
+static
+void FatalError(const char *frm, ...)
+{
+ va_list args;
+
+ va_start(args, frm);
+ vfprintf(stderr, frm, args);
+ va_end(args);
+
+ exit(1);
+}
+
+// Issue a message
+
+static
+void Warning(const char *frm, ...)
+{
+ va_list args;
+
+ va_start(args, frm);
+ vfprintf(stderr, frm, args);
+ va_end(args);
+}
+
+// The error handler
+
+static
+int MyErrorHandler(int ErrorCode, const char *ErrorText)
+{
+ FatalError("icctrans: %s", ErrorText);
+ return 0;
+}
+
+// Print usage to stderr
+
+static
+void Help(void)
+{
+
+ fprintf(stderr, "usage: icctrans [flags] [CGATS input] [CGATS output]\n\n");
+
+ fprintf(stderr, "flags:\n\n");
+ fprintf(stderr, "%cv - Verbose (Print PCS as well)\n", SW);
+ fprintf(stderr, "%cw - use 16 bits\n", SW);
+ fprintf(stderr, "%c5 - don't use %% on inks (always 0..255, even on CMYK)\n", SW);
+ fprintf(stderr, "%cx - Hexadecimal\n", SW);
+ fprintf(stderr, "%cq - Quantize CGATS to 8 bits\n\n", SW);
+
+ fprintf(stderr, "%ci<profile> - Input profile (defaults to sRGB)\n", SW);
+ fprintf(stderr, "%co<profile> - Output profile (defaults to sRGB)\n", SW);
+ fprintf(stderr, "%cl<profile> - Transform by device-link profile\n", SW);
+
+ fprintf(stderr, "\nYou can use '*Lab', '*xyz' and others as built-in profiles\n\n");
+
+ fprintf(stderr, "%ct<0,1,2,3> Intent (0=Perceptual, 1=Rel.Col, 2=Saturation, 3=Abs.Col.)\n", SW);
+ fprintf(stderr, "%cd<0..1> - Observer adaptation state (abs.col. only)\n\n", SW);
+
+ fprintf(stderr, "%cb - Black point compensation\n", SW);
+ fprintf(stderr, "%cf<n> - Preserve black (CMYK only) 0=off, 1=black ink only, 2=full K plane\n", SW);
+ fprintf(stderr, "%cc<0,1,2,3> Precalculates transform (0=Off, 1=Normal, 2=Hi-res, 3=LoRes)\n\n", SW);
+ fprintf(stderr, "%cn - Terse output, intended for pipe usage\n", SW);
+
+ fprintf(stderr, "%cp<profile> - Soft proof profile\n", SW);
+ fprintf(stderr, "%cm<0,1,2,3> - Soft proof intent\n", SW);
+ fprintf(stderr, "%cg - Marks out-of-gamut colors on softproof\n\n", SW);
+
+
+
+ fprintf(stderr, "This program is intended to be a demo of the little cms\n"
+ "engine. Both lcms and this program are freeware. You can\n"
+ "obtain both in source code at http://www.littlecms.com\n"
+ "For suggestions, comments, bug reports etc. send mail to\n"
+ "info@littlecms.com\n\n");
+ exit(0);
+}
+
+
+
+// The toggles stuff
+
+static
+void HandleSwitches(int argc, char *argv[])
+{
+ int s;
+
+ while ((s = xgetopt(argc,argv,
+ "%C:c:VvQqWwxXhHbBnNI:i:O:o:T:t:L:l:p:P:m:M:gGF:f:d:D:!:5")) != EOF) {
+
+ switch (s){
+
+ case '5':
+ lUse255always = TRUE;
+ break;
+
+ case '!':
+ IncludePart = xoptarg;
+ break;
+
+ case 'b':
+ case 'B':
+ BlackPointCompensation = TRUE;
+ break;
+
+ case 'c':
+ case 'C':
+ PrecalcMode = atoi(xoptarg);
+ if (PrecalcMode < 0 || PrecalcMode > 3)
+ FatalError("icctrans: Unknown precalc mode '%d'", PrecalcMode);
+ break;
+
+ case 'd':
+ case 'D': {
+ double ObserverAdaptationState = atof(xoptarg);
+ if (ObserverAdaptationState != 0 &&
+ ObserverAdaptationState != 1.0)
+ Warning("Adaptation states other that 0 or 1 are not yet implemented");
+
+ cmsSetAdaptationState(ObserverAdaptationState);
+ }
+ break;
+
+ case 'f':
+ case 'F':
+ PreserveBlack = atoi(xoptarg);
+ if (PreserveBlack < 0 || PreserveBlack > 2)
+ FatalError("Unknown PreserveBlack '%d'", PreserveBlack);
+ break;
+
+ case 'g':
+ case 'G':
+ GamutCheck = TRUE;
+ break;
+
+ case 'i':
+ case 'I':
+ if (lIsDeviceLink)
+ FatalError("icctrans: Device-link already specified");
+
+ cInProf = xoptarg;
+ break;
+
+ case 'l':
+ case 'L':
+ cInProf = xoptarg;
+ lIsDeviceLink = TRUE;
+ break;
+
+ case 'm':
+ case 'M':
+ ProofingIntent = atoi(xoptarg);
+ if (ProofingIntent > 3) ProofingIntent = 3;
+ if (ProofingIntent < 0) ProofingIntent = 0;
+ break;
+
+ case 'n':
+ case 'N':
+ lTerse = TRUE;
+ break;
+
+
+ case 'o':
+ case 'O':
+ if (lIsDeviceLink)
+ FatalError("icctrans: Device-link already specified");
+ cOutProf = xoptarg;
+ break;
+
+ case 'p':
+ case 'P':
+ cProofing = xoptarg;
+ break;
+
+ case 'q':
+ case 'Q':
+ lQuantize = TRUE;
+ break;
+
+ case 't':
+ case 'T':
+ Intent = atoi(xoptarg);
+ if (Intent > 3) Intent = 3;
+ if (Intent < 0) Intent = 0;
+ break;
+
+ case 'v':
+ case 'V':
+ Verbose = TRUE;
+ break;
+
+ case 'W':
+ case 'w':
+ Width16 = TRUE;
+ break;
+
+ case 'x':
+ case 'X':
+ InHexa = TRUE;
+ break;
+
+ default:
+
+ FatalError("icctrans: Unknown option - run without args to see valid ones.\n");
+ }
+ }
+}
+
+
+// Displays the colorant table
+
+static
+void PrintColorantTable(cmsHPROFILE hInput, icTagSignature Sig, const char* Title)
+{
+ LPcmsNAMEDCOLORLIST list;
+ int i;
+
+ if (cmsIsTag(hInput, Sig)) {
+
+ printf("%s:\n", Title);
+
+ list = cmsReadColorantTable(hInput, Sig);
+
+ for (i=0; i < list ->nColors; i++)
+ printf("\t%s\n", list ->List[i].Name);
+
+ cmsFreeNamedColorList(list);
+ printf("\n");
+ }
+
+}
+
+// Creates all needed color transforms
+
+static
+void OpenTransforms(void)
+{
+
+ DWORD dwIn, dwOut, dwFlags;
+
+ dwFlags = 0;
+
+
+ if (lIsDeviceLink) {
+
+ hInput = cmsOpenProfileFromFile(cInProf, "r");
+ hOutput = NULL;
+ InputColorSpace = cmsGetColorSpace(hInput);
+ OutputColorSpace = cmsGetPCS(hInput);
+
+ // Read colorant tables if present
+
+ if (cmsIsTag(hInput, icSigColorantTableTag))
+ InputColorant = cmsReadColorantTable(hInput, icSigColorantTableTag);
+
+ if (cmsIsTag(hInput, icSigColorantTableOutTag))
+ OutputColorant = cmsReadColorantTable(hInput, icSigColorantTableOutTag);
+
+
+
+ }
+ else {
+
+ hInput = OpenStockProfile(cInProf);
+ hOutput = OpenStockProfile(cOutProf);
+ hProof = NULL;
+
+ if (cmsIsTag(hInput, icSigColorantTableTag))
+ InputColorant = cmsReadColorantTable(hInput, icSigColorantTableTag);
+
+ if (cmsIsTag(hOutput, icSigColorantTableTag))
+ OutputColorant = cmsReadColorantTable(hOutput, icSigColorantTableTag);
+
+
+ if (cProofing != NULL) {
+
+ hProof = OpenStockProfile(cProofing);
+ dwFlags |= cmsFLAGS_SOFTPROOFING;
+ }
+
+ InputColorSpace = cmsGetColorSpace(hInput);
+ OutputColorSpace = cmsGetColorSpace(hOutput);
+
+ if (cmsGetDeviceClass(hInput) == icSigLinkClass ||
+ cmsGetDeviceClass(hOutput) == icSigLinkClass)
+ FatalError("icctrans: Use %cl flag for devicelink profiles!\n", SW);
+
+ }
+
+
+
+ if (Verbose) {
+
+ printf("From: %s\n", cmsTakeProductName(hInput));
+ printf("Desc: %s\n", cmsTakeProductDesc(hInput));
+ printf("Info: %s\n\n", cmsTakeProductInfo(hInput));
+ PrintColorantTable(hInput, icSigColorantTableTag, "Input colorant table");
+ PrintColorantTable(hInput, icSigColorantTableOutTag, "Input colorant out table");
+
+ if (hOutput) {
+ printf("To : %s\n", cmsTakeProductName(hOutput));
+ printf("Desc: %s\n", cmsTakeProductDesc(hOutput));
+ printf("Info: %s\n\n", cmsTakeProductInfo(hOutput));
+ PrintColorantTable(hOutput, icSigColorantTableTag, "Output colorant table");
+ PrintColorantTable(hOutput, icSigColorantTableOutTag, "Input colorant out table");
+ }
+ }
+
+
+ dwIn = BYTES_SH(2) | CHANNELS_SH(_cmsChannelsOf(InputColorSpace));
+ dwOut = BYTES_SH(2) | CHANNELS_SH(_cmsChannelsOf(OutputColorSpace));
+
+
+ if (PreserveBlack) {
+ dwFlags |= cmsFLAGS_PRESERVEBLACK;
+ if (PrecalcMode == 0) PrecalcMode = 1;
+ cmsSetCMYKPreservationStrategy(PreserveBlack-1);
+ }
+
+
+ switch (PrecalcMode) {
+
+ case 0: dwFlags |= cmsFLAGS_NOTPRECALC; break;
+ case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
+ case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
+ case 1: break;
+
+ default: FatalError("icctrans: Unknown precalculation mode '%d'", PrecalcMode);
+ }
+
+
+ if (BlackPointCompensation)
+ dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
+
+
+
+ if (GamutCheck) {
+
+ if (hProof == NULL)
+ FatalError("icctrans: I need proofing profile -p for gamut checking!");
+
+ cmsSetAlarmCodes(0xFF, 0xFF, 0xFF);
+ dwFlags |= cmsFLAGS_GAMUTCHECK;
+ }
+
+ if (cmsGetDeviceClass(hInput) == icSigNamedColorClass) {
+ dwIn = TYPE_NAMED_COLOR_INDEX;
+ }
+
+
+ hTrans = cmsCreateProofingTransform(hInput, dwIn,
+ hOutput, dwOut,
+ hProof,
+ Intent, ProofingIntent, dwFlags);
+
+
+ hTransXYZ = NULL; hTransLab = NULL;
+
+ if (hOutput && Verbose) {
+
+ hXYZ = cmsCreateXYZProfile();
+ hLab = cmsCreateLabProfile(NULL);
+
+ hTransXYZ = cmsCreateTransform(hInput, dwIn,
+ hXYZ, TYPE_XYZ_16,
+ Intent, cmsFLAGS_NOTPRECALC);
+
+ hTransLab = cmsCreateTransform(hInput, dwIn,
+ hLab, TYPE_Lab_16,
+ Intent, cmsFLAGS_NOTPRECALC);
+ }
+
+}
+
+
+// Free open resources
+
+static
+void CloseTransforms(void)
+{
+ if (InputColorant) cmsFreeNamedColorList(InputColorant);
+ if (OutputColorant) cmsFreeNamedColorList(OutputColorant);
+
+ cmsDeleteTransform(hTrans);
+ if (hTransLab) cmsDeleteTransform(hTransLab);
+ if (hTransXYZ) cmsDeleteTransform(hTransXYZ);
+ cmsCloseProfile(hInput);
+ if (hOutput) cmsCloseProfile(hOutput);
+ if (hProof) cmsCloseProfile(hProof);
+ if (hXYZ) cmsCloseProfile(hXYZ);
+ if (hLab) cmsCloseProfile(hLab);
+
+}
+
+
+// Print a value, with a prefix, normalized to a given range
+
+static
+void PrintRange(const char* C, double v, double Range)
+{
+ char Prefix[20];
+
+ Prefix[0] = 0;
+ if (!lTerse)
+ sprintf(Prefix, "%s=", C);
+
+ if (InHexa)
+ {
+ if (Width16)
+ printf("%s0x%x ", Prefix, (int) floor(v + .5));
+ else
+ printf("%s0x%x ", Prefix, (int) floor(v / 257. + .5));
+
+ }
+ else
+ {
+
+ double out = (v * Range) / 65535.0;
+ if (lQuantize)
+ out = floor(out + 0.5);
+
+ printf("%s%.2f ", Prefix, out);
+ }
+}
+
+
+static
+void Print255(const char* C, double v)
+{
+ PrintRange(C, v, 255.0);
+}
+
+static
+void Print100(const char* C, double v)
+{
+ PrintRange(C, v, lUse255always ? 255.0 : 100.0);
+}
+
+static
+void PrintCooked(const char* C, double v)
+{
+ if (lQuantize)
+ v = floor(v + 0.5);
+
+ if (lTerse)
+ printf("%.4f ", v);
+ else
+ printf("%s=%.4f ", C, v);
+}
+
+
+static
+void PrintResults(WORD Encoded[], icColorSpaceSignature ColorSpace)
+{
+ int i;
+
+ switch (ColorSpace) {
+
+ case icSigXYZData:
+ cmsXYZEncoded2Float(&xyz, Encoded);
+ PrintCooked("X", xyz.X * 100.);
+ PrintCooked("Y", xyz.Y * 100.);
+ PrintCooked("Z", xyz.Z * 100.);
+ break;
+
+ case icSigLabData:
+ cmsLabEncoded2Float(&Lab, Encoded);
+ PrintCooked("L*", Lab.L);
+ PrintCooked("a*", Lab.a);
+ PrintCooked("b*", Lab.b);
+ break;
+
+ case icSigLuvData:
+ Print255("L", Encoded[0]);
+ Print255("u", Encoded[1]);
+ Print255("v", Encoded[2]);
+ break;
+
+ case icSigYCbCrData:
+ Print255("Y", Encoded[0]);
+ Print255("Cb", Encoded[1]);
+ Print255("Cr", Encoded[2]);
+ break;
+
+
+ case icSigYxyData:
+ Print255("Y", Encoded[0]);
+ Print255("x", Encoded[1]);
+ Print255("y", Encoded[2]);
+ break;
+
+ case icSigRgbData:
+ Print255("R", Encoded[0]);
+ Print255("G", Encoded[1]);
+ Print255("B", Encoded[2]);
+ break;
+
+ case icSigGrayData:
+ Print255("G", Encoded[0]);
+ break;
+
+ case icSigHsvData:
+ Print255("H", Encoded[0]);
+ Print255("s", Encoded[1]);
+ Print255("v", Encoded[2]);
+ break;
+
+ case icSigHlsData:
+ Print255("H", Encoded[0]);
+ Print255("l", Encoded[1]);
+ Print255("s", Encoded[2]);
+ break;
+
+ case icSigCmykData:
+ Print100("C", Encoded[0]);
+ Print100("M", Encoded[1]);
+ Print100("Y", Encoded[2]);
+ Print100("K", Encoded[3]);
+ break;
+
+ case icSigCmyData:
+ Print100("C", Encoded[0]);
+ Print100("M", Encoded[1]);
+ Print100("Y", Encoded[2]);
+ break;
+
+
+
+ default:
+
+ for (i=0; i < _cmsChannelsOf(OutputColorSpace); i++) {
+
+ char Buffer[256];
+
+ if (OutputColorant)
+ sprintf(Buffer, "%s", OutputColorant->List[i].Name);
+ else
+ sprintf(Buffer, "Channel #%d", i + 1);
+
+ Print255(Buffer, Encoded[i]);
+ }
+ }
+
+ printf("\n");
+}
+
+
+// Get input from user
+
+static
+void GetLine(char* Buffer)
+{
+ scanf("%s", Buffer);
+
+ if (toupper(Buffer[0]) == 'Q') { // Quit?
+
+ CloseTransforms();
+
+ if (xisatty(stdin))
+ printf("Done.\n");
+
+ exit(0);
+ }
+
+}
+
+
+// Ask for a value
+
+static
+double GetAnswer(const char* Prompt, double Range)
+{
+ char Buffer[4096];
+ double val = 0.0;
+
+ if (Range == 0.0) { // Range 0 means double value
+
+ if (xisatty(stdin)) printf("%s? ", Prompt);
+ GetLine(Buffer);
+ return atof(Buffer);
+
+ }
+ else {
+
+ if (InHexa) { // Hexadecimal
+
+ int hexa;
+
+ if (Width16)
+ Range = 0xFFFF;
+ else
+ Range = 0xFF;
+
+ if (xisatty(stdin)) printf("%s (0..%X)? ", Prompt, (int) Range);
+ GetLine(Buffer);
+ sscanf(Buffer, "%x", &hexa);
+ val = hexa;
+ }
+ else { // Normal usage
+
+ if (xisatty(stdin)) printf("%s (0..%d)? ", Prompt, (int) Range);
+ GetLine(Buffer);
+ sscanf(Buffer, "%lf", &val);
+ }
+
+ // Normalize to 0..0xffff
+
+ if (val > Range) return 0xFFFF;
+ return floor((val * 65535.0) / Range + 0.5);
+
+ }
+}
+
+
+// Get a value in %
+static
+WORD Get100(const char* AskFor)
+{
+ return (WORD) GetAnswer(AskFor, lUse255always ? 255.0 : 100.0);
+}
+
+
+// Get a simple value in 0..255 range
+
+static
+WORD GetVal(const char* AskFor)
+{
+ return (WORD) GetAnswer(AskFor, 255.0);
+}
+
+// Get a double value
+static
+double GetDbl(const char* AskFor)
+{
+ return GetAnswer(AskFor, 0.0);
+}
+
+
+// Get a named-color index
+static
+WORD GetIndex(void)
+{
+ char Buffer[4096], Name[40], Prefix[40], Suffix[40];
+ int index, max;
+
+ max = cmsNamedColorCount(hTrans)-1;
+
+ if (xisatty(stdin)) printf("Color index (0..%d)? ", max);
+
+ GetLine(Buffer);
+ index = atoi(Buffer);
+
+ if (index > max)
+ FatalError("icctrans: Named color %d out of range!", index);
+
+ cmsNamedColorInfo(hTrans, index, Name, Prefix, Suffix);
+
+ printf("\n%s %s %s: ", Prefix, Name, Suffix);
+
+ return index;
+}
+
+
+
+// Read values from a text file or terminal
+
+static
+void TakeTextValues(WORD Encoded[])
+{
+
+ if (xisatty(stdin))
+ printf("\nEnter values, 'q' to quit\n");
+
+ if (cmsGetDeviceClass(hInput) == icSigNamedColorClass) {
+
+ Encoded[0] = GetIndex();
+ return;
+ }
+
+ switch (InputColorSpace) {
+
+ case icSigXYZData:
+ xyz.X = GetDbl("X");
+ xyz.Y = GetDbl("Y");
+ xyz.Z = GetDbl("Z");
+ cmsFloat2XYZEncoded(Encoded, &xyz);
+ break;
+
+ case icSigLabData:
+ Lab.L = GetDbl("L*");
+ Lab.a = GetDbl("a*");
+ Lab.b = GetDbl("b*");
+ cmsFloat2LabEncoded(Encoded, &Lab);
+ break;
+
+ case icSigLuvData:
+ Encoded[0] = GetVal("L");
+ Encoded[1] = GetVal("u");
+ Encoded[2] = GetVal("v");
+ break;
+
+ case icSigYCbCrData:
+ Encoded[0] = GetVal("Y");
+ Encoded[1] = GetVal("Cb");
+ Encoded[2] = GetVal("Cr");
+ break;
+
+
+ case icSigYxyData:
+ Encoded[0] = GetVal("Y");
+ Encoded[1] = GetVal("x");
+ Encoded[2] = GetVal("y");
+ break;
+
+ case icSigRgbData:
+ Encoded[0] = GetVal("R");
+ Encoded[1] = GetVal("G");
+ Encoded[2] = GetVal("B");
+ break;
+
+ case icSigGrayData:
+ Encoded[0] = GetVal("G");
+ break;
+
+ case icSigHsvData:
+ Encoded[0] = GetVal("H");
+ Encoded[1] = GetVal("s");
+ Encoded[2] = GetVal("v");
+ break;
+
+ case icSigHlsData:
+ Encoded[0] = GetVal("H");
+ Encoded[1] = GetVal("l");
+ Encoded[2] = GetVal("s");
+ break;
+
+ case icSigCmykData:
+ Encoded[0] = Get100("C");
+ Encoded[1] = Get100("M");
+ Encoded[2] = Get100("Y");
+ Encoded[3] = Get100("K");
+ break;
+
+ case icSigCmyData:
+ Encoded[0] = Get100("C");
+ Encoded[1] = Get100("M");
+ Encoded[2] = Get100("Y");
+ break;
+
+ case icSigHexachromeData:
+ Encoded[0] = Get100("C"); Encoded[1] = Get100("M");
+ Encoded[2] = Get100("Y"); Encoded[3] = Get100("K");
+ Encoded[4] = Get100("c"); Encoded[5] = Get100("m");
+ break;
+
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSig4colorData:
+ case icSig5colorData:
+ case icSig6colorData:
+ case icSig7colorData:
+ case icSig8colorData:
+ case icSigMCH5Data:
+ case icSigMCH7Data:
+ case icSigMCH8Data:
+ case icSigMCH9Data:
+ case icSigMCHAData:
+ case icSigMCHBData:
+ case icSigMCHCData:
+ case icSigMCHDData:
+ case icSigMCHEData:
+ case icSigMCHFData:
+
+ {
+
+ int i;
+
+ for (i=0; i < _cmsChannelsOf(InputColorSpace); i++) {
+
+ char Name[256];
+
+ if (InputColorant)
+ sprintf(Name, "%s", InputColorant->List[i].Name);
+ else
+ sprintf(Name, "Channel #%d", i+1);
+
+ Encoded[i] = GetVal(Name);
+ }
+ }
+ break;
+
+ default:
+ FatalError("icctrans: Unsupported %d channel profile", _cmsChannelsOf(InputColorSpace));
+ }
+
+ if (xisatty(stdin))
+ printf("\n");
+
+}
+
+
+
+// Take a value from IT8 and scale it accordly to fill a WORD (0..FFFF)
+
+static
+WORD GetIT8Val(const char* Name, double Max)
+{
+ double CGATSfactor = 65535.0 / Max;
+ double res;
+ const char* Val = cmsIT8GetData(hIT8in, CGATSPatch, Name);
+
+ if (Val == NULL)
+ FatalError("icctrans: Field '%s' not found", Name);
+
+ res = atof(Val);
+ if (res > Max) return 0xFFFF;
+
+ return (WORD) floor(res * CGATSfactor + 0.5);
+
+}
+
+
+// Read input values from CGATS file.
+
+static
+void TakeCGATSValues(int nPatch, WORD Encoded[])
+{
+ // At first take the name if SAMPLE_ID is present
+ if (cmsIT8GetPatchName(hIT8in, nPatch, CGATSPatch) == NULL) {
+ FatalError("icctrans: Sorry, I need 'SAMPLE_ID' on input CGATS to operate.");
+ }
+
+
+ // Special handling for named color profiles.
+ // Lookup the name in the names database (the transform)
+
+ if (cmsGetDeviceClass(hInput) == icSigNamedColorClass) {
+
+ int index = cmsNamedColorIndex(hTrans, CGATSPatch);
+ if (index < 0)
+ FatalError("icctrans: Named color '%s' not found in the profile", CGATSPatch);
+
+ Encoded[0] = (WORD) index;
+ return;
+ }
+
+ // Color is not a spot color, proceed.
+
+ switch (InputColorSpace) {
+
+
+ // Encoding should follow CGATS specification.
+
+ case icSigXYZData:
+ xyz.X = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "XYZ_X") / 100.0;
+ xyz.Y = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "XYZ_Y") / 100.0;
+ xyz.Z = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "XYZ_Z") / 100.0;
+ cmsFloat2XYZEncoded(Encoded, &xyz);
+ break;
+
+ case icSigLabData:
+ Lab.L = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "LAB_L");
+ Lab.a = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "LAB_A");
+ Lab.b = cmsIT8GetDataDbl(hIT8in, CGATSPatch, "LAB_B");
+ cmsFloat2LabEncoded(Encoded, &Lab);
+ break;
+
+
+ case icSigRgbData:
+ Encoded[0] = GetIT8Val("RGB_R", 255.0);
+ Encoded[1] = GetIT8Val("RGB_G", 255.0);
+ Encoded[2] = GetIT8Val("RGB_B", 255.0);
+ break;
+
+ case icSigGrayData:
+ Encoded[0] = GetIT8Val("GRAY", 255.0);
+ break;
+
+ case icSigCmykData:
+ Encoded[0] = GetIT8Val("CMYK_C", lUse255always ? 255.0 : 100.0);
+ Encoded[1] = GetIT8Val("CMYK_M", lUse255always ? 255.0 : 100.0);
+ Encoded[2] = GetIT8Val("CMYK_Y", lUse255always ? 255.0 : 100.0);
+ Encoded[3] = GetIT8Val("CMYK_K", lUse255always ? 255.0 : 100.0);
+ break;
+
+ case icSigCmyData:
+ Encoded[0] = GetIT8Val("CMY_C", lUse255always ? 255.0 : 100.0);
+ Encoded[1] = GetIT8Val("CMY_M", lUse255always ? 255.0 : 100.0);
+ Encoded[2] = GetIT8Val("CMY_Y", lUse255always ? 255.0 : 100.0);
+ break;
+
+ default: {
+
+ int i;
+
+ for (i=0; i < _cmsChannelsOf(InputColorSpace); i++) {
+
+ char Buffer[255];
+
+ sprintf(Buffer, "CHAN_%d", i);
+ Encoded[i] = GetIT8Val(Buffer, 255.0);
+ }
+
+ }
+ }
+
+}
+
+
+static
+void SetCGATSfld(const char* Col, double Val)
+{
+
+ if (lQuantize)
+ Val = floor(Val + 0.5);
+
+ if (!cmsIT8SetDataDbl(hIT8out, CGATSPatch, Col, Val)) {
+ FatalError("icctrans: couldn't set '%s' on output cgats '%s'", Col, CGATSoutFilename);
+ }
+}
+
+
+
+static
+void PutCGATSValues(int nPatch, WORD Encoded[])
+{
+
+ cmsIT8SetData(hIT8out, CGATSPatch, "SAMPLE_ID", CGATSPatch);
+ switch (OutputColorSpace) {
+
+
+ // Encoding should follow CGATS specification.
+
+ case icSigXYZData:
+ cmsXYZEncoded2Float(&xyz, Encoded);
+ SetCGATSfld("XYZ_X", xyz.X * 100.0);
+ SetCGATSfld("XYZ_Y", xyz.Y * 100.0);
+ SetCGATSfld("XYZ_Z", xyz.Z * 100.0);
+ break;
+
+ case icSigLabData:
+ cmsLabEncoded2Float(&Lab, Encoded);
+ SetCGATSfld("LAB_L", Lab.L);
+ SetCGATSfld("LAB_A", Lab.a);
+ SetCGATSfld("LAB_B", Lab.b);
+ break;
+
+
+ case icSigRgbData:
+ SetCGATSfld("RGB_R", Encoded[0] / 257.0);
+ SetCGATSfld("RGB_G", Encoded[1] / 257.0);
+ SetCGATSfld("RGB_B", Encoded[2] / 257.0);
+ break;
+
+ case icSigGrayData:
+ SetCGATSfld("GRAY", Encoded[0] / 257.0);
+ break;
+
+ case icSigCmykData:
+ SetCGATSfld("CMYK_C", (lUse255always ? 255.0 : 100.0) * Encoded[0] / 65535.0);
+ SetCGATSfld("CMYK_M", (lUse255always ? 255.0 : 100.0) * Encoded[1] / 65535.0);
+ SetCGATSfld("CMYK_Y", (lUse255always ? 255.0 : 100.0) * Encoded[2] / 65535.0);
+ SetCGATSfld("CMYK_K", (lUse255always ? 255.0 : 100.0) * Encoded[3] / 65535.0);
+ break;
+
+ case icSigCmyData:
+ SetCGATSfld("CMY_C", (lUse255always ? 255.0 : 100.0) * Encoded[0] / 65535.0);
+ SetCGATSfld("CMY_M", (lUse255always ? 255.0 : 100.0) * Encoded[1] / 65535.0);
+ SetCGATSfld("CMY_Y", (lUse255always ? 255.0 : 100.0) * Encoded[2] / 65535.0);
+ break;
+
+ default: {
+
+ int i;
+
+ for (i=1; i <= _cmsChannelsOf(OutputColorSpace); i++) {
+
+ char Buffer[255];
+
+ sprintf(Buffer, "CHAN_%d", i);
+ SetCGATSfld(Buffer, Encoded[i-1] / 257.0);
+ }
+ }
+ }
+}
+
+
+// Print XYZ/Lab values on verbose mode
+
+static
+void PrintPCS(WORD Input[], WORD PCSxyz[], WORD PCSLab[])
+{
+ if (Verbose && hTransXYZ && hTransLab) {
+
+ if (hTransXYZ) cmsDoTransform(hTransXYZ, Input, PCSxyz, 1);
+ if (hTransLab) cmsDoTransform(hTransLab, Input, PCSLab, 1);
+
+ PrintResults(PCSxyz, icSigXYZData);
+ PrintResults(PCSLab, icSigLabData);
+ }
+}
+
+
+
+// Create data format
+
+
+static
+void SetOutputDataFormat()
+{
+
+ cmsIT8SetPropertyStr(hIT8out, "ORIGINATOR", "icctrans");
+
+ if (IncludePart != NULL)
+ cmsIT8SetPropertyStr(hIT8out, ".INCLUDE", IncludePart);
+
+ cmsIT8SetComment(hIT8out, "Data follows");
+ cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_SETS", nMaxPatches);
+
+
+ switch (OutputColorSpace) {
+
+
+ // Encoding should follow CGATS specification.
+
+ case icSigXYZData:
+ cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 4);
+ cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
+ cmsIT8SetDataFormat(hIT8out, 1, "XYZ_X");
+ cmsIT8SetDataFormat(hIT8out, 2, "XYZ_Y");
+ cmsIT8SetDataFormat(hIT8out, 3, "XYZ_Z");
+ break;
+
+ case icSigLabData:
+ cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 4);
+ cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
+ cmsIT8SetDataFormat(hIT8out, 1, "LAB_L");
+ cmsIT8SetDataFormat(hIT8out, 2, "LAB_A");
+ cmsIT8SetDataFormat(hIT8out, 3, "LAB_B");
+ break;
+
+
+ case icSigRgbData:
+ cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 4);
+ cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
+ cmsIT8SetDataFormat(hIT8out, 1, "RGB_R");
+ cmsIT8SetDataFormat(hIT8out, 2, "RGB_G");
+ cmsIT8SetDataFormat(hIT8out, 3, "RGB_B");
+ break;
+
+ case icSigGrayData:
+ cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 2);
+ cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
+ cmsIT8SetDataFormat(hIT8out, 1, "GRAY");
+ break;
+
+ case icSigCmykData:
+ cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 5);
+ cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
+ cmsIT8SetDataFormat(hIT8out, 1, "CMYK_C");
+ cmsIT8SetDataFormat(hIT8out, 2, "CMYK_M");
+ cmsIT8SetDataFormat(hIT8out, 3, "CMYK_Y");
+ cmsIT8SetDataFormat(hIT8out, 4, "CMYK_K");
+ break;
+
+ case icSigCmyData:
+ cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", 4);
+ cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
+ cmsIT8SetDataFormat(hIT8out, 1, "CMY_C");
+ cmsIT8SetDataFormat(hIT8out, 2, "CMY_M");
+ cmsIT8SetDataFormat(hIT8out, 3, "CMY_Y");
+ break;
+
+ default: {
+
+ int i, n;
+ char Buffer[255];
+
+ n = _cmsChannelsOf(OutputColorSpace);
+ cmsIT8SetPropertyDbl(hIT8out, "NUMBER_OF_FIELDS", n+1);
+ cmsIT8SetDataFormat(hIT8out, 0, "SAMPLE_ID");
+
+ for (i=1; i <= n; i++) {
+ sprintf(Buffer, "CHAN_%d", i);
+ cmsIT8SetDataFormat(hIT8out, i, Buffer);
+ }
+ }
+ }
+}
+
+// Open CGATS if specified
+
+static
+void OpenCGATSFiles(int argc, char *argv[])
+{
+ int nParams = argc - xoptind;
+
+ if (nParams >= 1) {
+
+ hIT8in = cmsIT8LoadFromFile(argv[xoptind]);
+
+ if (hIT8in == NULL)
+ FatalError("icctrans: '%s' is not recognized as a CGATS file", argv[xoptind]);
+
+ nMaxPatches = (int) cmsIT8GetPropertyDbl(hIT8in, "NUMBER_OF_SETS");
+ }
+
+
+ if (nParams == 2) {
+
+ hIT8out = cmsIT8Alloc();
+ SetOutputDataFormat();
+ strncpy(CGATSoutFilename, argv[xoptind+1], MAX_PATH-1);
+ }
+
+ if (nParams > 2) FatalError("icctrans: Too many CGATS files");
+}
+
+
+
+// The main sink
+
+int main(int argc, char *argv[])
+{
+ WORD Input[MAXCHANNELS];
+ WORD Output[MAXCHANNELS];
+ WORD PCSLab[MAXCHANNELS];
+ WORD PCSxyz[MAXCHANNELS];
+ int nPatch = 0;
+
+
+ cmsSetErrorHandler(MyErrorHandler);
+
+ fprintf(stderr, "LittleCMS ColorSpace conversion calculator - v3.3\n\n");
+
+ if (argc == 1)
+ Help();
+
+ HandleSwitches(argc, argv);
+
+ // Open profiles, create transforms
+ OpenTransforms();
+
+ // Open CGATS input if specified
+ OpenCGATSFiles(argc, argv);
+
+ for(;;) {
+
+ if (hIT8in != NULL) {
+
+ if (nPatch >= nMaxPatches) break;
+ TakeCGATSValues(nPatch++, Input);
+
+ } else {
+
+ if (feof(stdin)) break;
+ TakeTextValues(Input);
+
+ }
+
+ cmsDoTransform(hTrans, Input, Output, 1);
+
+
+ if (hIT8out != NULL) {
+
+ PutCGATSValues(nPatch, Output);
+ }
+ else {
+
+ PrintResults(Output, OutputColorSpace);
+ PrintPCS(Input, PCSxyz, PCSLab);
+ }
+ }
+
+
+ CloseTransforms();
+
+ if (hIT8in)
+ cmsIT8Free(hIT8in);
+
+ if (hIT8out) {
+
+ cmsIT8SaveToFile(hIT8out, CGATSoutFilename);
+ cmsIT8Free(hIT8out);
+ }
+
+ return 0;
+}
+
+