Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/lcms2/utils/matlab/icctrans.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 // Little cms | |
| 3 // Copyright (C) 1998-2010 Marti Maria, Ignacio Ruiz de Conejo | |
| 4 // | |
| 5 // Permission is hereby granted, free of charge, to any person obtaining | |
| 6 // a copy of this software and associated documentation files (the "Software"), | |
| 7 // to deal in the Software without restriction, including without limitation | |
| 8 // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 9 // and/or sell copies of the Software, and to permit persons to whom the Software | |
| 10 // is furnished to do so, subject to the following conditions: | |
| 11 // | |
| 12 // The above copyright notice and this permission notice shall be included in | |
| 13 // all copies or substantial portions of the Software. | |
| 14 // | |
| 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| 16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO | |
| 17 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| 18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
| 19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
| 20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
| 21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| 22 | |
| 23 | |
| 24 #include "mex.h" | |
| 25 | |
| 26 #include "lcms2mt.h" | |
| 27 #include "string.h" | |
| 28 #include "stdarg.h" | |
| 29 | |
| 30 // xgetopt() interface ----------------------------------------------------- | |
| 31 | |
| 32 static int xoptind; | |
| 33 static char *xoptarg; | |
| 34 static int xopterr; | |
| 35 static char *letP; | |
| 36 static char SW = '-'; | |
| 37 | |
| 38 // ------------------------------------------------------------------------ | |
| 39 | |
| 40 | |
| 41 static int Verbose ; // Print some statistics | |
| 42 static char *cInProf; // Input profile | |
| 43 static char *cOutProf; // Output profile | |
| 44 static char *cProofing; // Softproofing profile | |
| 45 | |
| 46 | |
| 47 static int Intent; // Rendering Intent | |
| 48 static int ProofingIntent; // RI for proof | |
| 49 | |
| 50 static int PrecalcMode; // 0 = Not, 1=Normal, 2=Accurate, 3=Fast | |
| 51 | |
| 52 static cmsBool BlackPointCompensation; | |
| 53 static cmsBool lIsDeviceLink; | |
| 54 static cmsBool lMultiProfileChain; // Multiple profile chain | |
| 55 | |
| 56 static cmsHPROFILE hInput, hOutput, hProof; | |
| 57 static cmsHTRANSFORM hColorTransform; | |
| 58 static cmsHPROFILE hProfiles[255]; | |
| 59 static int nProfiles; | |
| 60 | |
| 61 static cmsColorSpaceSignature InputColorSpace, OutputColorSpace; | |
| 62 static int OutputChannels, InputChannels, nBytesDepth; | |
| 63 | |
| 64 | |
| 65 // Error. Print error message and abort | |
| 66 | |
| 67 static | |
| 68 cmsBool FatalError(const char *frm, ...) | |
| 69 { | |
| 70 va_list args; | |
| 71 char Buffer[1024]; | |
| 72 | |
| 73 va_start(args, frm); | |
| 74 vsprintf(Buffer, frm, args); | |
| 75 mexErrMsgTxt(Buffer); | |
| 76 va_end(args); | |
| 77 | |
| 78 return FALSE; | |
| 79 } | |
| 80 | |
| 81 // This is the handler passed to lcms | |
| 82 | |
| 83 static | |
| 84 void MatLabErrorHandler(cmsContext ContextID, cmsUInt32Number ErrorCode, | |
| 85 const char *Text) | |
| 86 { | |
| 87 mexErrMsgTxt(Text); | |
| 88 } | |
| 89 // | |
| 90 // Parse the command line options, System V style. | |
| 91 // | |
| 92 | |
| 93 static | |
| 94 void xoptinit() | |
| 95 { | |
| 96 xoptind = 1; | |
| 97 xopterr = 0; | |
| 98 letP = NULL; | |
| 99 } | |
| 100 | |
| 101 | |
| 102 static | |
| 103 int xgetopt(int argc, char *argv[], char *optionS) | |
| 104 { | |
| 105 unsigned char ch; | |
| 106 char *optP; | |
| 107 | |
| 108 if (SW == 0) { | |
| 109 SW = '/'; | |
| 110 } | |
| 111 | |
| 112 if (argc > xoptind) { | |
| 113 if (letP == NULL) { | |
| 114 if ((letP = argv[xoptind]) == NULL || | |
| 115 *(letP++) != SW) goto gopEOF; | |
| 116 if (*letP == SW) { | |
| 117 xoptind++; goto gopEOF; | |
| 118 } | |
| 119 } | |
| 120 if (0 == (ch = *(letP++))) { | |
| 121 xoptind++; goto gopEOF; | |
| 122 } | |
| 123 if (':' == ch || (optP = strchr(optionS, ch)) == NULL) | |
| 124 goto gopError; | |
| 125 if (':' == *(++optP)) { | |
| 126 xoptind++; | |
| 127 if (0 == *letP) { | |
| 128 if (argc <= xoptind) goto gopError; | |
| 129 letP = argv[xoptind++]; | |
| 130 } | |
| 131 xoptarg = letP; | |
| 132 letP = NULL; | |
| 133 } else { | |
| 134 if (0 == *letP) { | |
| 135 xoptind++; | |
| 136 letP = NULL; | |
| 137 } | |
| 138 xoptarg = NULL; | |
| 139 } | |
| 140 return ch; | |
| 141 } | |
| 142 gopEOF: | |
| 143 xoptarg = letP = NULL; | |
| 144 return EOF; | |
| 145 | |
| 146 gopError: | |
| 147 xoptarg = NULL; | |
| 148 if (xopterr) | |
| 149 FatalError ("get command line option"); | |
| 150 return ('?'); | |
| 151 } | |
| 152 | |
| 153 | |
| 154 // Return Mathlab type by depth | |
| 155 | |
| 156 static | |
| 157 size_t SizeOfArrayType(const mxArray *Array) | |
| 158 { | |
| 159 | |
| 160 switch (mxGetClassID(Array)) { | |
| 161 | |
| 162 case mxINT8_CLASS: return 1; | |
| 163 case mxUINT8_CLASS: return 1; | |
| 164 case mxINT16_CLASS: return 2; | |
| 165 case mxUINT16_CLASS: return 2; | |
| 166 case mxSINGLE_CLASS: return 4; | |
| 167 case mxDOUBLE_CLASS: return 0; // Special case -- lcms handles double as size=0 | |
| 168 | |
| 169 | |
| 170 default: | |
| 171 FatalError("Unsupported data type"); | |
| 172 return 0; | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 | |
| 177 // Get number of pixels of input array. Supported arrays are | |
| 178 // organized as NxMxD, being N and M the size of image and D the | |
| 179 // number of components. | |
| 180 | |
| 181 static | |
| 182 size_t GetNumberOfPixels(const mxArray* In) | |
| 183 { | |
| 184 int nDimensions = mxGetNumberOfDimensions(In); | |
| 185 const int *Dimensions = mxGetDimensions(In); | |
| 186 | |
| 187 switch (nDimensions) { | |
| 188 | |
| 189 case 1: return 1; // It is just a spot color | |
| 190 case 2: return Dimensions[0]; // A scanline | |
| 191 case 3: return Dimensions[0]*Dimensions[1]; // A image | |
| 192 | |
| 193 default: | |
| 194 FatalError("Unsupported array of %d dimensions", nDimensions); | |
| 195 return 0; | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 | |
| 200 // Allocates the output array. Copies the input array modifying the pixel | |
| 201 // definition to match "OutputChannels". | |
| 202 | |
| 203 static | |
| 204 mxArray* AllocateOutputArray(const mxArray* In, int OutputChannels) | |
| 205 { | |
| 206 | |
| 207 mxArray* Out = mxDuplicateArray(In); // Make a "deep copy" of Input array | |
| 208 int nDimensions = mxGetNumberOfDimensions(In); | |
| 209 const int* Dimensions = mxGetDimensions(In); | |
| 210 int InputChannels = Dimensions[nDimensions-1]; | |
| 211 | |
| 212 | |
| 213 // Modify pixel size only if needed | |
| 214 | |
| 215 if (InputChannels != OutputChannels) { | |
| 216 | |
| 217 | |
| 218 int i, NewSize; | |
| 219 int *ModifiedDimensions = (int*) mxMalloc(nDimensions * sizeof(int)); | |
| 220 | |
| 221 | |
| 222 memmove(ModifiedDimensions, Dimensions, nDimensions * sizeof(int)); | |
| 223 ModifiedDimensions[nDimensions - 1] = OutputChannels; | |
| 224 | |
| 225 switch (mxGetClassID(In)) { | |
| 226 | |
| 227 case mxINT8_CLASS: NewSize = sizeof(char); break; | |
| 228 case mxUINT8_CLASS: NewSize = sizeof(unsigned char); break; | |
| 229 case mxINT16_CLASS: NewSize = sizeof(short); break; | |
| 230 case mxUINT16_CLASS: NewSize = sizeof(unsigned short); break; | |
| 231 | |
| 232 default: | |
| 233 case mxDOUBLE_CLASS: NewSize = sizeof(double); break; | |
| 234 } | |
| 235 | |
| 236 | |
| 237 // NewSize = 1; | |
| 238 for (i=0; i < nDimensions; i++) | |
| 239 NewSize *= ModifiedDimensions[i]; | |
| 240 | |
| 241 | |
| 242 mxSetDimensions(Out, ModifiedDimensions, nDimensions); | |
| 243 mxFree(ModifiedDimensions); | |
| 244 | |
| 245 mxSetPr(Out, mxRealloc(mxGetPr(Out), NewSize)); | |
| 246 | |
| 247 } | |
| 248 | |
| 249 | |
| 250 return Out; | |
| 251 } | |
| 252 | |
| 253 | |
| 254 | |
| 255 // Does create a format descriptor. "Bytes" is the sizeof type in bytes | |
| 256 // | |
| 257 // Bytes Meaning | |
| 258 // ------ -------- | |
| 259 // 0 Floating point (double) | |
| 260 // 1 8-bit samples | |
| 261 // 2 16-bit samples | |
| 262 | |
| 263 static | |
| 264 cmsUInt32Number MakeFormatDescriptor(cmsColorSpaceSignature ColorSpace, int Bytes) | |
| 265 { | |
| 266 int IsFloat = (Bytes == 0 || Bytes == 4) ? 1 : 0; | |
| 267 int Channels = cmsChannelsOf(ColorSpace); | |
| 268 return FLOAT_SH(IsFloat)|COLORSPACE_SH(_cmsLCMScolorSpace(ColorSpace))|BYTES_SH(Bytes)|CHANNELS_SH(Channels)|PLANAR_SH(1); | |
| 269 } | |
| 270 | |
| 271 | |
| 272 // Opens a profile or proper built-in | |
| 273 | |
| 274 static | |
| 275 cmsHPROFILE OpenProfile(const char* File) | |
| 276 { | |
| 277 | |
| 278 cmsContext ContextID = 0; | |
| 279 | |
| 280 if (!File) | |
| 281 return cmsCreate_sRGBProfileTHR(ContextID); | |
| 282 | |
| 283 if (cmsstrcasecmp(File, "*Lab2") == 0) | |
| 284 return cmsCreateLab2ProfileTHR(ContextID, NULL); | |
| 285 | |
| 286 if (cmsstrcasecmp(File, "*Lab4") == 0) | |
| 287 return cmsCreateLab4ProfileTHR(ContextID, NULL); | |
| 288 | |
| 289 if (cmsstrcasecmp(File, "*Lab") == 0) | |
| 290 return cmsCreateLab4ProfileTHR(ContextID, NULL); | |
| 291 | |
| 292 if (cmsstrcasecmp(File, "*LabD65") == 0) { | |
| 293 | |
| 294 cmsCIExyY D65xyY; | |
| 295 | |
| 296 cmsWhitePointFromTemp( &D65xyY, 6504); | |
| 297 return cmsCreateLab4ProfileTHR(ContextID, &D65xyY); | |
| 298 } | |
| 299 | |
| 300 if (cmsstrcasecmp(File, "*XYZ") == 0) | |
| 301 return cmsCreateXYZProfileTHR(ContextID); | |
| 302 | |
| 303 if (cmsstrcasecmp(File, "*Gray22") == 0) { | |
| 304 | |
| 305 cmsToneCurve* Curve = cmsBuildGamma(ContextID, 2.2); | |
| 306 cmsHPROFILE hProfile = cmsCreateGrayProfileTHR(ContextID, cmsD50_xyY(), Curve); | |
| 307 cmsFreeToneCurve(Curve); | |
| 308 return hProfile; | |
| 309 } | |
| 310 | |
| 311 if (cmsstrcasecmp(File, "*Gray30") == 0) { | |
| 312 | |
| 313 cmsToneCurve* Curve = cmsBuildGamma(ContextID, 3.0); | |
| 314 cmsHPROFILE hProfile = cmsCreateGrayProfileTHR(ContextID, cmsD50_xyY(), Curve); | |
| 315 cmsFreeToneCurve(Curve); | |
| 316 return hProfile; | |
| 317 } | |
| 318 | |
| 319 if (cmsstrcasecmp(File, "*srgb") == 0) | |
| 320 return cmsCreate_sRGBProfileTHR(ContextID); | |
| 321 | |
| 322 if (cmsstrcasecmp(File, "*null") == 0) | |
| 323 return cmsCreateNULLProfileTHR(ContextID); | |
| 324 | |
| 325 | |
| 326 if (cmsstrcasecmp(File, "*Lin2222") == 0) { | |
| 327 | |
| 328 cmsToneCurve* Gamma = cmsBuildGamma(0, 2.2); | |
| 329 cmsToneCurve* Gamma4[4]; | |
| 330 cmsHPROFILE hProfile; | |
| 331 | |
| 332 Gamma4[0] = Gamma4[1] = Gamma4[2] = Gamma4[3] = Gamma; | |
| 333 hProfile = cmsCreateLinearizationDeviceLink(cmsSigCmykData, Gamma4); | |
| 334 cmsFreeToneCurve(Gamma); | |
| 335 return hProfile; | |
| 336 } | |
| 337 | |
| 338 | |
| 339 return cmsOpenProfileFromFileTHR(ContextID, File, "r"); | |
| 340 } | |
| 341 | |
| 342 | |
| 343 static | |
| 344 cmsUInt32Number GetFlags() | |
| 345 { | |
| 346 cmsUInt32Number dwFlags = 0; | |
| 347 | |
| 348 switch (PrecalcMode) { | |
| 349 | |
| 350 case 0: dwFlags = cmsFLAGS_NOOPTIMIZE; break; | |
| 351 case 2: dwFlags = cmsFLAGS_HIGHRESPRECALC; break; | |
| 352 case 3: dwFlags = cmsFLAGS_LOWRESPRECALC; break; | |
| 353 case 1: break; | |
| 354 | |
| 355 default: FatalError("Unknown precalculation mode '%d'", PrecalcMode); | |
| 356 } | |
| 357 | |
| 358 if (BlackPointCompensation) | |
| 359 dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION; | |
| 360 | |
| 361 return dwFlags; | |
| 362 } | |
| 363 | |
| 364 // Create transforms | |
| 365 | |
| 366 static | |
| 367 void OpenTransforms(int argc, char *argv[]) | |
| 368 { | |
| 369 | |
| 370 cmsUInt32Number dwIn, dwOut, dwFlags; | |
| 371 | |
| 372 | |
| 373 if (lMultiProfileChain) { | |
| 374 | |
| 375 int i; | |
| 376 cmsHTRANSFORM hTmp; | |
| 377 | |
| 378 | |
| 379 nProfiles = argc - xoptind; | |
| 380 for (i=0; i < nProfiles; i++) { | |
| 381 | |
| 382 hProfiles[i] = OpenProfile(argv[i+xoptind]); | |
| 383 } | |
| 384 | |
| 385 | |
| 386 // Create a temporary devicelink | |
| 387 | |
| 388 hTmp = cmsCreateMultiprofileTransform(hProfiles, nProfiles, | |
| 389 0, 0, Intent, GetFlags()); | |
| 390 | |
| 391 hInput = cmsTransform2DeviceLink(hTmp, 4.2, 0); | |
| 392 hOutput = NULL; | |
| 393 cmsDeleteTransform(hTmp); | |
| 394 | |
| 395 InputColorSpace = cmsGetColorSpace(hInput); | |
| 396 OutputColorSpace = cmsGetPCS(hInput); | |
| 397 lIsDeviceLink = TRUE; | |
| 398 | |
| 399 } | |
| 400 else | |
| 401 if (lIsDeviceLink) { | |
| 402 | |
| 403 hInput = cmsOpenProfileFromFile(cInProf, "r"); | |
| 404 hOutput = NULL; | |
| 405 InputColorSpace = cmsGetColorSpace(hInput); | |
| 406 OutputColorSpace = cmsGetPCS(hInput); | |
| 407 | |
| 408 | |
| 409 } | |
| 410 else { | |
| 411 | |
| 412 hInput = OpenProfile(cInProf); | |
| 413 hOutput = OpenProfile(cOutProf); | |
| 414 | |
| 415 InputColorSpace = cmsGetColorSpace(hInput); | |
| 416 OutputColorSpace = cmsGetColorSpace(hOutput); | |
| 417 | |
| 418 if (cmsGetDeviceClass(hInput) == cmsSigLinkClass || | |
| 419 cmsGetDeviceClass(hOutput) == cmsSigLinkClass) | |
| 420 FatalError("Use %cl flag for devicelink profiles!\n", SW); | |
| 421 | |
| 422 } | |
| 423 | |
| 424 | |
| 425 /* | |
| 426 | |
| 427 if (Verbose) { | |
| 428 | |
| 429 mexPrintf("From: %s\n", cmsTakeProductName(hInput)); | |
| 430 if (hOutput) mexPrintf("To : %s\n\n", cmsTakeProductName(hOutput)); | |
| 431 | |
| 432 } | |
| 433 */ | |
| 434 | |
| 435 | |
| 436 OutputChannels = cmsChannelsOf(OutputColorSpace); | |
| 437 InputChannels = cmsChannelsOf(InputColorSpace); | |
| 438 | |
| 439 | |
| 440 dwIn = MakeFormatDescriptor(InputColorSpace, nBytesDepth); | |
| 441 dwOut = MakeFormatDescriptor(OutputColorSpace, nBytesDepth); | |
| 442 | |
| 443 | |
| 444 dwFlags = GetFlags(); | |
| 445 | |
| 446 if (cProofing != NULL) { | |
| 447 | |
| 448 hProof = OpenProfile(cProofing); | |
| 449 dwFlags |= cmsFLAGS_SOFTPROOFING; | |
| 450 } | |
| 451 | |
| 452 | |
| 453 | |
| 454 | |
| 455 hColorTransform = cmsCreateProofingTransform(hInput, dwIn, | |
| 456 hOutput, dwOut, | |
| 457 hProof, Intent, | |
| 458 ProofingIntent, | |
| 459 dwFlags); | |
| 460 | |
| 461 } | |
| 462 | |
| 463 | |
| 464 | |
| 465 static | |
| 466 void ApplyTransforms(const mxArray *In, mxArray *Out) | |
| 467 { | |
| 468 double *Input = mxGetPr(In); | |
| 469 double *Output = mxGetPr(Out); | |
| 470 size_t nPixels = GetNumberOfPixels(In);; | |
| 471 | |
| 472 cmsDoTransform(hColorTransform, Input, Output, nPixels ); | |
| 473 | |
| 474 } | |
| 475 | |
| 476 | |
| 477 static | |
| 478 void CloseTransforms(void) | |
| 479 { | |
| 480 int i; | |
| 481 | |
| 482 if (hColorTransform) cmsDeleteTransform(hColorTransform); | |
| 483 if (hInput) cmsCloseProfile(hInput); | |
| 484 if (hOutput) cmsCloseProfile(hOutput); | |
| 485 if (hProof) cmsCloseProfile(hProof); | |
| 486 | |
| 487 for (i=0; i < nProfiles; i++) | |
| 488 cmsCloseProfile(hProfiles[i]); | |
| 489 | |
| 490 hColorTransform = NULL; hInput = NULL; hOutput = NULL; hProof = NULL; | |
| 491 } | |
| 492 | |
| 493 | |
| 494 static | |
| 495 void HandleSwitches(int argc, char *argv[]) | |
| 496 { | |
| 497 int s; | |
| 498 | |
| 499 xoptinit(); | |
| 500 | |
| 501 while ((s = xgetopt(argc, argv,"C:c:VvbBI:i:O:o:T:t:L:l:r:r:P:p:Mm")) != EOF) { | |
| 502 | |
| 503 | |
| 504 switch (s){ | |
| 505 | |
| 506 case 'b': | |
| 507 case 'B': | |
| 508 BlackPointCompensation = TRUE; | |
| 509 break; | |
| 510 | |
| 511 case 'c': | |
| 512 case 'C': | |
| 513 PrecalcMode = atoi(xoptarg); | |
| 514 if (PrecalcMode < 0 || PrecalcMode > 3) | |
| 515 FatalError("Unknown precalc mode '%d'", PrecalcMode); | |
| 516 break; | |
| 517 | |
| 518 case 'v': | |
| 519 case 'V': | |
| 520 Verbose = TRUE; | |
| 521 break; | |
| 522 | |
| 523 case 'i': | |
| 524 case 'I': | |
| 525 if (lIsDeviceLink) | |
| 526 FatalError("Device-link already specified"); | |
| 527 cInProf = xoptarg; | |
| 528 break; | |
| 529 | |
| 530 case 'o': | |
| 531 case 'O': | |
| 532 if (lIsDeviceLink) | |
| 533 FatalError("Device-link already specified"); | |
| 534 cOutProf = xoptarg; | |
| 535 break; | |
| 536 | |
| 537 case 't': | |
| 538 case 'T': | |
| 539 Intent = atoi(xoptarg); | |
| 540 // if (Intent > 3) Intent = 3; | |
| 541 if (Intent < 0) Intent = 0; | |
| 542 break; | |
| 543 | |
| 544 | |
| 545 case 'l': | |
| 546 case 'L': | |
| 547 cInProf = xoptarg; | |
| 548 lIsDeviceLink = TRUE; | |
| 549 break; | |
| 550 | |
| 551 case 'p': | |
| 552 case 'P': | |
| 553 cProofing = xoptarg; | |
| 554 break; | |
| 555 | |
| 556 | |
| 557 | |
| 558 case 'r': | |
| 559 case 'R': | |
| 560 ProofingIntent = atoi(xoptarg); | |
| 561 // if (ProofingIntent > 3) ProofingIntent = 3; | |
| 562 if (ProofingIntent < 0) ProofingIntent = 0; | |
| 563 break; | |
| 564 | |
| 565 | |
| 566 case 'm': | |
| 567 case 'M': | |
| 568 lMultiProfileChain = TRUE; | |
| 569 break; | |
| 570 | |
| 571 default: | |
| 572 FatalError("Unknown option."); | |
| 573 } | |
| 574 } | |
| 575 | |
| 576 // For multiprofile, need to specify -m | |
| 577 | |
| 578 if (xoptind < argc) { | |
| 579 | |
| 580 if (!lMultiProfileChain) | |
| 581 FatalError("Use %cm for multiprofile transforms", SW); | |
| 582 } | |
| 583 | |
| 584 } | |
| 585 | |
| 586 | |
| 587 | |
| 588 // -------------------------------------------------- Print some fancy help | |
| 589 static | |
| 590 void PrintHelp(void) | |
| 591 { | |
| 592 mexPrintf("(MX) little cms ColorSpace conversion tool - v2.0\n\n"); | |
| 593 | |
| 594 mexPrintf("usage: icctrans (mVar, flags)\n\n"); | |
| 595 | |
| 596 mexPrintf("mVar : Matlab array.\n"); | |
| 597 mexPrintf("flags: a string containing one or more of following options.\n\n"); | |
| 598 mexPrintf("\t%cv - Verbose\n", SW); | |
| 599 mexPrintf("\t%ci<profile> - Input profile (defaults to sRGB)\n", SW); | |
| 600 mexPrintf("\t%co<profile> - Output profile (defaults to sRGB)\n", SW); | |
| 601 mexPrintf("\t%cl<profile> - Transform by device-link profile\n", SW); | |
| 602 mexPrintf("\t%cm<profiles> - Apply multiprofile chain\n", SW); | |
| 603 | |
| 604 mexPrintf("\t%ct<n> - Rendering intent\n", SW); | |
| 605 | |
| 606 mexPrintf("\t%cb - Black point compensation\n", SW); | |
| 607 mexPrintf("\t%cc<0,1,2,3> - Optimize transform (0=Off, 1=Normal, 2=Hi-res, 3=Lo-Res) [defaults to 1]\n", SW); | |
| 608 | |
| 609 mexPrintf("\t%cp<profile> - Soft proof profile\n", SW); | |
| 610 mexPrintf("\t%cr<0,1,2,3> - Soft proof intent\n", SW); | |
| 611 | |
| 612 mexPrintf("\nYou can use following built-ins as profiles:\n\n"); | |
| 613 | |
| 614 mexPrintf("\t*Lab2 -- D50-based v2 CIEL*a*b\n" | |
| 615 "\t*Lab4 -- D50-based v4 CIEL*a*b\n" | |
| 616 "\t*Lab -- D50-based v4 CIEL*a*b\n" | |
| 617 "\t*XYZ -- CIE XYZ (PCS)\n" | |
| 618 "\t*sRGB -- IEC6 1996-2.1 sRGB color space\n" | |
| 619 "\t*Gray22 - Monochrome of Gamma 2.2\n" | |
| 620 "\t*Gray30 - Monochrome of Gamma 3.0\n" | |
| 621 "\t*null - Monochrome black for all input\n" | |
| 622 "\t*Lin2222- CMYK linearization of gamma 2.2 on each channel\n\n"); | |
| 623 | |
| 624 mexPrintf("For suggestions, comments, bug reports etc. send mail to info@littlecms.com\n\n"); | |
| 625 | |
| 626 } | |
| 627 | |
| 628 | |
| 629 | |
| 630 // Main entry point | |
| 631 | |
| 632 void mexFunction( | |
| 633 int nlhs, // Number of left hand side (output) arguments | |
| 634 mxArray *plhs[], // Array of left hand side arguments | |
| 635 int nrhs, // Number of right hand side (input) arguments | |
| 636 const mxArray *prhs[] // Array of right hand side arguments | |
| 637 ) | |
| 638 { | |
| 639 | |
| 640 char CommandLine[4096+1]; | |
| 641 char *pt, *argv[128]; | |
| 642 int argc = 1; | |
| 643 | |
| 644 | |
| 645 if (nrhs != 2) { | |
| 646 | |
| 647 PrintHelp(); | |
| 648 return; | |
| 649 } | |
| 650 | |
| 651 | |
| 652 if(nlhs > 1) { | |
| 653 FatalError("Too many output arguments."); | |
| 654 } | |
| 655 | |
| 656 | |
| 657 // Setup error handler | |
| 658 | |
| 659 cmsSetLogErrorHandler(MatLabErrorHandler); | |
| 660 | |
| 661 // Defaults | |
| 662 | |
| 663 Verbose = 0; | |
| 664 cInProf = NULL; | |
| 665 cOutProf = NULL; | |
| 666 cProofing = NULL; | |
| 667 | |
| 668 lMultiProfileChain = FALSE; | |
| 669 nProfiles = 0; | |
| 670 | |
| 671 Intent = INTENT_PERCEPTUAL; | |
| 672 ProofingIntent = INTENT_ABSOLUTE_COLORIMETRIC; | |
| 673 PrecalcMode = 1; | |
| 674 BlackPointCompensation = FALSE; | |
| 675 lIsDeviceLink = FALSE; | |
| 676 | |
| 677 // Check types. Fist parameter is array of values, second parameter is command line | |
| 678 | |
| 679 if (!mxIsNumeric(prhs[0])) | |
| 680 FatalError("Type mismatch on argument 1 -- Must be numeric"); | |
| 681 | |
| 682 if (!mxIsChar(prhs[1])) | |
| 683 FatalError("Type mismatch on argument 2 -- Must be string"); | |
| 684 | |
| 685 | |
| 686 | |
| 687 | |
| 688 // Unpack string to command line buffer | |
| 689 | |
| 690 if (mxGetString(prhs[1], CommandLine, 4096)) | |
| 691 FatalError("Cannot unpack command string"); | |
| 692 | |
| 693 // Separate to argv[] convention | |
| 694 | |
| 695 argv[0] = NULL; | |
| 696 for (pt = strtok(CommandLine, " "); | |
| 697 pt; | |
| 698 pt = strtok(NULL, " ")) { | |
| 699 | |
| 700 argv[argc++] = pt; | |
| 701 } | |
| 702 | |
| 703 | |
| 704 | |
| 705 // Parse arguments | |
| 706 HandleSwitches(argc, argv); | |
| 707 | |
| 708 | |
| 709 nBytesDepth = SizeOfArrayType(prhs[0]); | |
| 710 | |
| 711 OpenTransforms(argc, argv); | |
| 712 | |
| 713 | |
| 714 plhs[0] = AllocateOutputArray(prhs[0], OutputChannels); | |
| 715 | |
| 716 | |
| 717 ApplyTransforms(prhs[0], plhs[0]); | |
| 718 | |
| 719 CloseTransforms(); | |
| 720 | |
| 721 // Done! | |
| 722 } | |
| 723 | |
| 724 |
