| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330 |
- //---------------------------------------------------------------------------------
- //
- // Little Color Management System
- // Copyright (c) 1998-2023 Marti Maria Saguer
- //
- // 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 "utils.h"
- #ifndef _MSC_VER
- # include <unistd.h>
- #endif
- #ifdef CMS_IS_WINDOWS_
- # include <io.h>
- #endif
- #define MAX_INPUT_BUFFER 4096
- // Global options
- static cmsBool InHexa = FALSE;
- static cmsBool GamutCheck = FALSE;
- static cmsBool Width16 = FALSE;
- static cmsBool BlackPointCompensation = FALSE;
- static cmsBool lIsDeviceLink = FALSE;
- static cmsBool lQuantize = FALSE;
- static cmsBool lUnbounded = TRUE;
- static cmsBool lIsFloat = TRUE;
- static cmsUInt32Number Intent = INTENT_PERCEPTUAL;
- static cmsUInt32Number ProofingIntent = INTENT_PERCEPTUAL;
- static int PrecalcMode = 0;
- // --------------------------------------------------------------
- static char *cInProf = NULL;
- static char *cOutProf = NULL;
- static char *cProofing = NULL;
- static char *IncludePart = NULL;
- static cmsHANDLE hIT8in = NULL; // CGATS input
- static cmsHANDLE hIT8out = NULL; // CGATS output
- static char CGATSPatch[1024]; // Actual Patch Name
- static char CGATSoutFilename[cmsMAX_PATH];
- static int nMaxPatches;
- static cmsHTRANSFORM hTrans, hTransXYZ, hTransLab;
- static cmsBool InputNamedColor = FALSE;
- static cmsColorSpaceSignature InputColorSpace, OutputColorSpace;
- static cmsNAMEDCOLORLIST* InputColorant = NULL;
- static cmsNAMEDCOLORLIST* OutputColorant = NULL;
- static cmsFloat64Number InputRange, OutputRange;
- // isatty replacement
- #ifdef _MSC_VER
- #define xisatty(x) _isatty( _fileno( (x) ) )
- #else
- #define xisatty(x) isatty( fileno( (x) ) )
- #endif
- //---------------------------------------------------------------------------------------------------
- // Print usage to stderr
- static
- void Help(void)
- {
- fprintf(stderr, "usage: transicc [flags] [CGATS input] [CGATS output]\n\n");
- fprintf(stderr, "flags:\n\n");
- fprintf(stderr, "-v<0..3> - Verbosity level\n");
- fprintf(stderr, "-e[op] - Encoded representation of numbers\n");
- fprintf(stderr, "\t-w - use 16 bits\n");
- fprintf(stderr, "\t-x - Hexadecimal\n\n");
- fprintf(stderr, "-s - bounded mode (clip negatives and highlights)\n");
- fprintf(stderr, "-q - Quantize (round decimals)\n\n");
- fprintf(stderr, "-i<profile> - Input profile (defaults to sRGB)\n");
- fprintf(stderr, "-o<profile> - Output profile (defaults to sRGB)\n");
- fprintf(stderr, "-l<profile> - Transform by device-link profile\n");
- PrintBuiltins();
- PrintRenderingIntents(NULL);
- fprintf(stderr, "\n");
- fprintf(stderr, "-d<0..1> - Observer adaptation state (abs.col. only)\n\n");
- fprintf(stderr, "-b - Black point compensation\n");
- fprintf(stderr, "-c<0,1,2,3> Precalculates transform (0=Off, 1=Normal, 2=Hi-res, 3=LoRes)\n\n");
- fprintf(stderr, "-n - Terse output, intended for pipe usage\n");
- fprintf(stderr, "-p<profile> - Soft proof profile\n");
- fprintf(stderr, "-m<0,1,2,3> - Soft proof intent\n");
- fprintf(stderr, "-g - Marks out-of-gamut colors on softproof\n\n");
- fprintf(stderr, "This program is intended to be a demo of the Little CMS\n"
- "color engine. Both lcms and this program are open source.\n"
- "You can obtain both in source code at https://www.littlecms.com\n"
- "For suggestions, comments, bug reports etc. send mail to\n"
- "info@littlecms.com\n\n");
- }
- // The toggles stuff
- static
- void HandleSwitches(cmsContext ContextID, int argc, char *argv[])
- {
- int s;
- while ((s = xgetopt(argc, argv,
- "bBC:c:d:D:eEgGI:i:L:l:m:M:nNO:o:p:P:QqSsT:t:V:v:WwxX!:-:")) != EOF) {
- switch (s){
- case '-':
- if (strcmp(xoptarg, "help") == 0)
- {
- Help();
- exit(0);
- }
- else
- {
- FatalError("Unknown option - run without args to see valid ones.\n");
- }
- 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("Unknown precalc mode '%d'", PrecalcMode);
- break;
- case 'd':
- case 'D': {
- cmsFloat64Number ObserverAdaptationState = atof(xoptarg);
- if (ObserverAdaptationState < 0 ||
- ObserverAdaptationState > 1.0)
- FatalError("Adaptation states should be between 0 and 1");
- cmsSetAdaptationState(ContextID, ObserverAdaptationState);
- }
- break;
- case 'e':
- case 'E':
- lIsFloat = FALSE;
- 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;
- // No extra intents for proofing
- case 'm':
- case 'M':
- ProofingIntent = atoi(xoptarg);
- if (ProofingIntent > 3)
- FatalError("Unknown Proofing Intent '%d'", ProofingIntent);
- break;
- // For compatibility
- case 'n':
- case 'N':
- Verbose = 0;
- break;
- // Output profile
- case 'o':
- case 'O':
- if (lIsDeviceLink)
- FatalError("icctrans: Device-link already specified");
- cOutProf = xoptarg;
- break;
- // Proofing profile
- case 'p':
- case 'P':
- cProofing = xoptarg;
- break;
- // Quantize (get rid of decimals)
- case 'q':
- case 'Q':
- lQuantize = TRUE;
- break;
- // Inhibit unbounded mode
- case 's':
- case 'S':
- lUnbounded = FALSE;
- break;
- // The intent
- case 't':
- case 'T':
- Intent = atoi(xoptarg);
- break;
- // Verbosity level
- case 'V':
- case 'v':
- Verbose = atoi(xoptarg);
- if (Verbose < 0 || Verbose > 3) {
- FatalError("Unknown verbosity level '%d'", Verbose);
- }
- break;
- // Wide (16 bits)
- case 'W':
- case 'w':
- Width16 = TRUE;
- break;
- // Hexadecimal
- case 'x':
- case 'X':
- InHexa = TRUE;
- break;
- default:
- FatalError("Unknown option - run without args to see valid ones.\n");
- }
- }
- // If output CGATS involved, switch to float
- if ((argc - xoptind) > 2) {
- lIsFloat = TRUE;
- }
- }
- static
- void SetRange(cmsFloat64Number range, cmsBool IsInput)
- {
- if (IsInput)
- InputRange = range;
- else
- OutputRange = range;
- }
- // Populate a named color list with usual component names.
- // I am using the first Colorant channel to store the range, but it works since
- // this space is not used anyway.
- static
- cmsNAMEDCOLORLIST* ComponentNames(cmsContext ContextID, cmsColorSpaceSignature space, cmsBool IsInput)
- {
- cmsNAMEDCOLORLIST* out;
- int i, n;
- char Buffer[cmsMAX_PATH];
- out = cmsAllocNamedColorList(0, 12, cmsMAXCHANNELS, "", "");
- if (out == NULL) return NULL;
- switch (space) {
- case cmsSigXYZData:
- SetRange(100, IsInput);
- cmsAppendNamedColor(ContextID, out, "X", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "Z", NULL, NULL);
- break;
- case cmsSigLabData:
- SetRange(1, IsInput);
- cmsAppendNamedColor(ContextID, out, "L*", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "a*", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "b*", NULL, NULL);
- break;
- case cmsSigLuvData:
- SetRange(1, IsInput);
- cmsAppendNamedColor(ContextID, out, "L", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "u", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "v", NULL, NULL);
- break;
- case cmsSigYCbCrData:
- SetRange(255, IsInput);
- cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL );
- cmsAppendNamedColor(ContextID, out, "Cb", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "Cr", NULL, NULL);
- break;
- case cmsSigYxyData:
- SetRange(1, IsInput);
- cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "x", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "y", NULL, NULL);
- break;
- case cmsSigRgbData:
- SetRange(255, IsInput);
- cmsAppendNamedColor(ContextID, out, "R", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "G", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "B", NULL, NULL);
- break;
- case cmsSigGrayData:
- SetRange(255, IsInput);
- cmsAppendNamedColor(ContextID, out, "G", NULL, NULL);
- break;
- case cmsSigHsvData:
- SetRange(255, IsInput);
- cmsAppendNamedColor(ContextID, out, "H", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "s", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "v", NULL, NULL);
- break;
- case cmsSigHlsData:
- SetRange(255, IsInput);
- cmsAppendNamedColor(ContextID, out, "H", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "l", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "s", NULL, NULL);
- break;
- case cmsSigCmykData:
- SetRange(1, IsInput);
- cmsAppendNamedColor(ContextID, out, "C", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "M", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "K", NULL, NULL);
- break;
- case cmsSigCmyData:
- SetRange(1, IsInput);
- cmsAppendNamedColor(ContextID, out, "C", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "M", NULL, NULL);
- cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL);
- break;
- default:
- SetRange(1, IsInput);
- n = cmsChannelsOfColorSpace(ContextID, space);
- for (i=0; i < n; i++) {
- sprintf(Buffer, "Channel #%d", i + 1);
- cmsAppendNamedColor(ContextID, out, Buffer, NULL, NULL);
- }
- }
- return out;
- }
- // Creates all needed color transforms
- static
- cmsBool OpenTransforms(cmsContext ContextID)
- {
- cmsHPROFILE hInput, hOutput, hProof;
- cmsUInt32Number dwIn, dwOut, dwFlags;
- cmsNAMEDCOLORLIST* List;
- int i;
- // We don't need cache
- dwFlags = cmsFLAGS_NOCACHE;
- if (lIsDeviceLink) {
- hInput = OpenStockProfile(0, cInProf);
- if (hInput == NULL) return FALSE;
- hOutput = NULL;
- hProof = NULL;
- if (cmsGetDeviceClass(ContextID, hInput) == cmsSigNamedColorClass) {
- OutputColorSpace = cmsGetColorSpace(ContextID, hInput);
- InputColorSpace = cmsGetPCS(ContextID, hInput);
- }
- else {
- InputColorSpace = cmsGetColorSpace(ContextID, hInput);
- OutputColorSpace = cmsGetPCS(ContextID, hInput);
- }
- // Read colorant tables if present
- if (cmsIsTag(ContextID, hInput, cmsSigColorantTableTag)) {
- List = cmsReadTag(ContextID, hInput, cmsSigColorantTableTag);
- InputColorant = cmsDupNamedColorList(ContextID, List);
- InputRange = 1;
- }
- else InputColorant = ComponentNames(ContextID, InputColorSpace, TRUE);
- if (cmsIsTag(ContextID, hInput, cmsSigColorantTableOutTag)){
- List = cmsReadTag(ContextID, hInput, cmsSigColorantTableOutTag);
- OutputColorant = cmsDupNamedColorList(ContextID, List);
- OutputRange = 1;
- }
- else OutputColorant = ComponentNames(ContextID, OutputColorSpace, FALSE);
- }
- else {
- hInput = OpenStockProfile(0, cInProf);
- if (hInput == NULL) return FALSE;
- hOutput = OpenStockProfile(0, cOutProf);
- if (hOutput == NULL) return FALSE;
- hProof = NULL;
- if (cmsGetDeviceClass(ContextID, hInput) == cmsSigLinkClass ||
- cmsGetDeviceClass(ContextID, hOutput) == cmsSigLinkClass)
- FatalError("Use -l flag for devicelink profiles!\n");
- InputColorSpace = cmsGetColorSpace(ContextID, hInput);
- OutputColorSpace = cmsGetColorSpace(ContextID, hOutput);
- // Read colorant tables if present
- if (cmsIsTag(ContextID, hInput, cmsSigColorantTableTag)) {
- List = cmsReadTag(ContextID, hInput, cmsSigColorantTableTag);
- InputColorant = cmsDupNamedColorList(ContextID, List);
- if (cmsNamedColorCount(ContextID, InputColorant) <= 3)
- SetRange(255, TRUE);
- else
- SetRange(1, TRUE); // Inks are already divided by 100 in the formatter
- }
- else InputColorant = ComponentNames(ContextID, InputColorSpace, TRUE);
- if (cmsIsTag(ContextID, hOutput, cmsSigColorantTableTag)){
- List = cmsReadTag(ContextID, hOutput, cmsSigColorantTableTag);
- OutputColorant = cmsDupNamedColorList(ContextID, List);
- if (cmsNamedColorCount(ContextID, OutputColorant) <= 3)
- SetRange(255, FALSE);
- else
- SetRange(1, FALSE); // Inks are already divided by 100 in the formatter
- }
- else OutputColorant = ComponentNames(ContextID, OutputColorSpace, FALSE);
- if (cProofing != NULL) {
- hProof = OpenStockProfile(0, cProofing);
- if (hProof == NULL) return FALSE;
- dwFlags |= cmsFLAGS_SOFTPROOFING;
- }
- }
- // Print information on profiles
- if (Verbose > 2) {
- printf("Profile:\n");
- PrintProfileInformation(ContextID, hInput);
- if (hOutput) {
- printf("Output profile:\n");
- PrintProfileInformation(ContextID, hOutput);
- }
- if (hProof != NULL) {
- printf("Proofing profile:\n");
- PrintProfileInformation(ContextID, hProof);
- }
- }
- // Input is always in floating point
- dwIn = cmsFormatterForColorspaceOfProfile(ContextID, hInput, 0, TRUE);
- if (lIsDeviceLink) {
- dwOut = cmsFormatterForPCSOfProfile(ContextID, hInput, lIsFloat ? 0 : 2, lIsFloat);
- }
- else {
- // 16 bits or floating point (only on output)
- dwOut = cmsFormatterForColorspaceOfProfile(ContextID, hOutput, lIsFloat ? 0 : 2, lIsFloat);
- }
- // For named color, there is a specialized formatter
- if (cmsGetDeviceClass(ContextID, hInput) == cmsSigNamedColorClass) {
- dwIn = TYPE_NAMED_COLOR_INDEX;
- InputNamedColor = TRUE;
- }
- // Precision mode
- switch (PrecalcMode) {
- case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break;
- case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
- case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
- case 1: break;
- default:
- FatalError("Unknown precalculation mode '%d'", PrecalcMode);
- }
- if (BlackPointCompensation)
- dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
- if (GamutCheck) {
- cmsUInt16Number Alarm[cmsMAXCHANNELS];
- if (hProof == NULL)
- FatalError("I need proofing profile -p for gamut checking!");
- for (i=0; i < cmsMAXCHANNELS; i++)
- Alarm[i] = 0xFFFF;
- cmsSetAlarmCodes(ContextID, Alarm);
- dwFlags |= cmsFLAGS_GAMUTCHECK;
- }
- // The main transform
- hTrans = cmsCreateProofingTransform(ContextID, hInput, dwIn, hOutput, dwOut, hProof, Intent, ProofingIntent, dwFlags);
- if (hProof) cmsCloseProfile(ContextID, hProof);
- if (hTrans == NULL) return FALSE;
- // PCS Dump if requested
- hTransXYZ = NULL; hTransLab = NULL;
- if (hOutput && Verbose > 1) {
- cmsHPROFILE hXYZ = cmsCreateXYZProfile(ContextID);
- cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
- hTransXYZ = cmsCreateTransform(ContextID, hInput, dwIn, hXYZ, lIsFloat ? TYPE_XYZ_DBL : TYPE_XYZ_16, Intent, cmsFLAGS_NOCACHE);
- if (hTransXYZ == NULL) return FALSE;
- hTransLab = cmsCreateTransform(ContextID, hInput, dwIn, hLab, lIsFloat? TYPE_Lab_DBL : TYPE_Lab_16, Intent, cmsFLAGS_NOCACHE);
- if (hTransLab == NULL) return FALSE;
- cmsCloseProfile(ContextID, hXYZ);
- cmsCloseProfile(ContextID, hLab);
- }
- if (hInput) cmsCloseProfile(ContextID, hInput);
- if (hOutput) cmsCloseProfile(ContextID, hOutput);
- return TRUE;
- }
- // Free open resources
- static
- void CloseTransforms(cmsContext ContextID)
- {
- if (InputColorant) cmsFreeNamedColorList(ContextID, InputColorant);
- if (OutputColorant) cmsFreeNamedColorList(ContextID, OutputColorant);
- if (hTrans) cmsDeleteTransform(ContextID, hTrans);
- if (hTransLab) cmsDeleteTransform(ContextID, hTransLab);
- if (hTransXYZ) cmsDeleteTransform(ContextID, hTransXYZ);
- }
- // ---------------------------------------------------------------------------------------------------
- // Get input from user
- static
- void GetLine(cmsContext ContextID, char* Buffer, const char* frm, ...)
- {
- int res;
- va_list args;
- va_start(args, frm);
- do {
- if (xisatty(stdin))
- vfprintf(stderr, frm, args);
- res = scanf("%4095s", Buffer);
- if (res < 0 || toupper(Buffer[0]) == 'Q') { // Quit?
- CloseTransforms(ContextID);
- if (xisatty(stdin))
- fprintf(stderr, "Done.\n");
- exit(0);
- }
- } while (res == 0);
- va_end(args);
- }
- // Print a value which is given in double floating point
- static
- void PrintFloatResults(cmsContext ContextID, cmsFloat64Number Value[])
- {
- cmsUInt32Number i, n;
- char ChannelName[cmsMAX_PATH];
- cmsFloat64Number v;
- n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace);
- for (i=0; i < n; i++) {
- if (OutputColorant != NULL) {
- cmsNamedColorInfo(ContextID, OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
- }
- else {
- OutputRange = 1;
- sprintf(ChannelName, "Channel #%u", i + 1);
- }
- v = (cmsFloat64Number) Value[i]* OutputRange;
- if (lQuantize)
- v = floor(v + 0.5);
- if (!lUnbounded) {
- if (v < 0)
- v = 0;
- if (v > OutputRange)
- v = OutputRange;
- }
- if (Verbose <= 0)
- printf("%.4f ", v);
- else
- printf("%s=%.4f ", ChannelName, v);
- }
- printf("\n");
- }
- // Get a named-color index
- static
- cmsUInt16Number GetIndex(cmsContext ContextID)
- {
- char Buffer[4096], Name[cmsMAX_PATH], Prefix[40], Suffix[40];
- int index, max;
- const cmsNAMEDCOLORLIST* NamedColorList;
- NamedColorList = cmsGetNamedColorList(hTrans);
- if (NamedColorList == NULL) return 0;
- max = cmsNamedColorCount(ContextID, NamedColorList)-1;
- GetLine(ContextID, Buffer, "Color index (0..%d)? ", max);
- index = atoi(Buffer);
- if (index > max)
- FatalError("Named color %d out of range!", index);
- cmsNamedColorInfo(ContextID, NamedColorList, index, Name, Prefix, Suffix, NULL, NULL);
- printf("\n%s %s %s\n", Prefix, Name, Suffix);
- return (cmsUInt16Number) index;
- }
- // Read values from a text file or terminal
- static
- void TakeFloatValues(cmsContext ContextID, cmsFloat64Number Float[])
- {
- cmsUInt32Number i, n;
- char ChannelName[cmsMAX_PATH];
- char Buffer[4096];
- if (xisatty(stdin))
- fprintf(stderr, "\nEnter values, 'q' to quit\n");
- if (InputNamedColor) {
- // This is named color index, which is always cmsUInt16Number
- cmsUInt16Number index = GetIndex(ContextID);
- memcpy(Float, &index, sizeof(cmsUInt16Number));
- return;
- }
- n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
- for (i=0; i < n; i++) {
- if (InputColorant) {
- cmsNamedColorInfo(ContextID, InputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
- }
- else {
- InputRange = 1;
- sprintf(ChannelName, "Channel #%u", i+1);
- }
- GetLine(ContextID, Buffer, "%s? ", ChannelName);
- Float[i] = (cmsFloat64Number) atof(Buffer) / InputRange;
- }
- if (xisatty(stdin))
- fprintf(stderr, "\n");
- }
- static
- void PrintPCSFloat(cmsContext ContextID, cmsFloat64Number Input[])
- {
- if (Verbose > 1 && hTransXYZ && hTransLab) {
- cmsCIEXYZ XYZ = { 0, 0, 0 };
- cmsCIELab Lab = { 0, 0, 0 };
- if (hTransXYZ) cmsDoTransform(ContextID, hTransXYZ, Input, &XYZ, 1);
- if (hTransLab) cmsDoTransform(ContextID, hTransLab, Input, &Lab, 1);
- printf("[PCS] Lab=(%.4f,%.4f,%.4f) XYZ=(%.4f,%.4f,%.4f)\n", Lab.L, Lab.a, Lab.b,
- XYZ.X * 100.0, XYZ.Y * 100.0, XYZ.Z * 100.0);
- }
- }
- // -----------------------------------------------------------------------------------------------
- static
- void PrintEncodedResults(cmsContext ContextID, cmsUInt16Number Encoded[])
- {
- cmsUInt32Number i, n;
- char ChannelName[cmsMAX_PATH];
- cmsUInt32Number v;
- n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace);
- for (i=0; i < n; i++) {
- if (OutputColorant != NULL) {
- cmsNamedColorInfo(ContextID, OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
- }
- else {
- sprintf(ChannelName, "Channel #%u", i + 1);
- }
- if (Verbose > 0)
- printf("%s=", ChannelName);
- v = Encoded[i];
- if (InHexa) {
- if (Width16)
- printf("0x%04X ", (int) floor(v + .5));
- else
- printf("0x%02X ", (int) floor(v / 257. + .5));
- } else {
- if (Width16)
- printf("%d ", (int) floor(v + .5));
- else
- printf("%d ", (int) floor(v / 257. + .5));
- }
- }
- printf("\n");
- }
- // Print XYZ/Lab values on verbose mode
- static
- void PrintPCSEncoded(cmsContext ContextID, cmsFloat64Number Input[])
- {
- if (Verbose > 1 && hTransXYZ && hTransLab) {
- cmsUInt16Number XYZ[3], Lab[3];
- if (hTransXYZ) cmsDoTransform(ContextID, hTransXYZ, Input, XYZ, 1);
- if (hTransLab) cmsDoTransform(ContextID, hTransLab, Input, Lab, 1);
- printf("[PCS] Lab=(0x%04X,0x%04X,0x%04X) XYZ=(0x%04X,0x%04X,0x%04X)\n", Lab[0], Lab[1], Lab[2],
- XYZ[0], XYZ[1], XYZ[2]);
- }
- }
- // --------------------------------------------------------------------------------------
- // Take a value from IT8 and scale it accordly to fill a cmsUInt16Number (0..FFFF)
- static
- cmsFloat64Number GetIT8Val(cmsContext ContextID, const char* Name, cmsFloat64Number Max)
- {
- const char* Val = cmsIT8GetData(ContextID, hIT8in, CGATSPatch, Name);
- if (Val == NULL)
- FatalError("Field '%s' not found", Name);
- return atof(Val) / Max;
- }
- // Read input values from CGATS file.
- static
- void TakeCGATSValues(cmsContext ContextID, int nPatch, cmsFloat64Number Float[])
- {
- // At first take the name if SAMPLE_ID is present
- if (cmsIT8GetPatchName(ContextID, hIT8in, nPatch, CGATSPatch) == NULL) {
- FatalError("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 (InputNamedColor) {
- const cmsNAMEDCOLORLIST* NamedColorList;
- int index;
- NamedColorList = cmsGetNamedColorList(hTrans);
- if (NamedColorList == NULL)
- FatalError("Malformed named color profile");
- index = cmsNamedColorIndex(ContextID, NamedColorList, CGATSPatch);
- if (index < 0)
- FatalError("Named color '%s' not found in the profile", CGATSPatch);
- Float[0] = index;
- return;
- }
- // Color is not a spot color, proceed.
- switch (InputColorSpace) {
- // Encoding should follow CGATS specification.
- case cmsSigXYZData:
- Float[0] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "XYZ_X") / 100.0;
- Float[1] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "XYZ_Y") / 100.0;
- Float[2] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "XYZ_Z") / 100.0;
- break;
- case cmsSigLabData:
- Float[0] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "LAB_L");
- Float[1] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "LAB_A");
- Float[2] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "LAB_B");
- break;
- case cmsSigRgbData:
- Float[0] = GetIT8Val(ContextID, "RGB_R", 255.0);
- Float[1] = GetIT8Val(ContextID, "RGB_G", 255.0);
- Float[2] = GetIT8Val(ContextID, "RGB_B", 255.0);
- break;
- case cmsSigGrayData:
- Float[0] = GetIT8Val(ContextID, "GRAY", 255.0);
- break;
- case cmsSigCmykData:
- Float[0] = GetIT8Val(ContextID, "CMYK_C", 1.0);
- Float[1] = GetIT8Val(ContextID, "CMYK_M", 1.0);
- Float[2] = GetIT8Val(ContextID, "CMYK_Y", 1.0);
- Float[3] = GetIT8Val(ContextID, "CMYK_K", 1.0);
- break;
- case cmsSigCmyData:
- Float[0] = GetIT8Val(ContextID, "CMY_C", 1.0);
- Float[1] = GetIT8Val(ContextID, "CMY_M", 1.0);
- Float[2] = GetIT8Val(ContextID, "CMY_Y", 1.0);
- break;
- case cmsSig1colorData:
- case cmsSig2colorData:
- case cmsSig3colorData:
- case cmsSig4colorData:
- case cmsSig5colorData:
- case cmsSig6colorData:
- case cmsSig7colorData:
- case cmsSig8colorData:
- case cmsSig9colorData:
- case cmsSig10colorData:
- case cmsSig11colorData:
- case cmsSig12colorData:
- case cmsSig13colorData:
- case cmsSig14colorData:
- case cmsSig15colorData:
- {
- cmsUInt32Number i, n;
- n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
- for (i=0; i < n; i++) {
- char Buffer[255];
- sprintf(Buffer, "%uCLR_%u", n, i+1);
- Float[i] = GetIT8Val(ContextID, Buffer, 100.0);
- }
- }
- break;
- default:
- {
- cmsUInt32Number i, n;
- n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
- for (i=0; i < n; i++) {
- char Buffer[255];
- sprintf(Buffer, "CHAN_%u", i+1);
- Float[i] = GetIT8Val(ContextID, Buffer, 1.0);
- }
- }
- }
- }
- static
- void SetCGATSfld(cmsContext ContextID, const char* Col, cmsFloat64Number Val)
- {
- if (lQuantize)
- Val = floor(Val + 0.5);
- if (!cmsIT8SetDataDbl(ContextID, hIT8out, CGATSPatch, Col, Val)) {
- FatalError("couldn't set '%s' on output cgats '%s'", Col, CGATSoutFilename);
- }
- }
- static
- void PutCGATSValues(cmsContext ContextID, cmsFloat64Number Float[])
- {
- cmsIT8SetData(ContextID, hIT8out, CGATSPatch, "SAMPLE_ID", CGATSPatch);
- switch (OutputColorSpace) {
- // Encoding should follow CGATS specification.
- case cmsSigXYZData:
- SetCGATSfld(ContextID, "XYZ_X", Float[0] * 100.0);
- SetCGATSfld(ContextID, "XYZ_Y", Float[1] * 100.0);
- SetCGATSfld(ContextID, "XYZ_Z", Float[2] * 100.0);
- break;
- case cmsSigLabData:
- SetCGATSfld(ContextID, "LAB_L", Float[0]);
- SetCGATSfld(ContextID, "LAB_A", Float[1]);
- SetCGATSfld(ContextID, "LAB_B", Float[2]);
- break;
- case cmsSigRgbData:
- SetCGATSfld(ContextID, "RGB_R", Float[0] * 255.0);
- SetCGATSfld(ContextID, "RGB_G", Float[1] * 255.0);
- SetCGATSfld(ContextID, "RGB_B", Float[2] * 255.0);
- break;
- case cmsSigGrayData:
- SetCGATSfld(ContextID, "GRAY", Float[0] * 255.0);
- break;
- case cmsSigCmykData:
- SetCGATSfld(ContextID, "CMYK_C", Float[0]);
- SetCGATSfld(ContextID, "CMYK_M", Float[1]);
- SetCGATSfld(ContextID, "CMYK_Y", Float[2]);
- SetCGATSfld(ContextID, "CMYK_K", Float[3]);
- break;
- case cmsSigCmyData:
- SetCGATSfld(ContextID, "CMY_C", Float[0]);
- SetCGATSfld(ContextID, "CMY_M", Float[1]);
- SetCGATSfld(ContextID, "CMY_Y", Float[2]);
- break;
- case cmsSig1colorData:
- case cmsSig2colorData:
- case cmsSig3colorData:
- case cmsSig4colorData:
- case cmsSig5colorData:
- case cmsSig6colorData:
- case cmsSig7colorData:
- case cmsSig8colorData:
- case cmsSig9colorData:
- case cmsSig10colorData:
- case cmsSig11colorData:
- case cmsSig12colorData:
- case cmsSig13colorData:
- case cmsSig14colorData:
- case cmsSig15colorData:
- {
- cmsInt32Number i, n;
- n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
- for (i=0; i < n; i++) {
- char Buffer[255];
- sprintf(Buffer, "%uCLR_%u", n, i+1);
- SetCGATSfld(ContextID, Buffer, Float[i] * 100.0);
- }
- }
- break;
- default:
- {
- cmsInt32Number i, n;
- n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
- for (i=0; i < n; i++) {
- char Buffer[255];
- sprintf(Buffer, "CHAN_%u", i+1);
- SetCGATSfld(ContextID, Buffer, Float[i]);
- }
- }
- }
- }
- // Create data format
- static
- void SetOutputDataFormat(cmsContext ContextID)
- {
- cmsIT8DefineDblFormat(ContextID, hIT8out, "%.4g");
- cmsIT8SetPropertyStr(ContextID, hIT8out, "ORIGINATOR", "icctrans");
- if (IncludePart != NULL)
- cmsIT8SetPropertyStr(ContextID, hIT8out, ".INCLUDE", IncludePart);
- cmsIT8SetComment(ContextID, hIT8out, "Data follows");
- cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_SETS", nMaxPatches);
- switch (OutputColorSpace) {
- // Encoding should follow CGATS specification.
- case cmsSigXYZData:
- cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4);
- cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
- cmsIT8SetDataFormat(ContextID, hIT8out, 1, "XYZ_X");
- cmsIT8SetDataFormat(ContextID, hIT8out, 2, "XYZ_Y");
- cmsIT8SetDataFormat(ContextID, hIT8out, 3, "XYZ_Z");
- break;
- case cmsSigLabData:
- cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4);
- cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
- cmsIT8SetDataFormat(ContextID, hIT8out, 1, "LAB_L");
- cmsIT8SetDataFormat(ContextID, hIT8out, 2, "LAB_A");
- cmsIT8SetDataFormat(ContextID, hIT8out, 3, "LAB_B");
- break;
- case cmsSigRgbData:
- cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4);
- cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
- cmsIT8SetDataFormat(ContextID, hIT8out, 1, "RGB_R");
- cmsIT8SetDataFormat(ContextID, hIT8out, 2, "RGB_G");
- cmsIT8SetDataFormat(ContextID, hIT8out, 3, "RGB_B");
- break;
- case cmsSigGrayData:
- cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 2);
- cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
- cmsIT8SetDataFormat(ContextID, hIT8out, 1, "GRAY");
- break;
- case cmsSigCmykData:
- cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 5);
- cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
- cmsIT8SetDataFormat(ContextID, hIT8out, 1, "CMYK_C");
- cmsIT8SetDataFormat(ContextID, hIT8out, 2, "CMYK_M");
- cmsIT8SetDataFormat(ContextID, hIT8out, 3, "CMYK_Y");
- cmsIT8SetDataFormat(ContextID, hIT8out, 4, "CMYK_K");
- break;
- case cmsSigCmyData:
- cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4);
- cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
- cmsIT8SetDataFormat(ContextID, hIT8out, 1, "CMY_C");
- cmsIT8SetDataFormat(ContextID, hIT8out, 2, "CMY_M");
- cmsIT8SetDataFormat(ContextID, hIT8out, 3, "CMY_Y");
- break;
- case cmsSig1colorData:
- case cmsSig2colorData:
- case cmsSig3colorData:
- case cmsSig4colorData:
- case cmsSig5colorData:
- case cmsSig6colorData:
- case cmsSig7colorData:
- case cmsSig8colorData:
- case cmsSig9colorData:
- case cmsSig10colorData:
- case cmsSig11colorData:
- case cmsSig12colorData:
- case cmsSig13colorData:
- case cmsSig14colorData:
- case cmsSig15colorData:
- {
- int i, n;
- char Buffer[255];
- n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace);
- cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", n+1);
- cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
- for (i=1; i <= n; i++) {
- sprintf(Buffer, "%dCLR_%d", n, i);
- cmsIT8SetDataFormat(ContextID, hIT8out, i, Buffer);
- }
- }
- break;
- default: {
- int i, n;
- char Buffer[255];
- n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace);
- cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", n+1);
- cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
- for (i=1; i <= n; i++) {
- sprintf(Buffer, "CHAN_%d", i);
- cmsIT8SetDataFormat(ContextID, hIT8out, i, Buffer);
- }
- }
- }
- }
- // Open CGATS if specified
- static
- void OpenCGATSFiles(cmsContext ContextID, int argc, char *argv[])
- {
- int nParams = argc - xoptind;
- if (nParams >= 1) {
- hIT8in = cmsIT8LoadFromFile(0, argv[xoptind]);
- if (hIT8in == NULL)
- FatalError("'%s' is not recognized as a CGATS file", argv[xoptind]);
- nMaxPatches = (int) cmsIT8GetPropertyDbl(ContextID, hIT8in, "NUMBER_OF_SETS");
- }
- if (nParams == 2) {
- hIT8out = cmsIT8Alloc(NULL);
- SetOutputDataFormat(ContextID);
- strncpy(CGATSoutFilename, argv[xoptind+1], cmsMAX_PATH-1);
- }
- if (nParams > 2) FatalError("Too many CGATS files");
- }
- // The main sink
- int main(int argc, char *argv[])
- {
- cmsUInt16Number Output[cmsMAXCHANNELS];
- cmsFloat64Number OutputFloat[cmsMAXCHANNELS];
- cmsFloat64Number InputFloat[cmsMAXCHANNELS];
- cmsContext ContextID = NULL;
- int nPatch = 0;
- fprintf(stderr, "LittleCMS ColorSpace conversion calculator - 5.1 [LittleCMS %2.2f]\n", cmsGetEncodedCMMversion() / 1000.0);
- fprintf(stderr, "Copyright (c) 1998-2023 Marti Maria Saguer. See COPYING file for details.\n");
- fflush(stderr);
- InitUtils(ContextID, "transicc");
- Verbose = 1;
- if (argc == 1) {
- Help();
- return 0;
- }
- HandleSwitches(ContextID, argc, argv);
- // Open profiles, create transforms
- if (!OpenTransforms(ContextID)) return 1;
- // Open CGATS input if specified
- OpenCGATSFiles(ContextID, argc, argv);
- // Main loop: read all values and convert them
- for(;;) {
- if (hIT8in != NULL) {
- if (nPatch >= nMaxPatches) break;
- TakeCGATSValues(ContextID, nPatch++, InputFloat);
- } else {
- if (feof(stdin)) break;
- TakeFloatValues(ContextID, InputFloat);
- }
- if (lIsFloat)
- cmsDoTransform(ContextID, hTrans, InputFloat, OutputFloat, 1);
- else
- cmsDoTransform(ContextID, hTrans, InputFloat, Output, 1);
- if (hIT8out != NULL) {
- PutCGATSValues(ContextID, OutputFloat);
- }
- else {
- if (lIsFloat) {
- PrintFloatResults(ContextID, OutputFloat); PrintPCSFloat(ContextID, InputFloat);
- }
- else {
- PrintEncodedResults(ContextID, Output); PrintPCSEncoded(ContextID, InputFloat);
- }
- }
- }
- // Cleanup
- CloseTransforms(ContextID);
- if (hIT8in)
- cmsIT8Free(ContextID, hIT8in);
- if (hIT8out) {
- cmsIT8SaveToFile(ContextID, hIT8out, CGATSoutFilename);
- cmsIT8Free(ContextID, hIT8out);
- }
- // All is ok
- return 0;
- }
|