transicc.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. //---------------------------------------------------------------------------------
  2. //
  3. // Little Color Management System
  4. // Copyright (c) 1998-2023 Marti Maria Saguer
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining
  7. // a copy of this software and associated documentation files (the "Software"),
  8. // to deal in the Software without restriction, including without limitation
  9. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. // and/or sell copies of the Software, and to permit persons to whom the Software
  11. // is furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  18. // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  20. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  21. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. //
  24. //---------------------------------------------------------------------------------
  25. //
  26. #include "utils.h"
  27. #ifndef _MSC_VER
  28. # include <unistd.h>
  29. #endif
  30. #ifdef CMS_IS_WINDOWS_
  31. # include <io.h>
  32. #endif
  33. #define MAX_INPUT_BUFFER 4096
  34. // Global options
  35. static cmsBool InHexa = FALSE;
  36. static cmsBool GamutCheck = FALSE;
  37. static cmsBool Width16 = FALSE;
  38. static cmsBool BlackPointCompensation = FALSE;
  39. static cmsBool lIsDeviceLink = FALSE;
  40. static cmsBool lQuantize = FALSE;
  41. static cmsBool lUnbounded = TRUE;
  42. static cmsBool lIsFloat = TRUE;
  43. static cmsUInt32Number Intent = INTENT_PERCEPTUAL;
  44. static cmsUInt32Number ProofingIntent = INTENT_PERCEPTUAL;
  45. static int PrecalcMode = 0;
  46. // --------------------------------------------------------------
  47. static char *cInProf = NULL;
  48. static char *cOutProf = NULL;
  49. static char *cProofing = NULL;
  50. static char *IncludePart = NULL;
  51. static cmsHANDLE hIT8in = NULL; // CGATS input
  52. static cmsHANDLE hIT8out = NULL; // CGATS output
  53. static char CGATSPatch[1024]; // Actual Patch Name
  54. static char CGATSoutFilename[cmsMAX_PATH];
  55. static int nMaxPatches;
  56. static cmsHTRANSFORM hTrans, hTransXYZ, hTransLab;
  57. static cmsBool InputNamedColor = FALSE;
  58. static cmsColorSpaceSignature InputColorSpace, OutputColorSpace;
  59. static cmsNAMEDCOLORLIST* InputColorant = NULL;
  60. static cmsNAMEDCOLORLIST* OutputColorant = NULL;
  61. static cmsFloat64Number InputRange, OutputRange;
  62. // isatty replacement
  63. #ifdef _MSC_VER
  64. #define xisatty(x) _isatty( _fileno( (x) ) )
  65. #else
  66. #define xisatty(x) isatty( fileno( (x) ) )
  67. #endif
  68. //---------------------------------------------------------------------------------------------------
  69. // Print usage to stderr
  70. static
  71. void Help(void)
  72. {
  73. fprintf(stderr, "usage: transicc [flags] [CGATS input] [CGATS output]\n\n");
  74. fprintf(stderr, "flags:\n\n");
  75. fprintf(stderr, "-v<0..3> - Verbosity level\n");
  76. fprintf(stderr, "-e[op] - Encoded representation of numbers\n");
  77. fprintf(stderr, "\t-w - use 16 bits\n");
  78. fprintf(stderr, "\t-x - Hexadecimal\n\n");
  79. fprintf(stderr, "-s - bounded mode (clip negatives and highlights)\n");
  80. fprintf(stderr, "-q - Quantize (round decimals)\n\n");
  81. fprintf(stderr, "-i<profile> - Input profile (defaults to sRGB)\n");
  82. fprintf(stderr, "-o<profile> - Output profile (defaults to sRGB)\n");
  83. fprintf(stderr, "-l<profile> - Transform by device-link profile\n");
  84. PrintBuiltins();
  85. PrintRenderingIntents(NULL);
  86. fprintf(stderr, "\n");
  87. fprintf(stderr, "-d<0..1> - Observer adaptation state (abs.col. only)\n\n");
  88. fprintf(stderr, "-b - Black point compensation\n");
  89. fprintf(stderr, "-c<0,1,2,3> Precalculates transform (0=Off, 1=Normal, 2=Hi-res, 3=LoRes)\n\n");
  90. fprintf(stderr, "-n - Terse output, intended for pipe usage\n");
  91. fprintf(stderr, "-p<profile> - Soft proof profile\n");
  92. fprintf(stderr, "-m<0,1,2,3> - Soft proof intent\n");
  93. fprintf(stderr, "-g - Marks out-of-gamut colors on softproof\n\n");
  94. fprintf(stderr, "This program is intended to be a demo of the Little CMS\n"
  95. "color engine. Both lcms and this program are open source.\n"
  96. "You can obtain both in source code at https://www.littlecms.com\n"
  97. "For suggestions, comments, bug reports etc. send mail to\n"
  98. "info@littlecms.com\n\n");
  99. }
  100. // The toggles stuff
  101. static
  102. void HandleSwitches(cmsContext ContextID, int argc, char *argv[])
  103. {
  104. int s;
  105. while ((s = xgetopt(argc, argv,
  106. "bBC:c:d:D:eEgGI:i:L:l:m:M:nNO:o:p:P:QqSsT:t:V:v:WwxX!:-:")) != EOF) {
  107. switch (s){
  108. case '-':
  109. if (strcmp(xoptarg, "help") == 0)
  110. {
  111. Help();
  112. exit(0);
  113. }
  114. else
  115. {
  116. FatalError("Unknown option - run without args to see valid ones.\n");
  117. }
  118. break;
  119. case '!':
  120. IncludePart = xoptarg;
  121. break;
  122. case 'b':
  123. case 'B':
  124. BlackPointCompensation = TRUE;
  125. break;
  126. case 'c':
  127. case 'C':
  128. PrecalcMode = atoi(xoptarg);
  129. if (PrecalcMode < 0 || PrecalcMode > 3)
  130. FatalError("Unknown precalc mode '%d'", PrecalcMode);
  131. break;
  132. case 'd':
  133. case 'D': {
  134. cmsFloat64Number ObserverAdaptationState = atof(xoptarg);
  135. if (ObserverAdaptationState < 0 ||
  136. ObserverAdaptationState > 1.0)
  137. FatalError("Adaptation states should be between 0 and 1");
  138. cmsSetAdaptationState(ContextID, ObserverAdaptationState);
  139. }
  140. break;
  141. case 'e':
  142. case 'E':
  143. lIsFloat = FALSE;
  144. break;
  145. case 'g':
  146. case 'G':
  147. GamutCheck = TRUE;
  148. break;
  149. case 'i':
  150. case 'I':
  151. if (lIsDeviceLink)
  152. FatalError("icctrans: Device-link already specified");
  153. cInProf = xoptarg;
  154. break;
  155. case 'l':
  156. case 'L':
  157. cInProf = xoptarg;
  158. lIsDeviceLink = TRUE;
  159. break;
  160. // No extra intents for proofing
  161. case 'm':
  162. case 'M':
  163. ProofingIntent = atoi(xoptarg);
  164. if (ProofingIntent > 3)
  165. FatalError("Unknown Proofing Intent '%d'", ProofingIntent);
  166. break;
  167. // For compatibility
  168. case 'n':
  169. case 'N':
  170. Verbose = 0;
  171. break;
  172. // Output profile
  173. case 'o':
  174. case 'O':
  175. if (lIsDeviceLink)
  176. FatalError("icctrans: Device-link already specified");
  177. cOutProf = xoptarg;
  178. break;
  179. // Proofing profile
  180. case 'p':
  181. case 'P':
  182. cProofing = xoptarg;
  183. break;
  184. // Quantize (get rid of decimals)
  185. case 'q':
  186. case 'Q':
  187. lQuantize = TRUE;
  188. break;
  189. // Inhibit unbounded mode
  190. case 's':
  191. case 'S':
  192. lUnbounded = FALSE;
  193. break;
  194. // The intent
  195. case 't':
  196. case 'T':
  197. Intent = atoi(xoptarg);
  198. break;
  199. // Verbosity level
  200. case 'V':
  201. case 'v':
  202. Verbose = atoi(xoptarg);
  203. if (Verbose < 0 || Verbose > 3) {
  204. FatalError("Unknown verbosity level '%d'", Verbose);
  205. }
  206. break;
  207. // Wide (16 bits)
  208. case 'W':
  209. case 'w':
  210. Width16 = TRUE;
  211. break;
  212. // Hexadecimal
  213. case 'x':
  214. case 'X':
  215. InHexa = TRUE;
  216. break;
  217. default:
  218. FatalError("Unknown option - run without args to see valid ones.\n");
  219. }
  220. }
  221. // If output CGATS involved, switch to float
  222. if ((argc - xoptind) > 2) {
  223. lIsFloat = TRUE;
  224. }
  225. }
  226. static
  227. void SetRange(cmsFloat64Number range, cmsBool IsInput)
  228. {
  229. if (IsInput)
  230. InputRange = range;
  231. else
  232. OutputRange = range;
  233. }
  234. // Populate a named color list with usual component names.
  235. // I am using the first Colorant channel to store the range, but it works since
  236. // this space is not used anyway.
  237. static
  238. cmsNAMEDCOLORLIST* ComponentNames(cmsContext ContextID, cmsColorSpaceSignature space, cmsBool IsInput)
  239. {
  240. cmsNAMEDCOLORLIST* out;
  241. int i, n;
  242. char Buffer[cmsMAX_PATH];
  243. out = cmsAllocNamedColorList(0, 12, cmsMAXCHANNELS, "", "");
  244. if (out == NULL) return NULL;
  245. switch (space) {
  246. case cmsSigXYZData:
  247. SetRange(100, IsInput);
  248. cmsAppendNamedColor(ContextID, out, "X", NULL, NULL);
  249. cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL);
  250. cmsAppendNamedColor(ContextID, out, "Z", NULL, NULL);
  251. break;
  252. case cmsSigLabData:
  253. SetRange(1, IsInput);
  254. cmsAppendNamedColor(ContextID, out, "L*", NULL, NULL);
  255. cmsAppendNamedColor(ContextID, out, "a*", NULL, NULL);
  256. cmsAppendNamedColor(ContextID, out, "b*", NULL, NULL);
  257. break;
  258. case cmsSigLuvData:
  259. SetRange(1, IsInput);
  260. cmsAppendNamedColor(ContextID, out, "L", NULL, NULL);
  261. cmsAppendNamedColor(ContextID, out, "u", NULL, NULL);
  262. cmsAppendNamedColor(ContextID, out, "v", NULL, NULL);
  263. break;
  264. case cmsSigYCbCrData:
  265. SetRange(255, IsInput);
  266. cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL );
  267. cmsAppendNamedColor(ContextID, out, "Cb", NULL, NULL);
  268. cmsAppendNamedColor(ContextID, out, "Cr", NULL, NULL);
  269. break;
  270. case cmsSigYxyData:
  271. SetRange(1, IsInput);
  272. cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL);
  273. cmsAppendNamedColor(ContextID, out, "x", NULL, NULL);
  274. cmsAppendNamedColor(ContextID, out, "y", NULL, NULL);
  275. break;
  276. case cmsSigRgbData:
  277. SetRange(255, IsInput);
  278. cmsAppendNamedColor(ContextID, out, "R", NULL, NULL);
  279. cmsAppendNamedColor(ContextID, out, "G", NULL, NULL);
  280. cmsAppendNamedColor(ContextID, out, "B", NULL, NULL);
  281. break;
  282. case cmsSigGrayData:
  283. SetRange(255, IsInput);
  284. cmsAppendNamedColor(ContextID, out, "G", NULL, NULL);
  285. break;
  286. case cmsSigHsvData:
  287. SetRange(255, IsInput);
  288. cmsAppendNamedColor(ContextID, out, "H", NULL, NULL);
  289. cmsAppendNamedColor(ContextID, out, "s", NULL, NULL);
  290. cmsAppendNamedColor(ContextID, out, "v", NULL, NULL);
  291. break;
  292. case cmsSigHlsData:
  293. SetRange(255, IsInput);
  294. cmsAppendNamedColor(ContextID, out, "H", NULL, NULL);
  295. cmsAppendNamedColor(ContextID, out, "l", NULL, NULL);
  296. cmsAppendNamedColor(ContextID, out, "s", NULL, NULL);
  297. break;
  298. case cmsSigCmykData:
  299. SetRange(1, IsInput);
  300. cmsAppendNamedColor(ContextID, out, "C", NULL, NULL);
  301. cmsAppendNamedColor(ContextID, out, "M", NULL, NULL);
  302. cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL);
  303. cmsAppendNamedColor(ContextID, out, "K", NULL, NULL);
  304. break;
  305. case cmsSigCmyData:
  306. SetRange(1, IsInput);
  307. cmsAppendNamedColor(ContextID, out, "C", NULL, NULL);
  308. cmsAppendNamedColor(ContextID, out, "M", NULL, NULL);
  309. cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL);
  310. break;
  311. default:
  312. SetRange(1, IsInput);
  313. n = cmsChannelsOfColorSpace(ContextID, space);
  314. for (i=0; i < n; i++) {
  315. sprintf(Buffer, "Channel #%d", i + 1);
  316. cmsAppendNamedColor(ContextID, out, Buffer, NULL, NULL);
  317. }
  318. }
  319. return out;
  320. }
  321. // Creates all needed color transforms
  322. static
  323. cmsBool OpenTransforms(cmsContext ContextID)
  324. {
  325. cmsHPROFILE hInput, hOutput, hProof;
  326. cmsUInt32Number dwIn, dwOut, dwFlags;
  327. cmsNAMEDCOLORLIST* List;
  328. int i;
  329. // We don't need cache
  330. dwFlags = cmsFLAGS_NOCACHE;
  331. if (lIsDeviceLink) {
  332. hInput = OpenStockProfile(0, cInProf);
  333. if (hInput == NULL) return FALSE;
  334. hOutput = NULL;
  335. hProof = NULL;
  336. if (cmsGetDeviceClass(ContextID, hInput) == cmsSigNamedColorClass) {
  337. OutputColorSpace = cmsGetColorSpace(ContextID, hInput);
  338. InputColorSpace = cmsGetPCS(ContextID, hInput);
  339. }
  340. else {
  341. InputColorSpace = cmsGetColorSpace(ContextID, hInput);
  342. OutputColorSpace = cmsGetPCS(ContextID, hInput);
  343. }
  344. // Read colorant tables if present
  345. if (cmsIsTag(ContextID, hInput, cmsSigColorantTableTag)) {
  346. List = cmsReadTag(ContextID, hInput, cmsSigColorantTableTag);
  347. InputColorant = cmsDupNamedColorList(ContextID, List);
  348. InputRange = 1;
  349. }
  350. else InputColorant = ComponentNames(ContextID, InputColorSpace, TRUE);
  351. if (cmsIsTag(ContextID, hInput, cmsSigColorantTableOutTag)){
  352. List = cmsReadTag(ContextID, hInput, cmsSigColorantTableOutTag);
  353. OutputColorant = cmsDupNamedColorList(ContextID, List);
  354. OutputRange = 1;
  355. }
  356. else OutputColorant = ComponentNames(ContextID, OutputColorSpace, FALSE);
  357. }
  358. else {
  359. hInput = OpenStockProfile(0, cInProf);
  360. if (hInput == NULL) return FALSE;
  361. hOutput = OpenStockProfile(0, cOutProf);
  362. if (hOutput == NULL) return FALSE;
  363. hProof = NULL;
  364. if (cmsGetDeviceClass(ContextID, hInput) == cmsSigLinkClass ||
  365. cmsGetDeviceClass(ContextID, hOutput) == cmsSigLinkClass)
  366. FatalError("Use -l flag for devicelink profiles!\n");
  367. InputColorSpace = cmsGetColorSpace(ContextID, hInput);
  368. OutputColorSpace = cmsGetColorSpace(ContextID, hOutput);
  369. // Read colorant tables if present
  370. if (cmsIsTag(ContextID, hInput, cmsSigColorantTableTag)) {
  371. List = cmsReadTag(ContextID, hInput, cmsSigColorantTableTag);
  372. InputColorant = cmsDupNamedColorList(ContextID, List);
  373. if (cmsNamedColorCount(ContextID, InputColorant) <= 3)
  374. SetRange(255, TRUE);
  375. else
  376. SetRange(1, TRUE); // Inks are already divided by 100 in the formatter
  377. }
  378. else InputColorant = ComponentNames(ContextID, InputColorSpace, TRUE);
  379. if (cmsIsTag(ContextID, hOutput, cmsSigColorantTableTag)){
  380. List = cmsReadTag(ContextID, hOutput, cmsSigColorantTableTag);
  381. OutputColorant = cmsDupNamedColorList(ContextID, List);
  382. if (cmsNamedColorCount(ContextID, OutputColorant) <= 3)
  383. SetRange(255, FALSE);
  384. else
  385. SetRange(1, FALSE); // Inks are already divided by 100 in the formatter
  386. }
  387. else OutputColorant = ComponentNames(ContextID, OutputColorSpace, FALSE);
  388. if (cProofing != NULL) {
  389. hProof = OpenStockProfile(0, cProofing);
  390. if (hProof == NULL) return FALSE;
  391. dwFlags |= cmsFLAGS_SOFTPROOFING;
  392. }
  393. }
  394. // Print information on profiles
  395. if (Verbose > 2) {
  396. printf("Profile:\n");
  397. PrintProfileInformation(ContextID, hInput);
  398. if (hOutput) {
  399. printf("Output profile:\n");
  400. PrintProfileInformation(ContextID, hOutput);
  401. }
  402. if (hProof != NULL) {
  403. printf("Proofing profile:\n");
  404. PrintProfileInformation(ContextID, hProof);
  405. }
  406. }
  407. // Input is always in floating point
  408. dwIn = cmsFormatterForColorspaceOfProfile(ContextID, hInput, 0, TRUE);
  409. if (lIsDeviceLink) {
  410. dwOut = cmsFormatterForPCSOfProfile(ContextID, hInput, lIsFloat ? 0 : 2, lIsFloat);
  411. }
  412. else {
  413. // 16 bits or floating point (only on output)
  414. dwOut = cmsFormatterForColorspaceOfProfile(ContextID, hOutput, lIsFloat ? 0 : 2, lIsFloat);
  415. }
  416. // For named color, there is a specialized formatter
  417. if (cmsGetDeviceClass(ContextID, hInput) == cmsSigNamedColorClass) {
  418. dwIn = TYPE_NAMED_COLOR_INDEX;
  419. InputNamedColor = TRUE;
  420. }
  421. // Precision mode
  422. switch (PrecalcMode) {
  423. case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break;
  424. case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
  425. case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
  426. case 1: break;
  427. default:
  428. FatalError("Unknown precalculation mode '%d'", PrecalcMode);
  429. }
  430. if (BlackPointCompensation)
  431. dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
  432. if (GamutCheck) {
  433. cmsUInt16Number Alarm[cmsMAXCHANNELS];
  434. if (hProof == NULL)
  435. FatalError("I need proofing profile -p for gamut checking!");
  436. for (i=0; i < cmsMAXCHANNELS; i++)
  437. Alarm[i] = 0xFFFF;
  438. cmsSetAlarmCodes(ContextID, Alarm);
  439. dwFlags |= cmsFLAGS_GAMUTCHECK;
  440. }
  441. // The main transform
  442. hTrans = cmsCreateProofingTransform(ContextID, hInput, dwIn, hOutput, dwOut, hProof, Intent, ProofingIntent, dwFlags);
  443. if (hProof) cmsCloseProfile(ContextID, hProof);
  444. if (hTrans == NULL) return FALSE;
  445. // PCS Dump if requested
  446. hTransXYZ = NULL; hTransLab = NULL;
  447. if (hOutput && Verbose > 1) {
  448. cmsHPROFILE hXYZ = cmsCreateXYZProfile(ContextID);
  449. cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL);
  450. hTransXYZ = cmsCreateTransform(ContextID, hInput, dwIn, hXYZ, lIsFloat ? TYPE_XYZ_DBL : TYPE_XYZ_16, Intent, cmsFLAGS_NOCACHE);
  451. if (hTransXYZ == NULL) return FALSE;
  452. hTransLab = cmsCreateTransform(ContextID, hInput, dwIn, hLab, lIsFloat? TYPE_Lab_DBL : TYPE_Lab_16, Intent, cmsFLAGS_NOCACHE);
  453. if (hTransLab == NULL) return FALSE;
  454. cmsCloseProfile(ContextID, hXYZ);
  455. cmsCloseProfile(ContextID, hLab);
  456. }
  457. if (hInput) cmsCloseProfile(ContextID, hInput);
  458. if (hOutput) cmsCloseProfile(ContextID, hOutput);
  459. return TRUE;
  460. }
  461. // Free open resources
  462. static
  463. void CloseTransforms(cmsContext ContextID)
  464. {
  465. if (InputColorant) cmsFreeNamedColorList(ContextID, InputColorant);
  466. if (OutputColorant) cmsFreeNamedColorList(ContextID, OutputColorant);
  467. if (hTrans) cmsDeleteTransform(ContextID, hTrans);
  468. if (hTransLab) cmsDeleteTransform(ContextID, hTransLab);
  469. if (hTransXYZ) cmsDeleteTransform(ContextID, hTransXYZ);
  470. }
  471. // ---------------------------------------------------------------------------------------------------
  472. // Get input from user
  473. static
  474. void GetLine(cmsContext ContextID, char* Buffer, const char* frm, ...)
  475. {
  476. int res;
  477. va_list args;
  478. va_start(args, frm);
  479. do {
  480. if (xisatty(stdin))
  481. vfprintf(stderr, frm, args);
  482. res = scanf("%4095s", Buffer);
  483. if (res < 0 || toupper(Buffer[0]) == 'Q') { // Quit?
  484. CloseTransforms(ContextID);
  485. if (xisatty(stdin))
  486. fprintf(stderr, "Done.\n");
  487. exit(0);
  488. }
  489. } while (res == 0);
  490. va_end(args);
  491. }
  492. // Print a value which is given in double floating point
  493. static
  494. void PrintFloatResults(cmsContext ContextID, cmsFloat64Number Value[])
  495. {
  496. cmsUInt32Number i, n;
  497. char ChannelName[cmsMAX_PATH];
  498. cmsFloat64Number v;
  499. n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace);
  500. for (i=0; i < n; i++) {
  501. if (OutputColorant != NULL) {
  502. cmsNamedColorInfo(ContextID, OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
  503. }
  504. else {
  505. OutputRange = 1;
  506. sprintf(ChannelName, "Channel #%u", i + 1);
  507. }
  508. v = (cmsFloat64Number) Value[i]* OutputRange;
  509. if (lQuantize)
  510. v = floor(v + 0.5);
  511. if (!lUnbounded) {
  512. if (v < 0)
  513. v = 0;
  514. if (v > OutputRange)
  515. v = OutputRange;
  516. }
  517. if (Verbose <= 0)
  518. printf("%.4f ", v);
  519. else
  520. printf("%s=%.4f ", ChannelName, v);
  521. }
  522. printf("\n");
  523. }
  524. // Get a named-color index
  525. static
  526. cmsUInt16Number GetIndex(cmsContext ContextID)
  527. {
  528. char Buffer[4096], Name[cmsMAX_PATH], Prefix[40], Suffix[40];
  529. int index, max;
  530. const cmsNAMEDCOLORLIST* NamedColorList;
  531. NamedColorList = cmsGetNamedColorList(hTrans);
  532. if (NamedColorList == NULL) return 0;
  533. max = cmsNamedColorCount(ContextID, NamedColorList)-1;
  534. GetLine(ContextID, Buffer, "Color index (0..%d)? ", max);
  535. index = atoi(Buffer);
  536. if (index > max)
  537. FatalError("Named color %d out of range!", index);
  538. cmsNamedColorInfo(ContextID, NamedColorList, index, Name, Prefix, Suffix, NULL, NULL);
  539. printf("\n%s %s %s\n", Prefix, Name, Suffix);
  540. return (cmsUInt16Number) index;
  541. }
  542. // Read values from a text file or terminal
  543. static
  544. void TakeFloatValues(cmsContext ContextID, cmsFloat64Number Float[])
  545. {
  546. cmsUInt32Number i, n;
  547. char ChannelName[cmsMAX_PATH];
  548. char Buffer[4096];
  549. if (xisatty(stdin))
  550. fprintf(stderr, "\nEnter values, 'q' to quit\n");
  551. if (InputNamedColor) {
  552. // This is named color index, which is always cmsUInt16Number
  553. cmsUInt16Number index = GetIndex(ContextID);
  554. memcpy(Float, &index, sizeof(cmsUInt16Number));
  555. return;
  556. }
  557. n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
  558. for (i=0; i < n; i++) {
  559. if (InputColorant) {
  560. cmsNamedColorInfo(ContextID, InputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
  561. }
  562. else {
  563. InputRange = 1;
  564. sprintf(ChannelName, "Channel #%u", i+1);
  565. }
  566. GetLine(ContextID, Buffer, "%s? ", ChannelName);
  567. Float[i] = (cmsFloat64Number) atof(Buffer) / InputRange;
  568. }
  569. if (xisatty(stdin))
  570. fprintf(stderr, "\n");
  571. }
  572. static
  573. void PrintPCSFloat(cmsContext ContextID, cmsFloat64Number Input[])
  574. {
  575. if (Verbose > 1 && hTransXYZ && hTransLab) {
  576. cmsCIEXYZ XYZ = { 0, 0, 0 };
  577. cmsCIELab Lab = { 0, 0, 0 };
  578. if (hTransXYZ) cmsDoTransform(ContextID, hTransXYZ, Input, &XYZ, 1);
  579. if (hTransLab) cmsDoTransform(ContextID, hTransLab, Input, &Lab, 1);
  580. printf("[PCS] Lab=(%.4f,%.4f,%.4f) XYZ=(%.4f,%.4f,%.4f)\n", Lab.L, Lab.a, Lab.b,
  581. XYZ.X * 100.0, XYZ.Y * 100.0, XYZ.Z * 100.0);
  582. }
  583. }
  584. // -----------------------------------------------------------------------------------------------
  585. static
  586. void PrintEncodedResults(cmsContext ContextID, cmsUInt16Number Encoded[])
  587. {
  588. cmsUInt32Number i, n;
  589. char ChannelName[cmsMAX_PATH];
  590. cmsUInt32Number v;
  591. n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace);
  592. for (i=0; i < n; i++) {
  593. if (OutputColorant != NULL) {
  594. cmsNamedColorInfo(ContextID, OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL);
  595. }
  596. else {
  597. sprintf(ChannelName, "Channel #%u", i + 1);
  598. }
  599. if (Verbose > 0)
  600. printf("%s=", ChannelName);
  601. v = Encoded[i];
  602. if (InHexa) {
  603. if (Width16)
  604. printf("0x%04X ", (int) floor(v + .5));
  605. else
  606. printf("0x%02X ", (int) floor(v / 257. + .5));
  607. } else {
  608. if (Width16)
  609. printf("%d ", (int) floor(v + .5));
  610. else
  611. printf("%d ", (int) floor(v / 257. + .5));
  612. }
  613. }
  614. printf("\n");
  615. }
  616. // Print XYZ/Lab values on verbose mode
  617. static
  618. void PrintPCSEncoded(cmsContext ContextID, cmsFloat64Number Input[])
  619. {
  620. if (Verbose > 1 && hTransXYZ && hTransLab) {
  621. cmsUInt16Number XYZ[3], Lab[3];
  622. if (hTransXYZ) cmsDoTransform(ContextID, hTransXYZ, Input, XYZ, 1);
  623. if (hTransLab) cmsDoTransform(ContextID, hTransLab, Input, Lab, 1);
  624. printf("[PCS] Lab=(0x%04X,0x%04X,0x%04X) XYZ=(0x%04X,0x%04X,0x%04X)\n", Lab[0], Lab[1], Lab[2],
  625. XYZ[0], XYZ[1], XYZ[2]);
  626. }
  627. }
  628. // --------------------------------------------------------------------------------------
  629. // Take a value from IT8 and scale it accordly to fill a cmsUInt16Number (0..FFFF)
  630. static
  631. cmsFloat64Number GetIT8Val(cmsContext ContextID, const char* Name, cmsFloat64Number Max)
  632. {
  633. const char* Val = cmsIT8GetData(ContextID, hIT8in, CGATSPatch, Name);
  634. if (Val == NULL)
  635. FatalError("Field '%s' not found", Name);
  636. return atof(Val) / Max;
  637. }
  638. // Read input values from CGATS file.
  639. static
  640. void TakeCGATSValues(cmsContext ContextID, int nPatch, cmsFloat64Number Float[])
  641. {
  642. // At first take the name if SAMPLE_ID is present
  643. if (cmsIT8GetPatchName(ContextID, hIT8in, nPatch, CGATSPatch) == NULL) {
  644. FatalError("Sorry, I need 'SAMPLE_ID' on input CGATS to operate.");
  645. }
  646. // Special handling for named color profiles.
  647. // Lookup the name in the names database (the transform)
  648. if (InputNamedColor) {
  649. const cmsNAMEDCOLORLIST* NamedColorList;
  650. int index;
  651. NamedColorList = cmsGetNamedColorList(hTrans);
  652. if (NamedColorList == NULL)
  653. FatalError("Malformed named color profile");
  654. index = cmsNamedColorIndex(ContextID, NamedColorList, CGATSPatch);
  655. if (index < 0)
  656. FatalError("Named color '%s' not found in the profile", CGATSPatch);
  657. Float[0] = index;
  658. return;
  659. }
  660. // Color is not a spot color, proceed.
  661. switch (InputColorSpace) {
  662. // Encoding should follow CGATS specification.
  663. case cmsSigXYZData:
  664. Float[0] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "XYZ_X") / 100.0;
  665. Float[1] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "XYZ_Y") / 100.0;
  666. Float[2] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "XYZ_Z") / 100.0;
  667. break;
  668. case cmsSigLabData:
  669. Float[0] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "LAB_L");
  670. Float[1] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "LAB_A");
  671. Float[2] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "LAB_B");
  672. break;
  673. case cmsSigRgbData:
  674. Float[0] = GetIT8Val(ContextID, "RGB_R", 255.0);
  675. Float[1] = GetIT8Val(ContextID, "RGB_G", 255.0);
  676. Float[2] = GetIT8Val(ContextID, "RGB_B", 255.0);
  677. break;
  678. case cmsSigGrayData:
  679. Float[0] = GetIT8Val(ContextID, "GRAY", 255.0);
  680. break;
  681. case cmsSigCmykData:
  682. Float[0] = GetIT8Val(ContextID, "CMYK_C", 1.0);
  683. Float[1] = GetIT8Val(ContextID, "CMYK_M", 1.0);
  684. Float[2] = GetIT8Val(ContextID, "CMYK_Y", 1.0);
  685. Float[3] = GetIT8Val(ContextID, "CMYK_K", 1.0);
  686. break;
  687. case cmsSigCmyData:
  688. Float[0] = GetIT8Val(ContextID, "CMY_C", 1.0);
  689. Float[1] = GetIT8Val(ContextID, "CMY_M", 1.0);
  690. Float[2] = GetIT8Val(ContextID, "CMY_Y", 1.0);
  691. break;
  692. case cmsSig1colorData:
  693. case cmsSig2colorData:
  694. case cmsSig3colorData:
  695. case cmsSig4colorData:
  696. case cmsSig5colorData:
  697. case cmsSig6colorData:
  698. case cmsSig7colorData:
  699. case cmsSig8colorData:
  700. case cmsSig9colorData:
  701. case cmsSig10colorData:
  702. case cmsSig11colorData:
  703. case cmsSig12colorData:
  704. case cmsSig13colorData:
  705. case cmsSig14colorData:
  706. case cmsSig15colorData:
  707. {
  708. cmsUInt32Number i, n;
  709. n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
  710. for (i=0; i < n; i++) {
  711. char Buffer[255];
  712. sprintf(Buffer, "%uCLR_%u", n, i+1);
  713. Float[i] = GetIT8Val(ContextID, Buffer, 100.0);
  714. }
  715. }
  716. break;
  717. default:
  718. {
  719. cmsUInt32Number i, n;
  720. n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
  721. for (i=0; i < n; i++) {
  722. char Buffer[255];
  723. sprintf(Buffer, "CHAN_%u", i+1);
  724. Float[i] = GetIT8Val(ContextID, Buffer, 1.0);
  725. }
  726. }
  727. }
  728. }
  729. static
  730. void SetCGATSfld(cmsContext ContextID, const char* Col, cmsFloat64Number Val)
  731. {
  732. if (lQuantize)
  733. Val = floor(Val + 0.5);
  734. if (!cmsIT8SetDataDbl(ContextID, hIT8out, CGATSPatch, Col, Val)) {
  735. FatalError("couldn't set '%s' on output cgats '%s'", Col, CGATSoutFilename);
  736. }
  737. }
  738. static
  739. void PutCGATSValues(cmsContext ContextID, cmsFloat64Number Float[])
  740. {
  741. cmsIT8SetData(ContextID, hIT8out, CGATSPatch, "SAMPLE_ID", CGATSPatch);
  742. switch (OutputColorSpace) {
  743. // Encoding should follow CGATS specification.
  744. case cmsSigXYZData:
  745. SetCGATSfld(ContextID, "XYZ_X", Float[0] * 100.0);
  746. SetCGATSfld(ContextID, "XYZ_Y", Float[1] * 100.0);
  747. SetCGATSfld(ContextID, "XYZ_Z", Float[2] * 100.0);
  748. break;
  749. case cmsSigLabData:
  750. SetCGATSfld(ContextID, "LAB_L", Float[0]);
  751. SetCGATSfld(ContextID, "LAB_A", Float[1]);
  752. SetCGATSfld(ContextID, "LAB_B", Float[2]);
  753. break;
  754. case cmsSigRgbData:
  755. SetCGATSfld(ContextID, "RGB_R", Float[0] * 255.0);
  756. SetCGATSfld(ContextID, "RGB_G", Float[1] * 255.0);
  757. SetCGATSfld(ContextID, "RGB_B", Float[2] * 255.0);
  758. break;
  759. case cmsSigGrayData:
  760. SetCGATSfld(ContextID, "GRAY", Float[0] * 255.0);
  761. break;
  762. case cmsSigCmykData:
  763. SetCGATSfld(ContextID, "CMYK_C", Float[0]);
  764. SetCGATSfld(ContextID, "CMYK_M", Float[1]);
  765. SetCGATSfld(ContextID, "CMYK_Y", Float[2]);
  766. SetCGATSfld(ContextID, "CMYK_K", Float[3]);
  767. break;
  768. case cmsSigCmyData:
  769. SetCGATSfld(ContextID, "CMY_C", Float[0]);
  770. SetCGATSfld(ContextID, "CMY_M", Float[1]);
  771. SetCGATSfld(ContextID, "CMY_Y", Float[2]);
  772. break;
  773. case cmsSig1colorData:
  774. case cmsSig2colorData:
  775. case cmsSig3colorData:
  776. case cmsSig4colorData:
  777. case cmsSig5colorData:
  778. case cmsSig6colorData:
  779. case cmsSig7colorData:
  780. case cmsSig8colorData:
  781. case cmsSig9colorData:
  782. case cmsSig10colorData:
  783. case cmsSig11colorData:
  784. case cmsSig12colorData:
  785. case cmsSig13colorData:
  786. case cmsSig14colorData:
  787. case cmsSig15colorData:
  788. {
  789. cmsInt32Number i, n;
  790. n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
  791. for (i=0; i < n; i++) {
  792. char Buffer[255];
  793. sprintf(Buffer, "%uCLR_%u", n, i+1);
  794. SetCGATSfld(ContextID, Buffer, Float[i] * 100.0);
  795. }
  796. }
  797. break;
  798. default:
  799. {
  800. cmsInt32Number i, n;
  801. n = cmsChannelsOfColorSpace(ContextID, InputColorSpace);
  802. for (i=0; i < n; i++) {
  803. char Buffer[255];
  804. sprintf(Buffer, "CHAN_%u", i+1);
  805. SetCGATSfld(ContextID, Buffer, Float[i]);
  806. }
  807. }
  808. }
  809. }
  810. // Create data format
  811. static
  812. void SetOutputDataFormat(cmsContext ContextID)
  813. {
  814. cmsIT8DefineDblFormat(ContextID, hIT8out, "%.4g");
  815. cmsIT8SetPropertyStr(ContextID, hIT8out, "ORIGINATOR", "icctrans");
  816. if (IncludePart != NULL)
  817. cmsIT8SetPropertyStr(ContextID, hIT8out, ".INCLUDE", IncludePart);
  818. cmsIT8SetComment(ContextID, hIT8out, "Data follows");
  819. cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_SETS", nMaxPatches);
  820. switch (OutputColorSpace) {
  821. // Encoding should follow CGATS specification.
  822. case cmsSigXYZData:
  823. cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4);
  824. cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
  825. cmsIT8SetDataFormat(ContextID, hIT8out, 1, "XYZ_X");
  826. cmsIT8SetDataFormat(ContextID, hIT8out, 2, "XYZ_Y");
  827. cmsIT8SetDataFormat(ContextID, hIT8out, 3, "XYZ_Z");
  828. break;
  829. case cmsSigLabData:
  830. cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4);
  831. cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
  832. cmsIT8SetDataFormat(ContextID, hIT8out, 1, "LAB_L");
  833. cmsIT8SetDataFormat(ContextID, hIT8out, 2, "LAB_A");
  834. cmsIT8SetDataFormat(ContextID, hIT8out, 3, "LAB_B");
  835. break;
  836. case cmsSigRgbData:
  837. cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4);
  838. cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
  839. cmsIT8SetDataFormat(ContextID, hIT8out, 1, "RGB_R");
  840. cmsIT8SetDataFormat(ContextID, hIT8out, 2, "RGB_G");
  841. cmsIT8SetDataFormat(ContextID, hIT8out, 3, "RGB_B");
  842. break;
  843. case cmsSigGrayData:
  844. cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 2);
  845. cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
  846. cmsIT8SetDataFormat(ContextID, hIT8out, 1, "GRAY");
  847. break;
  848. case cmsSigCmykData:
  849. cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 5);
  850. cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
  851. cmsIT8SetDataFormat(ContextID, hIT8out, 1, "CMYK_C");
  852. cmsIT8SetDataFormat(ContextID, hIT8out, 2, "CMYK_M");
  853. cmsIT8SetDataFormat(ContextID, hIT8out, 3, "CMYK_Y");
  854. cmsIT8SetDataFormat(ContextID, hIT8out, 4, "CMYK_K");
  855. break;
  856. case cmsSigCmyData:
  857. cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4);
  858. cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
  859. cmsIT8SetDataFormat(ContextID, hIT8out, 1, "CMY_C");
  860. cmsIT8SetDataFormat(ContextID, hIT8out, 2, "CMY_M");
  861. cmsIT8SetDataFormat(ContextID, hIT8out, 3, "CMY_Y");
  862. break;
  863. case cmsSig1colorData:
  864. case cmsSig2colorData:
  865. case cmsSig3colorData:
  866. case cmsSig4colorData:
  867. case cmsSig5colorData:
  868. case cmsSig6colorData:
  869. case cmsSig7colorData:
  870. case cmsSig8colorData:
  871. case cmsSig9colorData:
  872. case cmsSig10colorData:
  873. case cmsSig11colorData:
  874. case cmsSig12colorData:
  875. case cmsSig13colorData:
  876. case cmsSig14colorData:
  877. case cmsSig15colorData:
  878. {
  879. int i, n;
  880. char Buffer[255];
  881. n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace);
  882. cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", n+1);
  883. cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
  884. for (i=1; i <= n; i++) {
  885. sprintf(Buffer, "%dCLR_%d", n, i);
  886. cmsIT8SetDataFormat(ContextID, hIT8out, i, Buffer);
  887. }
  888. }
  889. break;
  890. default: {
  891. int i, n;
  892. char Buffer[255];
  893. n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace);
  894. cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", n+1);
  895. cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID");
  896. for (i=1; i <= n; i++) {
  897. sprintf(Buffer, "CHAN_%d", i);
  898. cmsIT8SetDataFormat(ContextID, hIT8out, i, Buffer);
  899. }
  900. }
  901. }
  902. }
  903. // Open CGATS if specified
  904. static
  905. void OpenCGATSFiles(cmsContext ContextID, int argc, char *argv[])
  906. {
  907. int nParams = argc - xoptind;
  908. if (nParams >= 1) {
  909. hIT8in = cmsIT8LoadFromFile(0, argv[xoptind]);
  910. if (hIT8in == NULL)
  911. FatalError("'%s' is not recognized as a CGATS file", argv[xoptind]);
  912. nMaxPatches = (int) cmsIT8GetPropertyDbl(ContextID, hIT8in, "NUMBER_OF_SETS");
  913. }
  914. if (nParams == 2) {
  915. hIT8out = cmsIT8Alloc(NULL);
  916. SetOutputDataFormat(ContextID);
  917. strncpy(CGATSoutFilename, argv[xoptind+1], cmsMAX_PATH-1);
  918. }
  919. if (nParams > 2) FatalError("Too many CGATS files");
  920. }
  921. // The main sink
  922. int main(int argc, char *argv[])
  923. {
  924. cmsUInt16Number Output[cmsMAXCHANNELS];
  925. cmsFloat64Number OutputFloat[cmsMAXCHANNELS];
  926. cmsFloat64Number InputFloat[cmsMAXCHANNELS];
  927. cmsContext ContextID = NULL;
  928. int nPatch = 0;
  929. fprintf(stderr, "LittleCMS ColorSpace conversion calculator - 5.1 [LittleCMS %2.2f]\n", cmsGetEncodedCMMversion() / 1000.0);
  930. fprintf(stderr, "Copyright (c) 1998-2023 Marti Maria Saguer. See COPYING file for details.\n");
  931. fflush(stderr);
  932. InitUtils(ContextID, "transicc");
  933. Verbose = 1;
  934. if (argc == 1) {
  935. Help();
  936. return 0;
  937. }
  938. HandleSwitches(ContextID, argc, argv);
  939. // Open profiles, create transforms
  940. if (!OpenTransforms(ContextID)) return 1;
  941. // Open CGATS input if specified
  942. OpenCGATSFiles(ContextID, argc, argv);
  943. // Main loop: read all values and convert them
  944. for(;;) {
  945. if (hIT8in != NULL) {
  946. if (nPatch >= nMaxPatches) break;
  947. TakeCGATSValues(ContextID, nPatch++, InputFloat);
  948. } else {
  949. if (feof(stdin)) break;
  950. TakeFloatValues(ContextID, InputFloat);
  951. }
  952. if (lIsFloat)
  953. cmsDoTransform(ContextID, hTrans, InputFloat, OutputFloat, 1);
  954. else
  955. cmsDoTransform(ContextID, hTrans, InputFloat, Output, 1);
  956. if (hIT8out != NULL) {
  957. PutCGATSValues(ContextID, OutputFloat);
  958. }
  959. else {
  960. if (lIsFloat) {
  961. PrintFloatResults(ContextID, OutputFloat); PrintPCSFloat(ContextID, InputFloat);
  962. }
  963. else {
  964. PrintEncodedResults(ContextID, Output); PrintPCSEncoded(ContextID, InputFloat);
  965. }
  966. }
  967. }
  968. // Cleanup
  969. CloseTransforms(ContextID);
  970. if (hIT8in)
  971. cmsIT8Free(ContextID, hIT8in);
  972. if (hIT8out) {
  973. cmsIT8SaveToFile(ContextID, hIT8out, CGATSoutFilename);
  974. cmsIT8Free(ContextID, hIT8out);
  975. }
  976. // All is ok
  977. return 0;
  978. }