diff options
Diffstat (limited to 'debian/lcms/lcms-1.19.dfsg2/samples/icctrans.c')
| -rwxr-xr-x | debian/lcms/lcms-1.19.dfsg2/samples/icctrans.c | 1288 |
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; +} + + |
