Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/lcms2/utils/transicc/transicc.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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 | |
| 27 #include "utils.h" | |
| 28 | |
| 29 #ifndef _MSC_VER | |
| 30 # include <unistd.h> | |
| 31 #endif | |
| 32 | |
| 33 #ifdef CMS_IS_WINDOWS_ | |
| 34 # include <io.h> | |
| 35 #endif | |
| 36 | |
| 37 #define MAX_INPUT_BUFFER 4096 | |
| 38 | |
| 39 // Global options | |
| 40 | |
| 41 static cmsBool InHexa = FALSE; | |
| 42 static cmsBool GamutCheck = FALSE; | |
| 43 static cmsBool Width16 = FALSE; | |
| 44 static cmsBool BlackPointCompensation = FALSE; | |
| 45 static cmsBool lIsDeviceLink = FALSE; | |
| 46 static cmsBool lQuantize = FALSE; | |
| 47 static cmsBool lUnbounded = TRUE; | |
| 48 static cmsBool lIsFloat = TRUE; | |
| 49 | |
| 50 static cmsUInt32Number Intent = INTENT_PERCEPTUAL; | |
| 51 static cmsUInt32Number ProofingIntent = INTENT_PERCEPTUAL; | |
| 52 | |
| 53 static int PrecalcMode = 0; | |
| 54 | |
| 55 // -------------------------------------------------------------- | |
| 56 | |
| 57 static char *cInProf = NULL; | |
| 58 static char *cOutProf = NULL; | |
| 59 static char *cProofing = NULL; | |
| 60 | |
| 61 static char *IncludePart = NULL; | |
| 62 | |
| 63 static cmsHANDLE hIT8in = NULL; // CGATS input | |
| 64 static cmsHANDLE hIT8out = NULL; // CGATS output | |
| 65 | |
| 66 static char CGATSPatch[1024]; // Actual Patch Name | |
| 67 static char CGATSoutFilename[cmsMAX_PATH]; | |
| 68 | |
| 69 static int nMaxPatches; | |
| 70 | |
| 71 static cmsHTRANSFORM hTrans, hTransXYZ, hTransLab; | |
| 72 static cmsBool InputNamedColor = FALSE; | |
| 73 | |
| 74 static cmsColorSpaceSignature InputColorSpace, OutputColorSpace; | |
| 75 | |
| 76 static cmsNAMEDCOLORLIST* InputColorant = NULL; | |
| 77 static cmsNAMEDCOLORLIST* OutputColorant = NULL; | |
| 78 | |
| 79 static cmsFloat64Number InputRange, OutputRange; | |
| 80 | |
| 81 | |
| 82 // isatty replacement | |
| 83 #ifdef _MSC_VER | |
| 84 #define xisatty(x) _isatty( _fileno( (x) ) ) | |
| 85 #else | |
| 86 #define xisatty(x) isatty( fileno( (x) ) ) | |
| 87 #endif | |
| 88 | |
| 89 //--------------------------------------------------------------------------------------------------- | |
| 90 | |
| 91 // Print usage to stderr | |
| 92 static | |
| 93 void Help(void) | |
| 94 { | |
| 95 | |
| 96 fprintf(stderr, "usage: transicc [flags] [CGATS input] [CGATS output]\n\n"); | |
| 97 | |
| 98 fprintf(stderr, "flags:\n\n"); | |
| 99 fprintf(stderr, "-v<0..3> - Verbosity level\n"); | |
| 100 | |
| 101 fprintf(stderr, "-e[op] - Encoded representation of numbers\n"); | |
| 102 fprintf(stderr, "\t-w - use 16 bits\n"); | |
| 103 fprintf(stderr, "\t-x - Hexadecimal\n\n"); | |
| 104 | |
| 105 fprintf(stderr, "-s - bounded mode (clip negatives and highlights)\n"); | |
| 106 fprintf(stderr, "-q - Quantize (round decimals)\n\n"); | |
| 107 | |
| 108 fprintf(stderr, "-i<profile> - Input profile (defaults to sRGB)\n"); | |
| 109 fprintf(stderr, "-o<profile> - Output profile (defaults to sRGB)\n"); | |
| 110 fprintf(stderr, "-l<profile> - Transform by device-link profile\n"); | |
| 111 | |
| 112 PrintBuiltins(); | |
| 113 | |
| 114 PrintRenderingIntents(NULL); | |
| 115 | |
| 116 fprintf(stderr, "\n"); | |
| 117 | |
| 118 fprintf(stderr, "-d<0..1> - Observer adaptation state (abs.col. only)\n\n"); | |
| 119 | |
| 120 fprintf(stderr, "-b - Black point compensation\n"); | |
| 121 | |
| 122 fprintf(stderr, "-c<0,1,2,3> Precalculates transform (0=Off, 1=Normal, 2=Hi-res, 3=LoRes)\n\n"); | |
| 123 fprintf(stderr, "-n - Terse output, intended for pipe usage\n"); | |
| 124 | |
| 125 fprintf(stderr, "-p<profile> - Soft proof profile\n"); | |
| 126 fprintf(stderr, "-m<0,1,2,3> - Soft proof intent\n"); | |
| 127 fprintf(stderr, "-g - Marks out-of-gamut colors on softproof\n\n"); | |
| 128 | |
| 129 | |
| 130 | |
| 131 fprintf(stderr, "This program is intended to be a demo of the Little CMS\n" | |
| 132 "color engine. Both lcms and this program are open source.\n" | |
| 133 "You can obtain both in source code at https://www.littlecms.com\n" | |
| 134 "For suggestions, comments, bug reports etc. send mail to\n" | |
| 135 "info@littlecms.com\n\n"); | |
| 136 | |
| 137 } | |
| 138 | |
| 139 | |
| 140 | |
| 141 // The toggles stuff | |
| 142 | |
| 143 static | |
| 144 void HandleSwitches(cmsContext ContextID, int argc, char *argv[]) | |
| 145 { | |
| 146 int s; | |
| 147 | |
| 148 while ((s = xgetopt(argc, argv, | |
| 149 "bBC:c:d:D:eEgGI:i:L:l:m:M:nNO:o:p:P:QqSsT:t:V:v:WwxX!:-:")) != EOF) { | |
| 150 | |
| 151 switch (s){ | |
| 152 | |
| 153 case '-': | |
| 154 if (strcmp(xoptarg, "help") == 0) | |
| 155 { | |
| 156 Help(); | |
| 157 exit(0); | |
| 158 } | |
| 159 else | |
| 160 { | |
| 161 FatalError("Unknown option - run without args to see valid ones.\n"); | |
| 162 } | |
| 163 break; | |
| 164 | |
| 165 case '!': | |
| 166 IncludePart = xoptarg; | |
| 167 break; | |
| 168 | |
| 169 case 'b': | |
| 170 case 'B': | |
| 171 BlackPointCompensation = TRUE; | |
| 172 break; | |
| 173 | |
| 174 case 'c': | |
| 175 case 'C': | |
| 176 PrecalcMode = atoi(xoptarg); | |
| 177 if (PrecalcMode < 0 || PrecalcMode > 3) | |
| 178 FatalError("Unknown precalc mode '%d'", PrecalcMode); | |
| 179 break; | |
| 180 | |
| 181 case 'd': | |
| 182 case 'D': { | |
| 183 cmsFloat64Number ObserverAdaptationState = atof(xoptarg); | |
| 184 if (ObserverAdaptationState < 0 || | |
| 185 ObserverAdaptationState > 1.0) | |
| 186 FatalError("Adaptation states should be between 0 and 1"); | |
| 187 | |
| 188 cmsSetAdaptationState(ContextID, ObserverAdaptationState); | |
| 189 } | |
| 190 break; | |
| 191 | |
| 192 case 'e': | |
| 193 case 'E': | |
| 194 lIsFloat = FALSE; | |
| 195 break; | |
| 196 | |
| 197 case 'g': | |
| 198 case 'G': | |
| 199 GamutCheck = TRUE; | |
| 200 break; | |
| 201 | |
| 202 case 'i': | |
| 203 case 'I': | |
| 204 if (lIsDeviceLink) | |
| 205 FatalError("icctrans: Device-link already specified"); | |
| 206 | |
| 207 cInProf = xoptarg; | |
| 208 break; | |
| 209 | |
| 210 case 'l': | |
| 211 case 'L': | |
| 212 cInProf = xoptarg; | |
| 213 lIsDeviceLink = TRUE; | |
| 214 break; | |
| 215 | |
| 216 // No extra intents for proofing | |
| 217 case 'm': | |
| 218 case 'M': | |
| 219 ProofingIntent = atoi(xoptarg); | |
| 220 if (ProofingIntent > 3) | |
| 221 FatalError("Unknown Proofing Intent '%d'", ProofingIntent); | |
| 222 break; | |
| 223 | |
| 224 // For compatibility | |
| 225 case 'n': | |
| 226 case 'N': | |
| 227 Verbose = 0; | |
| 228 break; | |
| 229 | |
| 230 // Output profile | |
| 231 case 'o': | |
| 232 case 'O': | |
| 233 if (lIsDeviceLink) | |
| 234 FatalError("icctrans: Device-link already specified"); | |
| 235 cOutProf = xoptarg; | |
| 236 break; | |
| 237 | |
| 238 // Proofing profile | |
| 239 case 'p': | |
| 240 case 'P': | |
| 241 cProofing = xoptarg; | |
| 242 break; | |
| 243 | |
| 244 // Quantize (get rid of decimals) | |
| 245 case 'q': | |
| 246 case 'Q': | |
| 247 lQuantize = TRUE; | |
| 248 break; | |
| 249 | |
| 250 // Inhibit unbounded mode | |
| 251 case 's': | |
| 252 case 'S': | |
| 253 lUnbounded = FALSE; | |
| 254 break; | |
| 255 | |
| 256 // The intent | |
| 257 case 't': | |
| 258 case 'T': | |
| 259 Intent = atoi(xoptarg); | |
| 260 break; | |
| 261 | |
| 262 // Verbosity level | |
| 263 case 'V': | |
| 264 case 'v': | |
| 265 Verbose = atoi(xoptarg); | |
| 266 if (Verbose < 0 || Verbose > 3) { | |
| 267 FatalError("Unknown verbosity level '%d'", Verbose); | |
| 268 } | |
| 269 break; | |
| 270 | |
| 271 // Wide (16 bits) | |
| 272 case 'W': | |
| 273 case 'w': | |
| 274 Width16 = TRUE; | |
| 275 break; | |
| 276 | |
| 277 // Hexadecimal | |
| 278 case 'x': | |
| 279 case 'X': | |
| 280 InHexa = TRUE; | |
| 281 break; | |
| 282 | |
| 283 default: | |
| 284 FatalError("Unknown option - run without args to see valid ones.\n"); | |
| 285 } | |
| 286 } | |
| 287 | |
| 288 | |
| 289 // If output CGATS involved, switch to float | |
| 290 if ((argc - xoptind) > 2) { | |
| 291 lIsFloat = TRUE; | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 | |
| 296 | |
| 297 static | |
| 298 void SetRange(cmsFloat64Number range, cmsBool IsInput) | |
| 299 { | |
| 300 if (IsInput) | |
| 301 InputRange = range; | |
| 302 else | |
| 303 OutputRange = range; | |
| 304 } | |
| 305 | |
| 306 // Populate a named color list with usual component names. | |
| 307 // I am using the first Colorant channel to store the range, but it works since | |
| 308 // this space is not used anyway. | |
| 309 static | |
| 310 cmsNAMEDCOLORLIST* ComponentNames(cmsContext ContextID, cmsColorSpaceSignature space, cmsBool IsInput) | |
| 311 { | |
| 312 cmsNAMEDCOLORLIST* out; | |
| 313 int i, n; | |
| 314 char Buffer[cmsMAX_PATH]; | |
| 315 | |
| 316 out = cmsAllocNamedColorList(0, 12, cmsMAXCHANNELS, "", ""); | |
| 317 if (out == NULL) return NULL; | |
| 318 | |
| 319 switch (space) { | |
| 320 | |
| 321 case cmsSigXYZData: | |
| 322 SetRange(100, IsInput); | |
| 323 cmsAppendNamedColor(ContextID, out, "X", NULL, NULL); | |
| 324 cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL); | |
| 325 cmsAppendNamedColor(ContextID, out, "Z", NULL, NULL); | |
| 326 break; | |
| 327 | |
| 328 case cmsSigLabData: | |
| 329 SetRange(1, IsInput); | |
| 330 cmsAppendNamedColor(ContextID, out, "L*", NULL, NULL); | |
| 331 cmsAppendNamedColor(ContextID, out, "a*", NULL, NULL); | |
| 332 cmsAppendNamedColor(ContextID, out, "b*", NULL, NULL); | |
| 333 break; | |
| 334 | |
| 335 case cmsSigLuvData: | |
| 336 SetRange(1, IsInput); | |
| 337 cmsAppendNamedColor(ContextID, out, "L", NULL, NULL); | |
| 338 cmsAppendNamedColor(ContextID, out, "u", NULL, NULL); | |
| 339 cmsAppendNamedColor(ContextID, out, "v", NULL, NULL); | |
| 340 break; | |
| 341 | |
| 342 case cmsSigYCbCrData: | |
| 343 SetRange(255, IsInput); | |
| 344 cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL ); | |
| 345 cmsAppendNamedColor(ContextID, out, "Cb", NULL, NULL); | |
| 346 cmsAppendNamedColor(ContextID, out, "Cr", NULL, NULL); | |
| 347 break; | |
| 348 | |
| 349 | |
| 350 case cmsSigYxyData: | |
| 351 SetRange(1, IsInput); | |
| 352 cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL); | |
| 353 cmsAppendNamedColor(ContextID, out, "x", NULL, NULL); | |
| 354 cmsAppendNamedColor(ContextID, out, "y", NULL, NULL); | |
| 355 break; | |
| 356 | |
| 357 case cmsSigRgbData: | |
| 358 SetRange(255, IsInput); | |
| 359 cmsAppendNamedColor(ContextID, out, "R", NULL, NULL); | |
| 360 cmsAppendNamedColor(ContextID, out, "G", NULL, NULL); | |
| 361 cmsAppendNamedColor(ContextID, out, "B", NULL, NULL); | |
| 362 break; | |
| 363 | |
| 364 case cmsSigGrayData: | |
| 365 SetRange(255, IsInput); | |
| 366 cmsAppendNamedColor(ContextID, out, "G", NULL, NULL); | |
| 367 break; | |
| 368 | |
| 369 case cmsSigHsvData: | |
| 370 SetRange(255, IsInput); | |
| 371 cmsAppendNamedColor(ContextID, out, "H", NULL, NULL); | |
| 372 cmsAppendNamedColor(ContextID, out, "s", NULL, NULL); | |
| 373 cmsAppendNamedColor(ContextID, out, "v", NULL, NULL); | |
| 374 break; | |
| 375 | |
| 376 case cmsSigHlsData: | |
| 377 SetRange(255, IsInput); | |
| 378 cmsAppendNamedColor(ContextID, out, "H", NULL, NULL); | |
| 379 cmsAppendNamedColor(ContextID, out, "l", NULL, NULL); | |
| 380 cmsAppendNamedColor(ContextID, out, "s", NULL, NULL); | |
| 381 break; | |
| 382 | |
| 383 case cmsSigCmykData: | |
| 384 SetRange(1, IsInput); | |
| 385 cmsAppendNamedColor(ContextID, out, "C", NULL, NULL); | |
| 386 cmsAppendNamedColor(ContextID, out, "M", NULL, NULL); | |
| 387 cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL); | |
| 388 cmsAppendNamedColor(ContextID, out, "K", NULL, NULL); | |
| 389 break; | |
| 390 | |
| 391 case cmsSigCmyData: | |
| 392 SetRange(1, IsInput); | |
| 393 cmsAppendNamedColor(ContextID, out, "C", NULL, NULL); | |
| 394 cmsAppendNamedColor(ContextID, out, "M", NULL, NULL); | |
| 395 cmsAppendNamedColor(ContextID, out, "Y", NULL, NULL); | |
| 396 break; | |
| 397 | |
| 398 default: | |
| 399 | |
| 400 SetRange(1, IsInput); | |
| 401 | |
| 402 n = cmsChannelsOfColorSpace(ContextID, space); | |
| 403 | |
| 404 for (i=0; i < n; i++) { | |
| 405 | |
| 406 sprintf(Buffer, "Channel #%d", i + 1); | |
| 407 cmsAppendNamedColor(ContextID, out, Buffer, NULL, NULL); | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 return out; | |
| 412 | |
| 413 } | |
| 414 | |
| 415 | |
| 416 // Creates all needed color transforms | |
| 417 static | |
| 418 cmsBool OpenTransforms(cmsContext ContextID) | |
| 419 { | |
| 420 cmsHPROFILE hInput, hOutput, hProof; | |
| 421 cmsUInt32Number dwIn, dwOut, dwFlags; | |
| 422 cmsNAMEDCOLORLIST* List; | |
| 423 int i; | |
| 424 | |
| 425 // We don't need cache | |
| 426 dwFlags = cmsFLAGS_NOCACHE; | |
| 427 | |
| 428 if (lIsDeviceLink) { | |
| 429 | |
| 430 hInput = OpenStockProfile(0, cInProf); | |
| 431 if (hInput == NULL) return FALSE; | |
| 432 hOutput = NULL; | |
| 433 hProof = NULL; | |
| 434 | |
| 435 if (cmsGetDeviceClass(ContextID, hInput) == cmsSigNamedColorClass) { | |
| 436 OutputColorSpace = cmsGetColorSpace(ContextID, hInput); | |
| 437 InputColorSpace = cmsGetPCS(ContextID, hInput); | |
| 438 } | |
| 439 else { | |
| 440 InputColorSpace = cmsGetColorSpace(ContextID, hInput); | |
| 441 OutputColorSpace = cmsGetPCS(ContextID, hInput); | |
| 442 } | |
| 443 | |
| 444 // Read colorant tables if present | |
| 445 if (cmsIsTag(ContextID, hInput, cmsSigColorantTableTag)) { | |
| 446 List = cmsReadTag(ContextID, hInput, cmsSigColorantTableTag); | |
| 447 InputColorant = cmsDupNamedColorList(ContextID, List); | |
| 448 InputRange = 1; | |
| 449 } | |
| 450 else InputColorant = ComponentNames(ContextID, InputColorSpace, TRUE); | |
| 451 | |
| 452 if (cmsIsTag(ContextID, hInput, cmsSigColorantTableOutTag)){ | |
| 453 | |
| 454 List = cmsReadTag(ContextID, hInput, cmsSigColorantTableOutTag); | |
| 455 OutputColorant = cmsDupNamedColorList(ContextID, List); | |
| 456 OutputRange = 1; | |
| 457 } | |
| 458 else OutputColorant = ComponentNames(ContextID, OutputColorSpace, FALSE); | |
| 459 | |
| 460 } | |
| 461 else { | |
| 462 | |
| 463 hInput = OpenStockProfile(0, cInProf); | |
| 464 if (hInput == NULL) return FALSE; | |
| 465 | |
| 466 hOutput = OpenStockProfile(0, cOutProf); | |
| 467 if (hOutput == NULL) return FALSE; | |
| 468 hProof = NULL; | |
| 469 | |
| 470 | |
| 471 if (cmsGetDeviceClass(ContextID, hInput) == cmsSigLinkClass || | |
| 472 cmsGetDeviceClass(ContextID, hOutput) == cmsSigLinkClass) | |
| 473 FatalError("Use -l flag for devicelink profiles!\n"); | |
| 474 | |
| 475 | |
| 476 InputColorSpace = cmsGetColorSpace(ContextID, hInput); | |
| 477 OutputColorSpace = cmsGetColorSpace(ContextID, hOutput); | |
| 478 | |
| 479 // Read colorant tables if present | |
| 480 if (cmsIsTag(ContextID, hInput, cmsSigColorantTableTag)) { | |
| 481 List = cmsReadTag(ContextID, hInput, cmsSigColorantTableTag); | |
| 482 InputColorant = cmsDupNamedColorList(ContextID, List); | |
| 483 if (cmsNamedColorCount(ContextID, InputColorant) <= 3) | |
| 484 SetRange(255, TRUE); | |
| 485 else | |
| 486 SetRange(1, TRUE); // Inks are already divided by 100 in the formatter | |
| 487 | |
| 488 } | |
| 489 else InputColorant = ComponentNames(ContextID, InputColorSpace, TRUE); | |
| 490 | |
| 491 if (cmsIsTag(ContextID, hOutput, cmsSigColorantTableTag)){ | |
| 492 | |
| 493 List = cmsReadTag(ContextID, hOutput, cmsSigColorantTableTag); | |
| 494 OutputColorant = cmsDupNamedColorList(ContextID, List); | |
| 495 if (cmsNamedColorCount(ContextID, OutputColorant) <= 3) | |
| 496 SetRange(255, FALSE); | |
| 497 else | |
| 498 SetRange(1, FALSE); // Inks are already divided by 100 in the formatter | |
| 499 } | |
| 500 else OutputColorant = ComponentNames(ContextID, OutputColorSpace, FALSE); | |
| 501 | |
| 502 | |
| 503 if (cProofing != NULL) { | |
| 504 | |
| 505 hProof = OpenStockProfile(0, cProofing); | |
| 506 if (hProof == NULL) return FALSE; | |
| 507 dwFlags |= cmsFLAGS_SOFTPROOFING; | |
| 508 } | |
| 509 } | |
| 510 | |
| 511 // Print information on profiles | |
| 512 if (Verbose > 2) { | |
| 513 | |
| 514 printf("Profile:\n"); | |
| 515 PrintProfileInformation(ContextID, hInput); | |
| 516 | |
| 517 if (hOutput) { | |
| 518 | |
| 519 printf("Output profile:\n"); | |
| 520 PrintProfileInformation(ContextID, hOutput); | |
| 521 } | |
| 522 | |
| 523 if (hProof != NULL) { | |
| 524 printf("Proofing profile:\n"); | |
| 525 PrintProfileInformation(ContextID, hProof); | |
| 526 } | |
| 527 } | |
| 528 | |
| 529 | |
| 530 // Input is always in floating point | |
| 531 dwIn = cmsFormatterForColorspaceOfProfile(ContextID, hInput, 0, TRUE); | |
| 532 | |
| 533 if (lIsDeviceLink) { | |
| 534 | |
| 535 dwOut = cmsFormatterForPCSOfProfile(ContextID, hInput, lIsFloat ? 0 : 2, lIsFloat); | |
| 536 } | |
| 537 else { | |
| 538 | |
| 539 // 16 bits or floating point (only on output) | |
| 540 dwOut = cmsFormatterForColorspaceOfProfile(ContextID, hOutput, lIsFloat ? 0 : 2, lIsFloat); | |
| 541 } | |
| 542 | |
| 543 // For named color, there is a specialized formatter | |
| 544 if (cmsGetDeviceClass(ContextID, hInput) == cmsSigNamedColorClass) { | |
| 545 | |
| 546 dwIn = TYPE_NAMED_COLOR_INDEX; | |
| 547 InputNamedColor = TRUE; | |
| 548 } | |
| 549 | |
| 550 // Precision mode | |
| 551 switch (PrecalcMode) { | |
| 552 | |
| 553 case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break; | |
| 554 case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break; | |
| 555 case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break; | |
| 556 case 1: break; | |
| 557 | |
| 558 default: | |
| 559 FatalError("Unknown precalculation mode '%d'", PrecalcMode); | |
| 560 } | |
| 561 | |
| 562 | |
| 563 if (BlackPointCompensation) | |
| 564 dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION; | |
| 565 | |
| 566 | |
| 567 if (GamutCheck) { | |
| 568 | |
| 569 cmsUInt16Number Alarm[cmsMAXCHANNELS]; | |
| 570 | |
| 571 if (hProof == NULL) | |
| 572 FatalError("I need proofing profile -p for gamut checking!"); | |
| 573 | |
| 574 for (i=0; i < cmsMAXCHANNELS; i++) | |
| 575 Alarm[i] = 0xFFFF; | |
| 576 | |
| 577 cmsSetAlarmCodes(ContextID, Alarm); | |
| 578 dwFlags |= cmsFLAGS_GAMUTCHECK; | |
| 579 } | |
| 580 | |
| 581 | |
| 582 // The main transform | |
| 583 hTrans = cmsCreateProofingTransform(ContextID, hInput, dwIn, hOutput, dwOut, hProof, Intent, ProofingIntent, dwFlags); | |
| 584 | |
| 585 if (hProof) cmsCloseProfile(ContextID, hProof); | |
| 586 | |
| 587 if (hTrans == NULL) return FALSE; | |
| 588 | |
| 589 | |
| 590 // PCS Dump if requested | |
| 591 hTransXYZ = NULL; hTransLab = NULL; | |
| 592 | |
| 593 if (hOutput && Verbose > 1) { | |
| 594 | |
| 595 cmsHPROFILE hXYZ = cmsCreateXYZProfile(ContextID); | |
| 596 cmsHPROFILE hLab = cmsCreateLab4Profile(ContextID, NULL); | |
| 597 | |
| 598 hTransXYZ = cmsCreateTransform(ContextID, hInput, dwIn, hXYZ, lIsFloat ? TYPE_XYZ_DBL : TYPE_XYZ_16, Intent, cmsFLAGS_NOCACHE); | |
| 599 if (hTransXYZ == NULL) return FALSE; | |
| 600 | |
| 601 hTransLab = cmsCreateTransform(ContextID, hInput, dwIn, hLab, lIsFloat? TYPE_Lab_DBL : TYPE_Lab_16, Intent, cmsFLAGS_NOCACHE); | |
| 602 if (hTransLab == NULL) return FALSE; | |
| 603 | |
| 604 cmsCloseProfile(ContextID, hXYZ); | |
| 605 cmsCloseProfile(ContextID, hLab); | |
| 606 } | |
| 607 | |
| 608 if (hInput) cmsCloseProfile(ContextID, hInput); | |
| 609 if (hOutput) cmsCloseProfile(ContextID, hOutput); | |
| 610 | |
| 611 return TRUE; | |
| 612 } | |
| 613 | |
| 614 | |
| 615 // Free open resources | |
| 616 static | |
| 617 void CloseTransforms(cmsContext ContextID) | |
| 618 { | |
| 619 if (InputColorant) cmsFreeNamedColorList(ContextID, InputColorant); | |
| 620 if (OutputColorant) cmsFreeNamedColorList(ContextID, OutputColorant); | |
| 621 | |
| 622 if (hTrans) cmsDeleteTransform(ContextID, hTrans); | |
| 623 if (hTransLab) cmsDeleteTransform(ContextID, hTransLab); | |
| 624 if (hTransXYZ) cmsDeleteTransform(ContextID, hTransXYZ); | |
| 625 | |
| 626 } | |
| 627 | |
| 628 // --------------------------------------------------------------------------------------------------- | |
| 629 | |
| 630 // Get input from user | |
| 631 static | |
| 632 void GetLine(cmsContext ContextID, char* Buffer, const char* frm, ...) | |
| 633 { | |
| 634 int res; | |
| 635 va_list args; | |
| 636 | |
| 637 va_start(args, frm); | |
| 638 | |
| 639 do { | |
| 640 if (xisatty(stdin)) | |
| 641 vfprintf(stderr, frm, args); | |
| 642 | |
| 643 res = scanf("%4095s", Buffer); | |
| 644 | |
| 645 if (res < 0 || toupper(Buffer[0]) == 'Q') { // Quit? | |
| 646 | |
| 647 CloseTransforms(ContextID); | |
| 648 | |
| 649 if (xisatty(stdin)) | |
| 650 fprintf(stderr, "Done.\n"); | |
| 651 | |
| 652 exit(0); | |
| 653 } | |
| 654 } while (res == 0); | |
| 655 | |
| 656 va_end(args); | |
| 657 } | |
| 658 | |
| 659 | |
| 660 // Print a value which is given in double floating point | |
| 661 static | |
| 662 void PrintFloatResults(cmsContext ContextID, cmsFloat64Number Value[]) | |
| 663 { | |
| 664 cmsUInt32Number i, n; | |
| 665 char ChannelName[cmsMAX_PATH]; | |
| 666 cmsFloat64Number v; | |
| 667 | |
| 668 n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace); | |
| 669 for (i=0; i < n; i++) { | |
| 670 | |
| 671 if (OutputColorant != NULL) { | |
| 672 | |
| 673 cmsNamedColorInfo(ContextID, OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL); | |
| 674 } | |
| 675 else { | |
| 676 OutputRange = 1; | |
| 677 sprintf(ChannelName, "Channel #%u", i + 1); | |
| 678 } | |
| 679 | |
| 680 v = (cmsFloat64Number) Value[i]* OutputRange; | |
| 681 | |
| 682 if (lQuantize) | |
| 683 v = floor(v + 0.5); | |
| 684 | |
| 685 if (!lUnbounded) { | |
| 686 | |
| 687 if (v < 0) | |
| 688 v = 0; | |
| 689 if (v > OutputRange) | |
| 690 v = OutputRange; | |
| 691 } | |
| 692 | |
| 693 if (Verbose <= 0) | |
| 694 printf("%.4f ", v); | |
| 695 else | |
| 696 printf("%s=%.4f ", ChannelName, v); | |
| 697 } | |
| 698 | |
| 699 printf("\n"); | |
| 700 } | |
| 701 | |
| 702 | |
| 703 // Get a named-color index | |
| 704 static | |
| 705 cmsUInt16Number GetIndex(cmsContext ContextID) | |
| 706 { | |
| 707 char Buffer[4096], Name[cmsMAX_PATH], Prefix[40], Suffix[40]; | |
| 708 int index, max; | |
| 709 const cmsNAMEDCOLORLIST* NamedColorList; | |
| 710 | |
| 711 NamedColorList = cmsGetNamedColorList(hTrans); | |
| 712 if (NamedColorList == NULL) return 0; | |
| 713 | |
| 714 max = cmsNamedColorCount(ContextID, NamedColorList)-1; | |
| 715 | |
| 716 GetLine(ContextID, Buffer, "Color index (0..%d)? ", max); | |
| 717 index = atoi(Buffer); | |
| 718 | |
| 719 if (index > max) | |
| 720 FatalError("Named color %d out of range!", index); | |
| 721 | |
| 722 cmsNamedColorInfo(ContextID, NamedColorList, index, Name, Prefix, Suffix, NULL, NULL); | |
| 723 | |
| 724 printf("\n%s %s %s\n", Prefix, Name, Suffix); | |
| 725 | |
| 726 return (cmsUInt16Number) index; | |
| 727 } | |
| 728 | |
| 729 // Read values from a text file or terminal | |
| 730 static | |
| 731 void TakeFloatValues(cmsContext ContextID, cmsFloat64Number Float[]) | |
| 732 { | |
| 733 cmsUInt32Number i, n; | |
| 734 char ChannelName[cmsMAX_PATH]; | |
| 735 char Buffer[4096]; | |
| 736 | |
| 737 if (xisatty(stdin)) | |
| 738 fprintf(stderr, "\nEnter values, 'q' to quit\n"); | |
| 739 | |
| 740 if (InputNamedColor) { | |
| 741 | |
| 742 // This is named color index, which is always cmsUInt16Number | |
| 743 cmsUInt16Number index = GetIndex(ContextID); | |
| 744 memcpy(Float, &index, sizeof(cmsUInt16Number)); | |
| 745 return; | |
| 746 } | |
| 747 | |
| 748 n = cmsChannelsOfColorSpace(ContextID, InputColorSpace); | |
| 749 for (i=0; i < n; i++) { | |
| 750 | |
| 751 if (InputColorant) { | |
| 752 cmsNamedColorInfo(ContextID, InputColorant, i, ChannelName, NULL, NULL, NULL, NULL); | |
| 753 } | |
| 754 else { | |
| 755 InputRange = 1; | |
| 756 sprintf(ChannelName, "Channel #%u", i+1); | |
| 757 } | |
| 758 | |
| 759 GetLine(ContextID, Buffer, "%s? ", ChannelName); | |
| 760 | |
| 761 Float[i] = (cmsFloat64Number) atof(Buffer) / InputRange; | |
| 762 } | |
| 763 | |
| 764 if (xisatty(stdin)) | |
| 765 fprintf(stderr, "\n"); | |
| 766 } | |
| 767 | |
| 768 static | |
| 769 void PrintPCSFloat(cmsContext ContextID, cmsFloat64Number Input[]) | |
| 770 { | |
| 771 if (Verbose > 1 && hTransXYZ && hTransLab) { | |
| 772 | |
| 773 cmsCIEXYZ XYZ = { 0, 0, 0 }; | |
| 774 cmsCIELab Lab = { 0, 0, 0 }; | |
| 775 | |
| 776 if (hTransXYZ) cmsDoTransform(ContextID, hTransXYZ, Input, &XYZ, 1); | |
| 777 if (hTransLab) cmsDoTransform(ContextID, hTransLab, Input, &Lab, 1); | |
| 778 | |
| 779 printf("[PCS] Lab=(%.4f,%.4f,%.4f) XYZ=(%.4f,%.4f,%.4f)\n", Lab.L, Lab.a, Lab.b, | |
| 780 XYZ.X * 100.0, XYZ.Y * 100.0, XYZ.Z * 100.0); | |
| 781 | |
| 782 } | |
| 783 } | |
| 784 | |
| 785 | |
| 786 | |
| 787 | |
| 788 // ----------------------------------------------------------------------------------------------- | |
| 789 | |
| 790 static | |
| 791 void PrintEncodedResults(cmsContext ContextID, cmsUInt16Number Encoded[]) | |
| 792 { | |
| 793 cmsUInt32Number i, n; | |
| 794 char ChannelName[cmsMAX_PATH]; | |
| 795 cmsUInt32Number v; | |
| 796 | |
| 797 n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace); | |
| 798 for (i=0; i < n; i++) { | |
| 799 | |
| 800 if (OutputColorant != NULL) { | |
| 801 | |
| 802 cmsNamedColorInfo(ContextID, OutputColorant, i, ChannelName, NULL, NULL, NULL, NULL); | |
| 803 } | |
| 804 else { | |
| 805 sprintf(ChannelName, "Channel #%u", i + 1); | |
| 806 } | |
| 807 | |
| 808 if (Verbose > 0) | |
| 809 printf("%s=", ChannelName); | |
| 810 | |
| 811 v = Encoded[i]; | |
| 812 | |
| 813 if (InHexa) { | |
| 814 | |
| 815 if (Width16) | |
| 816 printf("0x%04X ", (int) floor(v + .5)); | |
| 817 else | |
| 818 printf("0x%02X ", (int) floor(v / 257. + .5)); | |
| 819 | |
| 820 } else { | |
| 821 | |
| 822 if (Width16) | |
| 823 printf("%d ", (int) floor(v + .5)); | |
| 824 else | |
| 825 printf("%d ", (int) floor(v / 257. + .5)); | |
| 826 } | |
| 827 | |
| 828 } | |
| 829 | |
| 830 printf("\n"); | |
| 831 } | |
| 832 | |
| 833 // Print XYZ/Lab values on verbose mode | |
| 834 | |
| 835 static | |
| 836 void PrintPCSEncoded(cmsContext ContextID, cmsFloat64Number Input[]) | |
| 837 { | |
| 838 if (Verbose > 1 && hTransXYZ && hTransLab) { | |
| 839 | |
| 840 cmsUInt16Number XYZ[3], Lab[3]; | |
| 841 | |
| 842 if (hTransXYZ) cmsDoTransform(ContextID, hTransXYZ, Input, XYZ, 1); | |
| 843 if (hTransLab) cmsDoTransform(ContextID, hTransLab, Input, Lab, 1); | |
| 844 | |
| 845 printf("[PCS] Lab=(0x%04X,0x%04X,0x%04X) XYZ=(0x%04X,0x%04X,0x%04X)\n", Lab[0], Lab[1], Lab[2], | |
| 846 XYZ[0], XYZ[1], XYZ[2]); | |
| 847 | |
| 848 } | |
| 849 } | |
| 850 | |
| 851 | |
| 852 // -------------------------------------------------------------------------------------- | |
| 853 | |
| 854 | |
| 855 | |
| 856 // Take a value from IT8 and scale it accordly to fill a cmsUInt16Number (0..FFFF) | |
| 857 | |
| 858 static | |
| 859 cmsFloat64Number GetIT8Val(cmsContext ContextID, const char* Name, cmsFloat64Number Max) | |
| 860 { | |
| 861 const char* Val = cmsIT8GetData(ContextID, hIT8in, CGATSPatch, Name); | |
| 862 | |
| 863 if (Val == NULL) | |
| 864 FatalError("Field '%s' not found", Name); | |
| 865 | |
| 866 return atof(Val) / Max; | |
| 867 | |
| 868 } | |
| 869 | |
| 870 | |
| 871 // Read input values from CGATS file. | |
| 872 | |
| 873 static | |
| 874 void TakeCGATSValues(cmsContext ContextID, int nPatch, cmsFloat64Number Float[]) | |
| 875 { | |
| 876 | |
| 877 // At first take the name if SAMPLE_ID is present | |
| 878 if (cmsIT8GetPatchName(ContextID, hIT8in, nPatch, CGATSPatch) == NULL) { | |
| 879 FatalError("Sorry, I need 'SAMPLE_ID' on input CGATS to operate."); | |
| 880 } | |
| 881 | |
| 882 | |
| 883 // Special handling for named color profiles. | |
| 884 // Lookup the name in the names database (the transform) | |
| 885 | |
| 886 if (InputNamedColor) { | |
| 887 | |
| 888 const cmsNAMEDCOLORLIST* NamedColorList; | |
| 889 int index; | |
| 890 | |
| 891 NamedColorList = cmsGetNamedColorList(hTrans); | |
| 892 if (NamedColorList == NULL) | |
| 893 FatalError("Malformed named color profile"); | |
| 894 | |
| 895 index = cmsNamedColorIndex(ContextID, NamedColorList, CGATSPatch); | |
| 896 if (index < 0) | |
| 897 FatalError("Named color '%s' not found in the profile", CGATSPatch); | |
| 898 | |
| 899 Float[0] = index; | |
| 900 return; | |
| 901 } | |
| 902 | |
| 903 // Color is not a spot color, proceed. | |
| 904 | |
| 905 switch (InputColorSpace) { | |
| 906 | |
| 907 // Encoding should follow CGATS specification. | |
| 908 | |
| 909 case cmsSigXYZData: | |
| 910 Float[0] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "XYZ_X") / 100.0; | |
| 911 Float[1] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "XYZ_Y") / 100.0; | |
| 912 Float[2] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "XYZ_Z") / 100.0; | |
| 913 break; | |
| 914 | |
| 915 case cmsSigLabData: | |
| 916 Float[0] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "LAB_L"); | |
| 917 Float[1] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "LAB_A"); | |
| 918 Float[2] = cmsIT8GetDataDbl(ContextID, hIT8in, CGATSPatch, "LAB_B"); | |
| 919 break; | |
| 920 | |
| 921 | |
| 922 case cmsSigRgbData: | |
| 923 Float[0] = GetIT8Val(ContextID, "RGB_R", 255.0); | |
| 924 Float[1] = GetIT8Val(ContextID, "RGB_G", 255.0); | |
| 925 Float[2] = GetIT8Val(ContextID, "RGB_B", 255.0); | |
| 926 break; | |
| 927 | |
| 928 case cmsSigGrayData: | |
| 929 Float[0] = GetIT8Val(ContextID, "GRAY", 255.0); | |
| 930 break; | |
| 931 | |
| 932 case cmsSigCmykData: | |
| 933 Float[0] = GetIT8Val(ContextID, "CMYK_C", 1.0); | |
| 934 Float[1] = GetIT8Val(ContextID, "CMYK_M", 1.0); | |
| 935 Float[2] = GetIT8Val(ContextID, "CMYK_Y", 1.0); | |
| 936 Float[3] = GetIT8Val(ContextID, "CMYK_K", 1.0); | |
| 937 break; | |
| 938 | |
| 939 case cmsSigCmyData: | |
| 940 Float[0] = GetIT8Val(ContextID, "CMY_C", 1.0); | |
| 941 Float[1] = GetIT8Val(ContextID, "CMY_M", 1.0); | |
| 942 Float[2] = GetIT8Val(ContextID, "CMY_Y", 1.0); | |
| 943 break; | |
| 944 | |
| 945 case cmsSig1colorData: | |
| 946 case cmsSig2colorData: | |
| 947 case cmsSig3colorData: | |
| 948 case cmsSig4colorData: | |
| 949 case cmsSig5colorData: | |
| 950 case cmsSig6colorData: | |
| 951 case cmsSig7colorData: | |
| 952 case cmsSig8colorData: | |
| 953 case cmsSig9colorData: | |
| 954 case cmsSig10colorData: | |
| 955 case cmsSig11colorData: | |
| 956 case cmsSig12colorData: | |
| 957 case cmsSig13colorData: | |
| 958 case cmsSig14colorData: | |
| 959 case cmsSig15colorData: | |
| 960 { | |
| 961 cmsUInt32Number i, n; | |
| 962 | |
| 963 n = cmsChannelsOfColorSpace(ContextID, InputColorSpace); | |
| 964 for (i=0; i < n; i++) { | |
| 965 | |
| 966 char Buffer[255]; | |
| 967 | |
| 968 sprintf(Buffer, "%uCLR_%u", n, i+1); | |
| 969 Float[i] = GetIT8Val(ContextID, Buffer, 100.0); | |
| 970 } | |
| 971 | |
| 972 } | |
| 973 break; | |
| 974 | |
| 975 default: | |
| 976 { | |
| 977 cmsUInt32Number i, n; | |
| 978 | |
| 979 n = cmsChannelsOfColorSpace(ContextID, InputColorSpace); | |
| 980 for (i=0; i < n; i++) { | |
| 981 | |
| 982 char Buffer[255]; | |
| 983 | |
| 984 sprintf(Buffer, "CHAN_%u", i+1); | |
| 985 Float[i] = GetIT8Val(ContextID, Buffer, 1.0); | |
| 986 } | |
| 987 | |
| 988 } | |
| 989 } | |
| 990 | |
| 991 } | |
| 992 | |
| 993 static | |
| 994 void SetCGATSfld(cmsContext ContextID, const char* Col, cmsFloat64Number Val) | |
| 995 { | |
| 996 if (lQuantize) | |
| 997 Val = floor(Val + 0.5); | |
| 998 | |
| 999 if (!cmsIT8SetDataDbl(ContextID, hIT8out, CGATSPatch, Col, Val)) { | |
| 1000 FatalError("couldn't set '%s' on output cgats '%s'", Col, CGATSoutFilename); | |
| 1001 } | |
| 1002 } | |
| 1003 | |
| 1004 | |
| 1005 | |
| 1006 static | |
| 1007 void PutCGATSValues(cmsContext ContextID, cmsFloat64Number Float[]) | |
| 1008 { | |
| 1009 cmsIT8SetData(ContextID, hIT8out, CGATSPatch, "SAMPLE_ID", CGATSPatch); | |
| 1010 switch (OutputColorSpace) { | |
| 1011 | |
| 1012 | |
| 1013 // Encoding should follow CGATS specification. | |
| 1014 | |
| 1015 case cmsSigXYZData: | |
| 1016 | |
| 1017 SetCGATSfld(ContextID, "XYZ_X", Float[0] * 100.0); | |
| 1018 SetCGATSfld(ContextID, "XYZ_Y", Float[1] * 100.0); | |
| 1019 SetCGATSfld(ContextID, "XYZ_Z", Float[2] * 100.0); | |
| 1020 break; | |
| 1021 | |
| 1022 case cmsSigLabData: | |
| 1023 | |
| 1024 SetCGATSfld(ContextID, "LAB_L", Float[0]); | |
| 1025 SetCGATSfld(ContextID, "LAB_A", Float[1]); | |
| 1026 SetCGATSfld(ContextID, "LAB_B", Float[2]); | |
| 1027 break; | |
| 1028 | |
| 1029 | |
| 1030 case cmsSigRgbData: | |
| 1031 SetCGATSfld(ContextID, "RGB_R", Float[0] * 255.0); | |
| 1032 SetCGATSfld(ContextID, "RGB_G", Float[1] * 255.0); | |
| 1033 SetCGATSfld(ContextID, "RGB_B", Float[2] * 255.0); | |
| 1034 break; | |
| 1035 | |
| 1036 case cmsSigGrayData: | |
| 1037 SetCGATSfld(ContextID, "GRAY", Float[0] * 255.0); | |
| 1038 break; | |
| 1039 | |
| 1040 case cmsSigCmykData: | |
| 1041 SetCGATSfld(ContextID, "CMYK_C", Float[0]); | |
| 1042 SetCGATSfld(ContextID, "CMYK_M", Float[1]); | |
| 1043 SetCGATSfld(ContextID, "CMYK_Y", Float[2]); | |
| 1044 SetCGATSfld(ContextID, "CMYK_K", Float[3]); | |
| 1045 break; | |
| 1046 | |
| 1047 case cmsSigCmyData: | |
| 1048 SetCGATSfld(ContextID, "CMY_C", Float[0]); | |
| 1049 SetCGATSfld(ContextID, "CMY_M", Float[1]); | |
| 1050 SetCGATSfld(ContextID, "CMY_Y", Float[2]); | |
| 1051 break; | |
| 1052 | |
| 1053 case cmsSig1colorData: | |
| 1054 case cmsSig2colorData: | |
| 1055 case cmsSig3colorData: | |
| 1056 case cmsSig4colorData: | |
| 1057 case cmsSig5colorData: | |
| 1058 case cmsSig6colorData: | |
| 1059 case cmsSig7colorData: | |
| 1060 case cmsSig8colorData: | |
| 1061 case cmsSig9colorData: | |
| 1062 case cmsSig10colorData: | |
| 1063 case cmsSig11colorData: | |
| 1064 case cmsSig12colorData: | |
| 1065 case cmsSig13colorData: | |
| 1066 case cmsSig14colorData: | |
| 1067 case cmsSig15colorData: | |
| 1068 { | |
| 1069 | |
| 1070 cmsInt32Number i, n; | |
| 1071 | |
| 1072 n = cmsChannelsOfColorSpace(ContextID, InputColorSpace); | |
| 1073 for (i=0; i < n; i++) { | |
| 1074 | |
| 1075 char Buffer[255]; | |
| 1076 | |
| 1077 sprintf(Buffer, "%uCLR_%u", n, i+1); | |
| 1078 | |
| 1079 SetCGATSfld(ContextID, Buffer, Float[i] * 100.0); | |
| 1080 } | |
| 1081 } | |
| 1082 break; | |
| 1083 | |
| 1084 default: | |
| 1085 { | |
| 1086 | |
| 1087 cmsInt32Number i, n; | |
| 1088 | |
| 1089 n = cmsChannelsOfColorSpace(ContextID, InputColorSpace); | |
| 1090 for (i=0; i < n; i++) { | |
| 1091 | |
| 1092 char Buffer[255]; | |
| 1093 | |
| 1094 sprintf(Buffer, "CHAN_%u", i+1); | |
| 1095 | |
| 1096 SetCGATSfld(ContextID, Buffer, Float[i]); | |
| 1097 } | |
| 1098 } | |
| 1099 } | |
| 1100 } | |
| 1101 | |
| 1102 | |
| 1103 | |
| 1104 // Create data format | |
| 1105 static | |
| 1106 void SetOutputDataFormat(cmsContext ContextID) | |
| 1107 { | |
| 1108 cmsIT8DefineDblFormat(ContextID, hIT8out, "%.4g"); | |
| 1109 cmsIT8SetPropertyStr(ContextID, hIT8out, "ORIGINATOR", "icctrans"); | |
| 1110 | |
| 1111 if (IncludePart != NULL) | |
| 1112 cmsIT8SetPropertyStr(ContextID, hIT8out, ".INCLUDE", IncludePart); | |
| 1113 | |
| 1114 cmsIT8SetComment(ContextID, hIT8out, "Data follows"); | |
| 1115 cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_SETS", nMaxPatches); | |
| 1116 | |
| 1117 | |
| 1118 switch (OutputColorSpace) { | |
| 1119 | |
| 1120 | |
| 1121 // Encoding should follow CGATS specification. | |
| 1122 | |
| 1123 case cmsSigXYZData: | |
| 1124 cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4); | |
| 1125 cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID"); | |
| 1126 cmsIT8SetDataFormat(ContextID, hIT8out, 1, "XYZ_X"); | |
| 1127 cmsIT8SetDataFormat(ContextID, hIT8out, 2, "XYZ_Y"); | |
| 1128 cmsIT8SetDataFormat(ContextID, hIT8out, 3, "XYZ_Z"); | |
| 1129 break; | |
| 1130 | |
| 1131 case cmsSigLabData: | |
| 1132 cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4); | |
| 1133 cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID"); | |
| 1134 cmsIT8SetDataFormat(ContextID, hIT8out, 1, "LAB_L"); | |
| 1135 cmsIT8SetDataFormat(ContextID, hIT8out, 2, "LAB_A"); | |
| 1136 cmsIT8SetDataFormat(ContextID, hIT8out, 3, "LAB_B"); | |
| 1137 break; | |
| 1138 | |
| 1139 | |
| 1140 case cmsSigRgbData: | |
| 1141 cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4); | |
| 1142 cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID"); | |
| 1143 cmsIT8SetDataFormat(ContextID, hIT8out, 1, "RGB_R"); | |
| 1144 cmsIT8SetDataFormat(ContextID, hIT8out, 2, "RGB_G"); | |
| 1145 cmsIT8SetDataFormat(ContextID, hIT8out, 3, "RGB_B"); | |
| 1146 break; | |
| 1147 | |
| 1148 case cmsSigGrayData: | |
| 1149 cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 2); | |
| 1150 cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID"); | |
| 1151 cmsIT8SetDataFormat(ContextID, hIT8out, 1, "GRAY"); | |
| 1152 break; | |
| 1153 | |
| 1154 case cmsSigCmykData: | |
| 1155 cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 5); | |
| 1156 cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID"); | |
| 1157 cmsIT8SetDataFormat(ContextID, hIT8out, 1, "CMYK_C"); | |
| 1158 cmsIT8SetDataFormat(ContextID, hIT8out, 2, "CMYK_M"); | |
| 1159 cmsIT8SetDataFormat(ContextID, hIT8out, 3, "CMYK_Y"); | |
| 1160 cmsIT8SetDataFormat(ContextID, hIT8out, 4, "CMYK_K"); | |
| 1161 break; | |
| 1162 | |
| 1163 case cmsSigCmyData: | |
| 1164 cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", 4); | |
| 1165 cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID"); | |
| 1166 cmsIT8SetDataFormat(ContextID, hIT8out, 1, "CMY_C"); | |
| 1167 cmsIT8SetDataFormat(ContextID, hIT8out, 2, "CMY_M"); | |
| 1168 cmsIT8SetDataFormat(ContextID, hIT8out, 3, "CMY_Y"); | |
| 1169 break; | |
| 1170 | |
| 1171 case cmsSig1colorData: | |
| 1172 case cmsSig2colorData: | |
| 1173 case cmsSig3colorData: | |
| 1174 case cmsSig4colorData: | |
| 1175 case cmsSig5colorData: | |
| 1176 case cmsSig6colorData: | |
| 1177 case cmsSig7colorData: | |
| 1178 case cmsSig8colorData: | |
| 1179 case cmsSig9colorData: | |
| 1180 case cmsSig10colorData: | |
| 1181 case cmsSig11colorData: | |
| 1182 case cmsSig12colorData: | |
| 1183 case cmsSig13colorData: | |
| 1184 case cmsSig14colorData: | |
| 1185 case cmsSig15colorData: | |
| 1186 { | |
| 1187 int i, n; | |
| 1188 char Buffer[255]; | |
| 1189 | |
| 1190 n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace); | |
| 1191 cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", n+1); | |
| 1192 cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID"); | |
| 1193 | |
| 1194 for (i=1; i <= n; i++) { | |
| 1195 sprintf(Buffer, "%dCLR_%d", n, i); | |
| 1196 cmsIT8SetDataFormat(ContextID, hIT8out, i, Buffer); | |
| 1197 } | |
| 1198 } | |
| 1199 break; | |
| 1200 | |
| 1201 default: { | |
| 1202 | |
| 1203 int i, n; | |
| 1204 char Buffer[255]; | |
| 1205 | |
| 1206 n = cmsChannelsOfColorSpace(ContextID, OutputColorSpace); | |
| 1207 cmsIT8SetPropertyDbl(ContextID, hIT8out, "NUMBER_OF_FIELDS", n+1); | |
| 1208 cmsIT8SetDataFormat(ContextID, hIT8out, 0, "SAMPLE_ID"); | |
| 1209 | |
| 1210 for (i=1; i <= n; i++) { | |
| 1211 sprintf(Buffer, "CHAN_%d", i); | |
| 1212 cmsIT8SetDataFormat(ContextID, hIT8out, i, Buffer); | |
| 1213 } | |
| 1214 } | |
| 1215 } | |
| 1216 } | |
| 1217 | |
| 1218 // Open CGATS if specified | |
| 1219 | |
| 1220 static | |
| 1221 void OpenCGATSFiles(cmsContext ContextID, int argc, char *argv[]) | |
| 1222 { | |
| 1223 int nParams = argc - xoptind; | |
| 1224 | |
| 1225 if (nParams >= 1) { | |
| 1226 | |
| 1227 hIT8in = cmsIT8LoadFromFile(0, argv[xoptind]); | |
| 1228 | |
| 1229 if (hIT8in == NULL) | |
| 1230 FatalError("'%s' is not recognized as a CGATS file", argv[xoptind]); | |
| 1231 | |
| 1232 nMaxPatches = (int) cmsIT8GetPropertyDbl(ContextID, hIT8in, "NUMBER_OF_SETS"); | |
| 1233 } | |
| 1234 | |
| 1235 if (nParams == 2) { | |
| 1236 | |
| 1237 hIT8out = cmsIT8Alloc(NULL); | |
| 1238 SetOutputDataFormat(ContextID); | |
| 1239 strncpy(CGATSoutFilename, argv[xoptind+1], cmsMAX_PATH-1); | |
| 1240 } | |
| 1241 | |
| 1242 if (nParams > 2) FatalError("Too many CGATS files"); | |
| 1243 } | |
| 1244 | |
| 1245 | |
| 1246 | |
| 1247 // The main sink | |
| 1248 int main(int argc, char *argv[]) | |
| 1249 { | |
| 1250 cmsUInt16Number Output[cmsMAXCHANNELS]; | |
| 1251 cmsFloat64Number OutputFloat[cmsMAXCHANNELS]; | |
| 1252 cmsFloat64Number InputFloat[cmsMAXCHANNELS]; | |
| 1253 cmsContext ContextID = NULL; | |
| 1254 | |
| 1255 int nPatch = 0; | |
| 1256 | |
| 1257 fprintf(stderr, "LittleCMS ColorSpace conversion calculator - 5.1 [LittleCMS %2.2f]\n", cmsGetEncodedCMMversion() / 1000.0); | |
| 1258 fprintf(stderr, "Copyright (c) 1998-2023 Marti Maria Saguer. See COPYING file for details.\n"); | |
| 1259 fflush(stderr); | |
| 1260 | |
| 1261 InitUtils(ContextID, "transicc"); | |
| 1262 | |
| 1263 Verbose = 1; | |
| 1264 | |
| 1265 if (argc == 1) { | |
| 1266 | |
| 1267 Help(); | |
| 1268 return 0; | |
| 1269 } | |
| 1270 | |
| 1271 HandleSwitches(ContextID, argc, argv); | |
| 1272 | |
| 1273 // Open profiles, create transforms | |
| 1274 if (!OpenTransforms(ContextID)) return 1; | |
| 1275 | |
| 1276 // Open CGATS input if specified | |
| 1277 OpenCGATSFiles(ContextID, argc, argv); | |
| 1278 | |
| 1279 // Main loop: read all values and convert them | |
| 1280 for(;;) { | |
| 1281 | |
| 1282 if (hIT8in != NULL) { | |
| 1283 | |
| 1284 if (nPatch >= nMaxPatches) break; | |
| 1285 TakeCGATSValues(ContextID, nPatch++, InputFloat); | |
| 1286 | |
| 1287 } else { | |
| 1288 | |
| 1289 if (feof(stdin)) break; | |
| 1290 TakeFloatValues(ContextID, InputFloat); | |
| 1291 | |
| 1292 } | |
| 1293 | |
| 1294 if (lIsFloat) | |
| 1295 cmsDoTransform(ContextID, hTrans, InputFloat, OutputFloat, 1); | |
| 1296 else | |
| 1297 cmsDoTransform(ContextID, hTrans, InputFloat, Output, 1); | |
| 1298 | |
| 1299 | |
| 1300 if (hIT8out != NULL) { | |
| 1301 | |
| 1302 PutCGATSValues(ContextID, OutputFloat); | |
| 1303 } | |
| 1304 else { | |
| 1305 | |
| 1306 if (lIsFloat) { | |
| 1307 PrintFloatResults(ContextID, OutputFloat); PrintPCSFloat(ContextID, InputFloat); | |
| 1308 } | |
| 1309 else { | |
| 1310 PrintEncodedResults(ContextID, Output); PrintPCSEncoded(ContextID, InputFloat); | |
| 1311 } | |
| 1312 | |
| 1313 } | |
| 1314 } | |
| 1315 | |
| 1316 | |
| 1317 // Cleanup | |
| 1318 CloseTransforms(ContextID); | |
| 1319 | |
| 1320 if (hIT8in) | |
| 1321 cmsIT8Free(ContextID, hIT8in); | |
| 1322 | |
| 1323 if (hIT8out) { | |
| 1324 cmsIT8SaveToFile(ContextID, hIT8out, CGATSoutFilename); | |
| 1325 cmsIT8Free(ContextID, hIT8out); | |
| 1326 } | |
| 1327 | |
| 1328 // All is ok | |
| 1329 return 0; | |
| 1330 } |
