1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 // This file is available under and governed by the GNU General Public 26 // License version 2 only, as published by the Free Software Foundation. 27 // However, the following notice accompanied the original version of this 28 // file: 29 // 30 //--------------------------------------------------------------------------------- 31 // 32 // Little Color Management System 33 // Copyright (c) 1998-2017 Marti Maria Saguer 34 // 35 // Permission is hereby granted, free of charge, to any person obtaining 36 // a copy of this software and associated documentation files (the "Software"), 37 // to deal in the Software without restriction, including without limitation 38 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 39 // and/or sell copies of the Software, and to permit persons to whom the Software 40 // is furnished to do so, subject to the following conditions: 41 // 42 // The above copyright notice and this permission notice shall be included in 43 // all copies or substantial portions of the Software. 44 // 45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 52 // 53 //--------------------------------------------------------------------------------- 54 // 55 56 #include "lcms2_internal.h" 57 58 59 // Allocates an empty multi profile element 60 cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, 61 cmsStageSignature Type, 62 cmsUInt32Number InputChannels, 63 cmsUInt32Number OutputChannels, 64 _cmsStageEvalFn EvalPtr, 65 _cmsStageDupElemFn DupElemPtr, 66 _cmsStageFreeElemFn FreePtr, 67 void* Data) 68 { 69 cmsStage* ph = (cmsStage*) _cmsMallocZero(ContextID, sizeof(cmsStage)); 70 71 if (ph == NULL) return NULL; 72 73 74 ph ->ContextID = ContextID; 75 76 ph ->Type = Type; 77 ph ->Implements = Type; // By default, no clue on what is implementing 78 79 ph ->InputChannels = InputChannels; 80 ph ->OutputChannels = OutputChannels; 81 ph ->EvalPtr = EvalPtr; 82 ph ->DupElemPtr = DupElemPtr; 83 ph ->FreePtr = FreePtr; 84 ph ->Data = Data; 85 86 return ph; 87 } 88 89 90 static 91 void EvaluateIdentity(const cmsFloat32Number In[], 92 cmsFloat32Number Out[], 93 const cmsStage *mpe) 94 { 95 memmove(Out, In, mpe ->InputChannels * sizeof(cmsFloat32Number)); 96 } 97 98 99 cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels) 100 { 101 return _cmsStageAllocPlaceholder(ContextID, 102 cmsSigIdentityElemType, 103 nChannels, nChannels, 104 EvaluateIdentity, 105 NULL, 106 NULL, 107 NULL); 108 } 109 110 // Conversion functions. From floating point to 16 bits 111 static 112 void FromFloatTo16(const cmsFloat32Number In[], cmsUInt16Number Out[], cmsUInt32Number n) 113 { 114 cmsUInt32Number i; 115 116 for (i=0; i < n; i++) { 117 Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0); 118 } 119 } 120 121 // From 16 bits to floating point 122 static 123 void From16ToFloat(const cmsUInt16Number In[], cmsFloat32Number Out[], cmsUInt32Number n) 124 { 125 cmsUInt32Number i; 126 127 for (i=0; i < n; i++) { 128 Out[i] = (cmsFloat32Number) In[i] / 65535.0F; 129 } 130 } 131 132 133 // This function is quite useful to analyze the structure of a LUT and retrieve the MPE elements 134 // that conform the LUT. It should be called with the LUT, the number of expected elements and 135 // then a list of expected types followed with a list of cmsFloat64Number pointers to MPE elements. If 136 // the function founds a match with current pipeline, it fills the pointers and returns TRUE 137 // if not, returns FALSE without touching anything. Setting pointers to NULL does bypass 138 // the storage process. 139 cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...) 140 { 141 va_list args; 142 cmsUInt32Number i; 143 cmsStage* mpe; 144 cmsStageSignature Type; 145 void** ElemPtr; 146 147 // Make sure same number of elements 148 if (cmsPipelineStageCount(Lut) != n) return FALSE; 149 150 va_start(args, n); 151 152 // Iterate across asked types 153 mpe = Lut ->Elements; 154 for (i=0; i < n; i++) { 155 156 // Get asked type. cmsStageSignature is promoted to int by compiler 157 Type = (cmsStageSignature)va_arg(args, int); 158 if (mpe ->Type != Type) { 159 160 va_end(args); // Mismatch. We are done. 161 return FALSE; 162 } 163 mpe = mpe ->Next; 164 } 165 166 // Found a combination, fill pointers if not NULL 167 mpe = Lut ->Elements; 168 for (i=0; i < n; i++) { 169 170 ElemPtr = va_arg(args, void**); 171 if (ElemPtr != NULL) 172 *ElemPtr = mpe; 173 174 mpe = mpe ->Next; 175 } 176 177 va_end(args); 178 return TRUE; 179 } 180 181 // Below there are implementations for several types of elements. Each type may be implemented by a 182 // evaluation function, a duplication function, a function to free resources and a constructor. 183 184 // ************************************************************************************************* 185 // Type cmsSigCurveSetElemType (curves) 186 // ************************************************************************************************* 187 188 cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe) 189 { 190 _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; 191 192 return Data ->TheCurves; 193 } 194 195 static 196 void EvaluateCurves(const cmsFloat32Number In[], 197 cmsFloat32Number Out[], 198 const cmsStage *mpe) 199 { 200 _cmsStageToneCurvesData* Data; 201 cmsUInt32Number i; 202 203 _cmsAssert(mpe != NULL); 204 205 Data = (_cmsStageToneCurvesData*) mpe ->Data; 206 if (Data == NULL) return; 207 208 if (Data ->TheCurves == NULL) return; 209 210 for (i=0; i < Data ->nCurves; i++) { 211 Out[i] = cmsEvalToneCurveFloat(Data ->TheCurves[i], In[i]); 212 } 213 } 214 215 static 216 void CurveSetElemTypeFree(cmsStage* mpe) 217 { 218 _cmsStageToneCurvesData* Data; 219 cmsUInt32Number i; 220 221 _cmsAssert(mpe != NULL); 222 223 Data = (_cmsStageToneCurvesData*) mpe ->Data; 224 if (Data == NULL) return; 225 226 if (Data ->TheCurves != NULL) { 227 for (i=0; i < Data ->nCurves; i++) { 228 if (Data ->TheCurves[i] != NULL) 229 cmsFreeToneCurve(Data ->TheCurves[i]); 230 } 231 } 232 _cmsFree(mpe ->ContextID, Data ->TheCurves); 233 _cmsFree(mpe ->ContextID, Data); 234 } 235 236 237 static 238 void* CurveSetDup(cmsStage* mpe) 239 { 240 _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; 241 _cmsStageToneCurvesData* NewElem; 242 cmsUInt32Number i; 243 244 NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageToneCurvesData)); 245 if (NewElem == NULL) return NULL; 246 247 NewElem ->nCurves = Data ->nCurves; 248 NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(mpe ->ContextID, NewElem ->nCurves, sizeof(cmsToneCurve*)); 249 250 if (NewElem ->TheCurves == NULL) goto Error; 251 252 for (i=0; i < NewElem ->nCurves; i++) { 253 254 // Duplicate each curve. It may fail. 255 NewElem ->TheCurves[i] = cmsDupToneCurve(Data ->TheCurves[i]); 256 if (NewElem ->TheCurves[i] == NULL) goto Error; 257 258 259 } 260 return (void*) NewElem; 261 262 Error: 263 264 if (NewElem ->TheCurves != NULL) { 265 for (i=0; i < NewElem ->nCurves; i++) { 266 if (NewElem ->TheCurves[i]) 267 cmsFreeToneCurve(NewElem ->TheCurves[i]); 268 } 269 } 270 _cmsFree(mpe ->ContextID, NewElem ->TheCurves); 271 _cmsFree(mpe ->ContextID, NewElem); 272 return NULL; 273 } 274 275 276 // Curves == NULL forces identity curves 277 cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Number nChannels, cmsToneCurve* const Curves[]) 278 { 279 cmsUInt32Number i; 280 _cmsStageToneCurvesData* NewElem; 281 cmsStage* NewMPE; 282 283 284 NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCurveSetElemType, nChannels, nChannels, 285 EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL ); 286 if (NewMPE == NULL) return NULL; 287 288 NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(ContextID, sizeof(_cmsStageToneCurvesData)); 289 if (NewElem == NULL) { 290 cmsStageFree(NewMPE); 291 return NULL; 292 } 293 294 NewMPE ->Data = (void*) NewElem; 295 296 NewElem ->nCurves = nChannels; 297 NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*)); 298 if (NewElem ->TheCurves == NULL) { 299 cmsStageFree(NewMPE); 300 return NULL; 301 } 302 303 for (i=0; i < nChannels; i++) { 304 305 if (Curves == NULL) { 306 NewElem ->TheCurves[i] = cmsBuildGamma(ContextID, 1.0); 307 } 308 else { 309 NewElem ->TheCurves[i] = cmsDupToneCurve(Curves[i]); 310 } 311 312 if (NewElem ->TheCurves[i] == NULL) { 313 cmsStageFree(NewMPE); 314 return NULL; 315 } 316 317 } 318 319 return NewMPE; 320 } 321 322 323 // Create a bunch of identity curves 324 cmsStage* CMSEXPORT _cmsStageAllocIdentityCurves(cmsContext ContextID, cmsUInt32Number nChannels) 325 { 326 cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL); 327 328 if (mpe == NULL) return NULL; 329 mpe ->Implements = cmsSigIdentityElemType; 330 return mpe; 331 } 332 333 334 // ************************************************************************************************* 335 // Type cmsSigMatrixElemType (Matrices) 336 // ************************************************************************************************* 337 338 339 // Special care should be taken here because precision loss. A temporary cmsFloat64Number buffer is being used 340 static 341 void EvaluateMatrix(const cmsFloat32Number In[], 342 cmsFloat32Number Out[], 343 const cmsStage *mpe) 344 { 345 cmsUInt32Number i, j; 346 _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; 347 cmsFloat64Number Tmp; 348 349 // Input is already in 0..1.0 notation 350 for (i=0; i < mpe ->OutputChannels; i++) { 351 352 Tmp = 0; 353 for (j=0; j < mpe->InputChannels; j++) { 354 Tmp += In[j] * Data->Double[i*mpe->InputChannels + j]; 355 } 356 357 if (Data ->Offset != NULL) 358 Tmp += Data->Offset[i]; 359 360 Out[i] = (cmsFloat32Number) Tmp; 361 } 362 363 364 // Output in 0..1.0 domain 365 } 366 367 368 // Duplicate a yet-existing matrix element 369 static 370 void* MatrixElemDup(cmsStage* mpe) 371 { 372 _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; 373 _cmsStageMatrixData* NewElem; 374 cmsUInt32Number sz; 375 376 NewElem = (_cmsStageMatrixData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageMatrixData)); 377 if (NewElem == NULL) return NULL; 378 379 sz = mpe ->InputChannels * mpe ->OutputChannels; 380 381 NewElem ->Double = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Double, sz * sizeof(cmsFloat64Number)) ; 382 383 if (Data ->Offset) 384 NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, 385 Data ->Offset, mpe -> OutputChannels * sizeof(cmsFloat64Number)) ; 386 387 return (void*) NewElem; 388 } 389 390 391 static 392 void MatrixElemTypeFree(cmsStage* mpe) 393 { 394 _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; 395 if (Data == NULL) 396 return; 397 if (Data ->Double) 398 _cmsFree(mpe ->ContextID, Data ->Double); 399 400 if (Data ->Offset) 401 _cmsFree(mpe ->ContextID, Data ->Offset); 402 403 _cmsFree(mpe ->ContextID, mpe ->Data); 404 } 405 406 407 408 cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, 409 const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset) 410 { 411 cmsUInt32Number i, n; 412 _cmsStageMatrixData* NewElem; 413 cmsStage* NewMPE; 414 415 n = Rows * Cols; 416 417 // Check for overflow 418 if (n == 0) return NULL; 419 if (n >= UINT_MAX / Cols) return NULL; 420 if (n >= UINT_MAX / Rows) return NULL; 421 if (n < Rows || n < Cols) return NULL; 422 423 NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigMatrixElemType, Cols, Rows, 424 EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL ); 425 if (NewMPE == NULL) return NULL; 426 427 428 NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData)); 429 if (NewElem == NULL) return NULL; 430 431 432 NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number)); 433 434 if (NewElem->Double == NULL) { 435 MatrixElemTypeFree(NewMPE); 436 return NULL; 437 } 438 439 for (i=0; i < n; i++) { 440 NewElem ->Double[i] = Matrix[i]; 441 } 442 443 444 if (Offset != NULL) { 445 446 NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Rows, sizeof(cmsFloat64Number)); 447 if (NewElem->Offset == NULL) { 448 MatrixElemTypeFree(NewMPE); 449 return NULL; 450 } 451 452 for (i=0; i < Rows; i++) { 453 NewElem ->Offset[i] = Offset[i]; 454 } 455 456 } 457 458 NewMPE ->Data = (void*) NewElem; 459 return NewMPE; 460 } 461 462 463 // ************************************************************************************************* 464 // Type cmsSigCLutElemType 465 // ************************************************************************************************* 466 467 468 // Evaluate in true floating point 469 static 470 void EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 471 { 472 _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 473 474 Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params); 475 } 476 477 478 // Convert to 16 bits, evaluate, and back to floating point 479 static 480 void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 481 { 482 _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 483 cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS]; 484 485 _cmsAssert(mpe ->InputChannels <= MAX_STAGE_CHANNELS); 486 _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS); 487 488 FromFloatTo16(In, In16, mpe ->InputChannels); 489 Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params); 490 From16ToFloat(Out16, Out, mpe ->OutputChannels); 491 } 492 493 494 // Given an hypercube of b dimensions, with Dims[] number of nodes by dimension, calculate the total amount of nodes 495 static 496 cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) 497 { 498 cmsUInt32Number rv, dim; 499 500 _cmsAssert(Dims != NULL); 501 502 for (rv = 1; b > 0; b--) { 503 504 dim = Dims[b-1]; 505 if (dim == 0) return 0; // Error 506 507 rv *= dim; 508 509 // Check for overflow 510 if (rv > UINT_MAX / dim) return 0; 511 } 512 513 return rv; 514 } 515 516 static 517 void* CLUTElemDup(cmsStage* mpe) 518 { 519 _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 520 _cmsStageCLutData* NewElem; 521 522 523 NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData)); 524 if (NewElem == NULL) return NULL; 525 526 NewElem ->nEntries = Data ->nEntries; 527 NewElem ->HasFloatValues = Data ->HasFloatValues; 528 529 if (Data ->Tab.T) { 530 531 if (Data ->HasFloatValues) { 532 NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); 533 if (NewElem ->Tab.TFloat == NULL) 534 goto Error; 535 } else { 536 NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); 537 if (NewElem ->Tab.T == NULL) 538 goto Error; 539 } 540 } 541 542 NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, 543 Data ->Params ->nSamples, 544 Data ->Params ->nInputs, 545 Data ->Params ->nOutputs, 546 NewElem ->Tab.T, 547 Data ->Params ->dwFlags); 548 if (NewElem->Params != NULL) 549 return (void*) NewElem; 550 Error: 551 if (NewElem->Tab.T) 552 // This works for both types 553 _cmsFree(mpe ->ContextID, NewElem -> Tab.T); 554 _cmsFree(mpe ->ContextID, NewElem); 555 return NULL; 556 } 557 558 559 static 560 void CLutElemTypeFree(cmsStage* mpe) 561 { 562 563 _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 564 565 // Already empty 566 if (Data == NULL) return; 567 568 // This works for both types 569 if (Data -> Tab.T) 570 _cmsFree(mpe ->ContextID, Data -> Tab.T); 571 572 _cmsFreeInterpParams(Data ->Params); 573 _cmsFree(mpe ->ContextID, mpe ->Data); 574 } 575 576 577 // Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different 578 // granularity on each dimension. 579 cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, 580 const cmsUInt32Number clutPoints[], 581 cmsUInt32Number inputChan, 582 cmsUInt32Number outputChan, 583 const cmsUInt16Number* Table) 584 { 585 cmsUInt32Number i, n; 586 _cmsStageCLutData* NewElem; 587 cmsStage* NewMPE; 588 589 _cmsAssert(clutPoints != NULL); 590 591 if (inputChan > MAX_INPUT_DIMENSIONS) { 592 cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); 593 return NULL; 594 } 595 596 NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, 597 EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL ); 598 599 if (NewMPE == NULL) return NULL; 600 601 NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); 602 if (NewElem == NULL) { 603 cmsStageFree(NewMPE); 604 return NULL; 605 } 606 607 NewMPE ->Data = (void*) NewElem; 608 609 NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); 610 NewElem -> HasFloatValues = FALSE; 611 612 if (n == 0) { 613 cmsStageFree(NewMPE); 614 return NULL; 615 } 616 617 618 NewElem ->Tab.T = (cmsUInt16Number*) _cmsCalloc(ContextID, n, sizeof(cmsUInt16Number)); 619 if (NewElem ->Tab.T == NULL) { 620 cmsStageFree(NewMPE); 621 return NULL; 622 } 623 624 if (Table != NULL) { 625 for (i=0; i < n; i++) { 626 NewElem ->Tab.T[i] = Table[i]; 627 } 628 } 629 630 NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.T, CMS_LERP_FLAGS_16BITS); 631 if (NewElem ->Params == NULL) { 632 cmsStageFree(NewMPE); 633 return NULL; 634 } 635 636 return NewMPE; 637 } 638 639 cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, 640 cmsUInt32Number nGridPoints, 641 cmsUInt32Number inputChan, 642 cmsUInt32Number outputChan, 643 const cmsUInt16Number* Table) 644 { 645 cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 646 int i; 647 648 // Our resulting LUT would be same gridpoints on all dimensions 649 for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 650 Dimensions[i] = nGridPoints; 651 652 return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); 653 } 654 655 656 cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, 657 cmsUInt32Number nGridPoints, 658 cmsUInt32Number inputChan, 659 cmsUInt32Number outputChan, 660 const cmsFloat32Number* Table) 661 { 662 cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 663 int i; 664 665 // Our resulting LUT would be same gridpoints on all dimensions 666 for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 667 Dimensions[i] = nGridPoints; 668 669 return cmsStageAllocCLutFloatGranular(ContextID, Dimensions, inputChan, outputChan, Table); 670 } 671 672 673 674 cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table) 675 { 676 cmsUInt32Number i, n; 677 _cmsStageCLutData* NewElem; 678 cmsStage* NewMPE; 679 680 _cmsAssert(clutPoints != NULL); 681 682 if (inputChan > MAX_INPUT_DIMENSIONS) { 683 cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); 684 return NULL; 685 } 686 687 NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, 688 EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL); 689 if (NewMPE == NULL) return NULL; 690 691 692 NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); 693 if (NewElem == NULL) { 694 cmsStageFree(NewMPE); 695 return NULL; 696 } 697 698 NewMPE ->Data = (void*) NewElem; 699 700 // There is a potential integer overflow on conputing n and nEntries. 701 NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); 702 NewElem -> HasFloatValues = TRUE; 703 704 if (n == 0) { 705 cmsStageFree(NewMPE); 706 return NULL; 707 } 708 709 NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat32Number)); 710 if (NewElem ->Tab.TFloat == NULL) { 711 cmsStageFree(NewMPE); 712 return NULL; 713 } 714 715 if (Table != NULL) { 716 for (i=0; i < n; i++) { 717 NewElem ->Tab.TFloat[i] = Table[i]; 718 } 719 } 720 721 NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); 722 if (NewElem ->Params == NULL) { 723 cmsStageFree(NewMPE); 724 return NULL; 725 } 726 727 return NewMPE; 728 } 729 730 731 static 732 int IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) 733 { 734 int nChan = *(int*) Cargo; 735 int i; 736 737 for (i=0; i < nChan; i++) 738 Out[i] = In[i]; 739 740 return 1; 741 } 742 743 // Creates an MPE that just copies input to output 744 cmsStage* CMSEXPORT _cmsStageAllocIdentityCLut(cmsContext ContextID, cmsUInt32Number nChan) 745 { 746 cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 747 cmsStage* mpe ; 748 int i; 749 750 for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 751 Dimensions[i] = 2; 752 753 mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL); 754 if (mpe == NULL) return NULL; 755 756 if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) { 757 cmsStageFree(mpe); 758 return NULL; 759 } 760 761 mpe ->Implements = cmsSigIdentityElemType; 762 return mpe; 763 } 764 765 766 767 // Quantize a value 0 <= i < MaxSamples to 0..0xffff 768 cmsUInt16Number CMSEXPORT _cmsQuantizeVal(cmsFloat64Number i, cmsUInt32Number MaxSamples) 769 { 770 cmsFloat64Number x; 771 772 x = ((cmsFloat64Number) i * 65535.) / (cmsFloat64Number) (MaxSamples - 1); 773 return _cmsQuickSaturateWord(x); 774 } 775 776 777 // This routine does a sweep on whole input space, and calls its callback 778 // function on knots. returns TRUE if all ok, FALSE otherwise. 779 cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags) 780 { 781 int i, t, index, rest; 782 cmsUInt32Number nTotalPoints; 783 cmsUInt32Number nInputs, nOutputs; 784 cmsUInt32Number* nSamples; 785 cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; 786 _cmsStageCLutData* clut; 787 788 if (mpe == NULL) return FALSE; 789 790 clut = (_cmsStageCLutData*) mpe->Data; 791 792 if (clut == NULL) return FALSE; 793 794 nSamples = clut->Params ->nSamples; 795 nInputs = clut->Params ->nInputs; 796 nOutputs = clut->Params ->nOutputs; 797 798 if (nInputs <= 0) return FALSE; 799 if (nOutputs <= 0) return FALSE; 800 if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; 801 if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; 802 803 memset(In, 0, sizeof(In)); 804 memset(Out, 0, sizeof(Out)); 805 806 nTotalPoints = CubeSize(nSamples, nInputs); 807 if (nTotalPoints == 0) return FALSE; 808 809 index = 0; 810 for (i = 0; i < (int) nTotalPoints; i++) { 811 812 rest = i; 813 for (t = (int)nInputs - 1; t >= 0; --t) { 814 815 cmsUInt32Number Colorant = rest % nSamples[t]; 816 817 rest /= nSamples[t]; 818 819 In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); 820 } 821 822 if (clut ->Tab.T != NULL) { 823 for (t = 0; t < (int)nOutputs; t++) 824 Out[t] = clut->Tab.T[index + t]; 825 } 826 827 if (!Sampler(In, Out, Cargo)) 828 return FALSE; 829 830 if (!(dwFlags & SAMPLER_INSPECT)) { 831 832 if (clut ->Tab.T != NULL) { 833 for (t=0; t < (int) nOutputs; t++) 834 clut->Tab.T[index + t] = Out[t]; 835 } 836 } 837 838 index += nOutputs; 839 } 840 841 return TRUE; 842 } 843 844 // Same as anterior, but for floating point 845 cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void * Cargo, cmsUInt32Number dwFlags) 846 { 847 int i, t, index, rest; 848 cmsUInt32Number nTotalPoints; 849 cmsUInt32Number nInputs, nOutputs; 850 cmsUInt32Number* nSamples; 851 cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; 852 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; 853 854 nSamples = clut->Params ->nSamples; 855 nInputs = clut->Params ->nInputs; 856 nOutputs = clut->Params ->nOutputs; 857 858 if (nInputs <= 0) return FALSE; 859 if (nOutputs <= 0) return FALSE; 860 if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; 861 if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; 862 863 nTotalPoints = CubeSize(nSamples, nInputs); 864 if (nTotalPoints == 0) return FALSE; 865 866 index = 0; 867 for (i = 0; i < (int)nTotalPoints; i++) { 868 869 rest = i; 870 for (t = (int) nInputs-1; t >=0; --t) { 871 872 cmsUInt32Number Colorant = rest % nSamples[t]; 873 874 rest /= nSamples[t]; 875 876 In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); 877 } 878 879 if (clut ->Tab.TFloat != NULL) { 880 for (t=0; t < (int) nOutputs; t++) 881 Out[t] = clut->Tab.TFloat[index + t]; 882 } 883 884 if (!Sampler(In, Out, Cargo)) 885 return FALSE; 886 887 if (!(dwFlags & SAMPLER_INSPECT)) { 888 889 if (clut ->Tab.TFloat != NULL) { 890 for (t=0; t < (int) nOutputs; t++) 891 clut->Tab.TFloat[index + t] = Out[t]; 892 } 893 } 894 895 index += nOutputs; 896 } 897 898 return TRUE; 899 } 900 901 902 903 // This routine does a sweep on whole input space, and calls its callback 904 // function on knots. returns TRUE if all ok, FALSE otherwise. 905 cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], 906 cmsSAMPLER16 Sampler, void * Cargo) 907 { 908 int i, t, rest; 909 cmsUInt32Number nTotalPoints; 910 cmsUInt16Number In[cmsMAXCHANNELS]; 911 912 if (nInputs >= cmsMAXCHANNELS) return FALSE; 913 914 nTotalPoints = CubeSize(clutPoints, nInputs); 915 if (nTotalPoints == 0) return FALSE; 916 917 for (i = 0; i < (int) nTotalPoints; i++) { 918 919 rest = i; 920 for (t = (int) nInputs-1; t >=0; --t) { 921 922 cmsUInt32Number Colorant = rest % clutPoints[t]; 923 924 rest /= clutPoints[t]; 925 In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); 926 927 } 928 929 if (!Sampler(In, NULL, Cargo)) 930 return FALSE; 931 } 932 933 return TRUE; 934 } 935 936 cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], 937 cmsSAMPLERFLOAT Sampler, void * Cargo) 938 { 939 int i, t, rest; 940 cmsUInt32Number nTotalPoints; 941 cmsFloat32Number In[cmsMAXCHANNELS]; 942 943 if (nInputs >= cmsMAXCHANNELS) return FALSE; 944 945 nTotalPoints = CubeSize(clutPoints, nInputs); 946 if (nTotalPoints == 0) return FALSE; 947 948 for (i = 0; i < (int) nTotalPoints; i++) { 949 950 rest = i; 951 for (t = (int) nInputs-1; t >=0; --t) { 952 953 cmsUInt32Number Colorant = rest % clutPoints[t]; 954 955 rest /= clutPoints[t]; 956 In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); 957 958 } 959 960 if (!Sampler(In, NULL, Cargo)) 961 return FALSE; 962 } 963 964 return TRUE; 965 } 966 967 // ******************************************************************************** 968 // Type cmsSigLab2XYZElemType 969 // ******************************************************************************** 970 971 972 static 973 void EvaluateLab2XYZ(const cmsFloat32Number In[], 974 cmsFloat32Number Out[], 975 const cmsStage *mpe) 976 { 977 cmsCIELab Lab; 978 cmsCIEXYZ XYZ; 979 const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; 980 981 // V4 rules 982 Lab.L = In[0] * 100.0; 983 Lab.a = In[1] * 255.0 - 128.0; 984 Lab.b = In[2] * 255.0 - 128.0; 985 986 cmsLab2XYZ(NULL, &XYZ, &Lab); 987 988 // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff 989 // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0) 990 991 Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); 992 Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); 993 Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); 994 return; 995 996 cmsUNUSED_PARAMETER(mpe); 997 } 998 999 1000 // No dup or free routines needed, as the structure has no pointers in it. 1001 cmsStage* CMSEXPORT _cmsStageAllocLab2XYZ(cmsContext ContextID) 1002 { 1003 return _cmsStageAllocPlaceholder(ContextID, cmsSigLab2XYZElemType, 3, 3, EvaluateLab2XYZ, NULL, NULL, NULL); 1004 } 1005 1006 // ******************************************************************************** 1007 1008 // v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable 1009 // number of gridpoints that would make exact match. However, a prelinearization 1010 // of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. 1011 // Almost all what we need but unfortunately, the rest of entries should be scaled by 1012 // (255*257/256) and this is not exact. 1013 1014 cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) 1015 { 1016 cmsStage* mpe; 1017 cmsToneCurve* LabTable[3]; 1018 int i, j; 1019 1020 LabTable[0] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); 1021 LabTable[1] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); 1022 LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); 1023 1024 for (j=0; j < 3; j++) { 1025 1026 if (LabTable[j] == NULL) { 1027 cmsFreeToneCurveTriple(LabTable); 1028 return NULL; 1029 } 1030 1031 // We need to map * (0xffff / 0xff00), that's same as (257 / 256) 1032 // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256); 1033 for (i=0; i < 257; i++) { 1034 1035 LabTable[j]->Table16[i] = (cmsUInt16Number) ((i * 0xffff + 0x80) >> 8); 1036 } 1037 1038 LabTable[j] ->Table16[257] = 0xffff; 1039 } 1040 1041 mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); 1042 cmsFreeToneCurveTriple(LabTable); 1043 1044 if (mpe == NULL) return NULL; 1045 mpe ->Implements = cmsSigLabV2toV4; 1046 return mpe; 1047 } 1048 1049 // ******************************************************************************** 1050 1051 // Matrix-based conversion, which is more accurate, but slower and cannot properly be saved in devicelink profiles 1052 cmsStage* CMSEXPORT _cmsStageAllocLabV2ToV4(cmsContext ContextID) 1053 { 1054 static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0, 1055 0, 65535.0/65280.0, 0, 1056 0, 0, 65535.0/65280.0 1057 }; 1058 1059 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL); 1060 1061 if (mpe == NULL) return mpe; 1062 mpe ->Implements = cmsSigLabV2toV4; 1063 return mpe; 1064 } 1065 1066 1067 // Reverse direction 1068 cmsStage* CMSEXPORT _cmsStageAllocLabV4ToV2(cmsContext ContextID) 1069 { 1070 static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0, 1071 0, 65280.0/65535.0, 0, 1072 0, 0, 65280.0/65535.0 1073 }; 1074 1075 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL); 1076 1077 if (mpe == NULL) return mpe; 1078 mpe ->Implements = cmsSigLabV4toV2; 1079 return mpe; 1080 } 1081 1082 1083 // To Lab to float. Note that the MPE gives numbers in normal Lab range 1084 // and we need 0..1.0 range for the formatters 1085 // L* : 0...100 => 0...1.0 (L* / 100) 1086 // ab* : -128..+127 to 0..1 ((ab* + 128) / 255) 1087 1088 cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID) 1089 { 1090 static const cmsFloat64Number a1[] = { 1091 1.0/100.0, 0, 0, 1092 0, 1.0/255.0, 0, 1093 0, 0, 1.0/255.0 1094 }; 1095 1096 static const cmsFloat64Number o1[] = { 1097 0, 1098 128.0/255.0, 1099 128.0/255.0 1100 }; 1101 1102 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); 1103 1104 if (mpe == NULL) return mpe; 1105 mpe ->Implements = cmsSigLab2FloatPCS; 1106 return mpe; 1107 } 1108 1109 // Fom XYZ to floating point PCS 1110 cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID) 1111 { 1112 #define n (32768.0/65535.0) 1113 static const cmsFloat64Number a1[] = { 1114 n, 0, 0, 1115 0, n, 0, 1116 0, 0, n 1117 }; 1118 #undef n 1119 1120 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); 1121 1122 if (mpe == NULL) return mpe; 1123 mpe ->Implements = cmsSigXYZ2FloatPCS; 1124 return mpe; 1125 } 1126 1127 cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID) 1128 { 1129 static const cmsFloat64Number a1[] = { 1130 100.0, 0, 0, 1131 0, 255.0, 0, 1132 0, 0, 255.0 1133 }; 1134 1135 static const cmsFloat64Number o1[] = { 1136 0, 1137 -128.0, 1138 -128.0 1139 }; 1140 1141 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); 1142 if (mpe == NULL) return mpe; 1143 mpe ->Implements = cmsSigFloatPCS2Lab; 1144 return mpe; 1145 } 1146 1147 cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID) 1148 { 1149 #define n (65535.0/32768.0) 1150 1151 static const cmsFloat64Number a1[] = { 1152 n, 0, 0, 1153 0, n, 0, 1154 0, 0, n 1155 }; 1156 #undef n 1157 1158 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); 1159 if (mpe == NULL) return mpe; 1160 mpe ->Implements = cmsSigFloatPCS2XYZ; 1161 return mpe; 1162 } 1163 1164 // Clips values smaller than zero 1165 static 1166 void Clipper(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 1167 { 1168 cmsUInt32Number i; 1169 for (i = 0; i < mpe->InputChannels; i++) { 1170 1171 cmsFloat32Number n = In[i]; 1172 Out[i] = n < 0 ? 0 : n; 1173 } 1174 } 1175 1176 cmsStage* _cmsStageClipNegatives(cmsContext ContextID, cmsUInt32Number nChannels) 1177 { 1178 return _cmsStageAllocPlaceholder(ContextID, cmsSigClipNegativesElemType, 1179 nChannels, nChannels, Clipper, NULL, NULL, NULL); 1180 } 1181 1182 // ******************************************************************************** 1183 // Type cmsSigXYZ2LabElemType 1184 // ******************************************************************************** 1185 1186 static 1187 void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 1188 { 1189 cmsCIELab Lab; 1190 cmsCIEXYZ XYZ; 1191 const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; 1192 1193 // From 0..1.0 to XYZ 1194 1195 XYZ.X = In[0] * XYZadj; 1196 XYZ.Y = In[1] * XYZadj; 1197 XYZ.Z = In[2] * XYZadj; 1198 1199 cmsXYZ2Lab(NULL, &Lab, &XYZ); 1200 1201 // From V4 Lab to 0..1.0 1202 1203 Out[0] = (cmsFloat32Number) (Lab.L / 100.0); 1204 Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); 1205 Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0); 1206 return; 1207 1208 cmsUNUSED_PARAMETER(mpe); 1209 } 1210 1211 cmsStage* CMSEXPORT _cmsStageAllocXYZ2Lab(cmsContext ContextID) 1212 { 1213 return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL); 1214 1215 } 1216 1217 // ******************************************************************************** 1218 1219 // For v4, S-Shaped curves are placed in a/b axis to increase resolution near gray 1220 1221 cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID) 1222 { 1223 cmsToneCurve* LabTable[3]; 1224 cmsFloat64Number Params[1] = {2.4} ; 1225 1226 LabTable[0] = cmsBuildGamma(ContextID, 1.0); 1227 LabTable[1] = cmsBuildParametricToneCurve(ContextID, 108, Params); 1228 LabTable[2] = cmsBuildParametricToneCurve(ContextID, 108, Params); 1229 1230 return cmsStageAllocToneCurves(ContextID, 3, LabTable); 1231 } 1232 1233 1234 // Free a single MPE 1235 void CMSEXPORT cmsStageFree(cmsStage* mpe) 1236 { 1237 if (mpe ->FreePtr) 1238 mpe ->FreePtr(mpe); 1239 1240 _cmsFree(mpe ->ContextID, mpe); 1241 } 1242 1243 1244 cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe) 1245 { 1246 return mpe ->InputChannels; 1247 } 1248 1249 cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe) 1250 { 1251 return mpe ->OutputChannels; 1252 } 1253 1254 cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe) 1255 { 1256 return mpe -> Type; 1257 } 1258 1259 void* CMSEXPORT cmsStageData(const cmsStage* mpe) 1260 { 1261 return mpe -> Data; 1262 } 1263 1264 cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) 1265 { 1266 return mpe -> Next; 1267 } 1268 1269 1270 // Duplicates an MPE 1271 cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) 1272 { 1273 cmsStage* NewMPE; 1274 1275 if (mpe == NULL) return NULL; 1276 NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, 1277 mpe ->Type, 1278 mpe ->InputChannels, 1279 mpe ->OutputChannels, 1280 mpe ->EvalPtr, 1281 mpe ->DupElemPtr, 1282 mpe ->FreePtr, 1283 NULL); 1284 if (NewMPE == NULL) return NULL; 1285 1286 NewMPE ->Implements = mpe ->Implements; 1287 1288 if (mpe ->DupElemPtr) { 1289 1290 NewMPE ->Data = mpe ->DupElemPtr(mpe); 1291 1292 if (NewMPE->Data == NULL) { 1293 1294 cmsStageFree(NewMPE); 1295 return NULL; 1296 } 1297 1298 } else { 1299 1300 NewMPE ->Data = NULL; 1301 } 1302 1303 return NewMPE; 1304 } 1305 1306 1307 // *********************************************************************************************************** 1308 1309 // This function sets up the channel count 1310 static 1311 cmsBool BlessLUT(cmsPipeline* lut) 1312 { 1313 // We can set the input/output channels only if we have elements. 1314 if (lut ->Elements != NULL) { 1315 1316 cmsStage* prev; 1317 cmsStage* next; 1318 cmsStage* First; 1319 cmsStage* Last; 1320 1321 First = cmsPipelineGetPtrToFirstStage(lut); 1322 Last = cmsPipelineGetPtrToLastStage(lut); 1323 1324 if (First == NULL || Last == NULL) return FALSE; 1325 1326 lut->InputChannels = First->InputChannels; 1327 lut->OutputChannels = Last->OutputChannels; 1328 1329 // Check chain consistency 1330 prev = First; 1331 next = prev->Next; 1332 1333 while (next != NULL) 1334 { 1335 if (next->InputChannels != prev->OutputChannels) 1336 return FALSE; 1337 1338 next = next->Next; 1339 prev = prev->Next; 1340 } 1341 } 1342 1343 return TRUE; 1344 } 1345 1346 1347 // Default to evaluate the LUT on 16 bit-basis. Precision is retained. 1348 static 1349 void _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* D) 1350 { 1351 cmsPipeline* lut = (cmsPipeline*) D; 1352 cmsStage *mpe; 1353 cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; 1354 int Phase = 0, NextPhase; 1355 1356 From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels); 1357 1358 for (mpe = lut ->Elements; 1359 mpe != NULL; 1360 mpe = mpe ->Next) { 1361 1362 NextPhase = Phase ^ 1; 1363 mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); 1364 Phase = NextPhase; 1365 } 1366 1367 1368 FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels); 1369 } 1370 1371 1372 1373 // Does evaluate the LUT on cmsFloat32Number-basis. 1374 static 1375 void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Number Out[], const void* D) 1376 { 1377 cmsPipeline* lut = (cmsPipeline*) D; 1378 cmsStage *mpe; 1379 cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; 1380 int Phase = 0, NextPhase; 1381 1382 memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number)); 1383 1384 for (mpe = lut ->Elements; 1385 mpe != NULL; 1386 mpe = mpe ->Next) { 1387 1388 NextPhase = Phase ^ 1; 1389 mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); 1390 Phase = NextPhase; 1391 } 1392 1393 memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number)); 1394 } 1395 1396 1397 // LUT Creation & Destruction 1398 cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels) 1399 { 1400 cmsPipeline* NewLUT; 1401 1402 // A value of zero in channels is allowed as placeholder 1403 if (InputChannels >= cmsMAXCHANNELS || 1404 OutputChannels >= cmsMAXCHANNELS) return NULL; 1405 1406 NewLUT = (cmsPipeline*) _cmsMallocZero(ContextID, sizeof(cmsPipeline)); 1407 if (NewLUT == NULL) return NULL; 1408 1409 NewLUT -> InputChannels = InputChannels; 1410 NewLUT -> OutputChannels = OutputChannels; 1411 1412 NewLUT ->Eval16Fn = _LUTeval16; 1413 NewLUT ->EvalFloatFn = _LUTevalFloat; 1414 NewLUT ->DupDataFn = NULL; 1415 NewLUT ->FreeDataFn = NULL; 1416 NewLUT ->Data = NewLUT; 1417 NewLUT ->ContextID = ContextID; 1418 1419 if (!BlessLUT(NewLUT)) 1420 { 1421 _cmsFree(ContextID, NewLUT); 1422 return NULL; 1423 } 1424 1425 return NewLUT; 1426 } 1427 1428 cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut) 1429 { 1430 _cmsAssert(lut != NULL); 1431 return lut ->ContextID; 1432 } 1433 1434 cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut) 1435 { 1436 _cmsAssert(lut != NULL); 1437 return lut ->InputChannels; 1438 } 1439 1440 cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut) 1441 { 1442 _cmsAssert(lut != NULL); 1443 return lut ->OutputChannels; 1444 } 1445 1446 // Free a profile elements LUT 1447 void CMSEXPORT cmsPipelineFree(cmsPipeline* lut) 1448 { 1449 cmsStage *mpe, *Next; 1450 1451 if (lut == NULL) return; 1452 1453 for (mpe = lut ->Elements; 1454 mpe != NULL; 1455 mpe = Next) { 1456 1457 Next = mpe ->Next; 1458 cmsStageFree(mpe); 1459 } 1460 1461 if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data); 1462 1463 _cmsFree(lut ->ContextID, lut); 1464 } 1465 1466 1467 // Default to evaluate the LUT on 16 bit-basis. 1468 void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut) 1469 { 1470 _cmsAssert(lut != NULL); 1471 lut ->Eval16Fn(In, Out, lut->Data); 1472 } 1473 1474 1475 // Does evaluate the LUT on cmsFloat32Number-basis. 1476 void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut) 1477 { 1478 _cmsAssert(lut != NULL); 1479 lut ->EvalFloatFn(In, Out, lut); 1480 } 1481 1482 1483 1484 // Duplicates a LUT 1485 cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) 1486 { 1487 cmsPipeline* NewLUT; 1488 cmsStage *NewMPE, *Anterior = NULL, *mpe; 1489 cmsBool First = TRUE; 1490 1491 if (lut == NULL) return NULL; 1492 1493 NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); 1494 if (NewLUT == NULL) return NULL; 1495 1496 for (mpe = lut ->Elements; 1497 mpe != NULL; 1498 mpe = mpe ->Next) { 1499 1500 NewMPE = cmsStageDup(mpe); 1501 1502 if (NewMPE == NULL) { 1503 cmsPipelineFree(NewLUT); 1504 return NULL; 1505 } 1506 1507 if (First) { 1508 NewLUT ->Elements = NewMPE; 1509 First = FALSE; 1510 } 1511 else { 1512 if (Anterior != NULL) 1513 Anterior ->Next = NewMPE; 1514 } 1515 1516 Anterior = NewMPE; 1517 } 1518 1519 NewLUT ->Eval16Fn = lut ->Eval16Fn; 1520 NewLUT ->EvalFloatFn = lut ->EvalFloatFn; 1521 NewLUT ->DupDataFn = lut ->DupDataFn; 1522 NewLUT ->FreeDataFn = lut ->FreeDataFn; 1523 1524 if (NewLUT ->DupDataFn != NULL) 1525 NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data); 1526 1527 1528 NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits; 1529 1530 if (!BlessLUT(NewLUT)) 1531 { 1532 _cmsFree(lut->ContextID, NewLUT); 1533 return NULL; 1534 } 1535 1536 return NewLUT; 1537 } 1538 1539 1540 int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) 1541 { 1542 cmsStage* Anterior = NULL, *pt; 1543 1544 if (lut == NULL || mpe == NULL) 1545 return FALSE; 1546 1547 switch (loc) { 1548 1549 case cmsAT_BEGIN: 1550 mpe ->Next = lut ->Elements; 1551 lut ->Elements = mpe; 1552 break; 1553 1554 case cmsAT_END: 1555 1556 if (lut ->Elements == NULL) 1557 lut ->Elements = mpe; 1558 else { 1559 1560 for (pt = lut ->Elements; 1561 pt != NULL; 1562 pt = pt -> Next) Anterior = pt; 1563 1564 Anterior ->Next = mpe; 1565 mpe ->Next = NULL; 1566 } 1567 break; 1568 default:; 1569 return FALSE; 1570 } 1571 1572 return BlessLUT(lut); 1573 } 1574 1575 // Unlink an element and return the pointer to it 1576 void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe) 1577 { 1578 cmsStage *Anterior, *pt, *Last; 1579 cmsStage *Unlinked = NULL; 1580 1581 1582 // If empty LUT, there is nothing to remove 1583 if (lut ->Elements == NULL) { 1584 if (mpe) *mpe = NULL; 1585 return; 1586 } 1587 1588 // On depending on the strategy... 1589 switch (loc) { 1590 1591 case cmsAT_BEGIN: 1592 { 1593 cmsStage* elem = lut ->Elements; 1594 1595 lut ->Elements = elem -> Next; 1596 elem ->Next = NULL; 1597 Unlinked = elem; 1598 1599 } 1600 break; 1601 1602 case cmsAT_END: 1603 Anterior = Last = NULL; 1604 for (pt = lut ->Elements; 1605 pt != NULL; 1606 pt = pt -> Next) { 1607 Anterior = Last; 1608 Last = pt; 1609 } 1610 1611 Unlinked = Last; // Next already points to NULL 1612 1613 // Truncate the chain 1614 if (Anterior) 1615 Anterior ->Next = NULL; 1616 else 1617 lut ->Elements = NULL; 1618 break; 1619 default:; 1620 } 1621 1622 if (mpe) 1623 *mpe = Unlinked; 1624 else 1625 cmsStageFree(Unlinked); 1626 1627 // May fail, but we ignore it 1628 BlessLUT(lut); 1629 } 1630 1631 1632 // Concatenate two LUT into a new single one 1633 cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) 1634 { 1635 cmsStage* mpe; 1636 1637 // If both LUTS does not have elements, we need to inherit 1638 // the number of channels 1639 if (l1 ->Elements == NULL && l2 ->Elements == NULL) { 1640 l1 ->InputChannels = l2 ->InputChannels; 1641 l1 ->OutputChannels = l2 ->OutputChannels; 1642 } 1643 1644 // Cat second 1645 for (mpe = l2 ->Elements; 1646 mpe != NULL; 1647 mpe = mpe ->Next) { 1648 1649 // We have to dup each element 1650 if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe))) 1651 return FALSE; 1652 } 1653 1654 return BlessLUT(l1); 1655 } 1656 1657 1658 cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On) 1659 { 1660 cmsBool Anterior = lut ->SaveAs8Bits; 1661 1662 lut ->SaveAs8Bits = On; 1663 return Anterior; 1664 } 1665 1666 1667 cmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut) 1668 { 1669 return lut ->Elements; 1670 } 1671 1672 cmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut) 1673 { 1674 cmsStage *mpe, *Anterior = NULL; 1675 1676 for (mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) 1677 Anterior = mpe; 1678 1679 return Anterior; 1680 } 1681 1682 cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut) 1683 { 1684 cmsStage *mpe; 1685 cmsUInt32Number n; 1686 1687 for (n=0, mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) 1688 n++; 1689 1690 return n; 1691 } 1692 1693 // This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional 1694 // duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. 1695 void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, 1696 _cmsOPTeval16Fn Eval16, 1697 void* PrivateData, 1698 _cmsFreeUserDataFn FreePrivateDataFn, 1699 _cmsDupUserDataFn DupPrivateDataFn) 1700 { 1701 1702 Lut ->Eval16Fn = Eval16; 1703 Lut ->DupDataFn = DupPrivateDataFn; 1704 Lut ->FreeDataFn = FreePrivateDataFn; 1705 Lut ->Data = PrivateData; 1706 } 1707 1708 1709 // ----------------------------------------------------------- Reverse interpolation 1710 // Here's how it goes. The derivative Df(x) of the function f is the linear 1711 // transformation that best approximates f near the point x. It can be represented 1712 // by a matrix A whose entries are the partial derivatives of the components of f 1713 // with respect to all the coordinates. This is know as the Jacobian 1714 // 1715 // The best linear approximation to f is given by the matrix equation: 1716 // 1717 // y-y0 = A (x-x0) 1718 // 1719 // So, if x0 is a good "guess" for the zero of f, then solving for the zero of this 1720 // linear approximation will give a "better guess" for the zero of f. Thus let y=0, 1721 // and since y0=f(x0) one can solve the above equation for x. This leads to the 1722 // Newton's method formula: 1723 // 1724 // xn+1 = xn - A-1 f(xn) 1725 // 1726 // where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the 1727 // fashion described above. Iterating this will give better and better approximations 1728 // if you have a "good enough" initial guess. 1729 1730 1731 #define JACOBIAN_EPSILON 0.001f 1732 #define INVERSION_MAX_ITERATIONS 30 1733 1734 // Increment with reflexion on boundary 1735 static 1736 void IncDelta(cmsFloat32Number *Val) 1737 { 1738 if (*Val < (1.0 - JACOBIAN_EPSILON)) 1739 1740 *Val += JACOBIAN_EPSILON; 1741 1742 else 1743 *Val -= JACOBIAN_EPSILON; 1744 1745 } 1746 1747 1748 1749 // Euclidean distance between two vectors of n elements each one 1750 static 1751 cmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], int n) 1752 { 1753 cmsFloat32Number sum = 0; 1754 int i; 1755 1756 for (i=0; i < n; i++) { 1757 cmsFloat32Number dif = b[i] - a[i]; 1758 sum += dif * dif; 1759 } 1760 1761 return sqrtf(sum); 1762 } 1763 1764 1765 // Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method 1766 // 1767 // x1 <- x - [J(x)]^-1 * f(x) 1768 // 1769 // lut: The LUT on where to do the search 1770 // Target: LabK, 3 values of Lab plus destination K which is fixed 1771 // Result: The obtained CMYK 1772 // Hint: Location where begin the search 1773 1774 cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], 1775 cmsFloat32Number Result[], 1776 cmsFloat32Number Hint[], 1777 const cmsPipeline* lut) 1778 { 1779 cmsUInt32Number i, j; 1780 cmsFloat64Number error, LastError = 1E20; 1781 cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; 1782 cmsVEC3 tmp, tmp2; 1783 cmsMAT3 Jacobian; 1784 1785 // Only 3->3 and 4->3 are supported 1786 if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; 1787 if (lut ->OutputChannels != 3) return FALSE; 1788 1789 // Take the hint as starting point if specified 1790 if (Hint == NULL) { 1791 1792 // Begin at any point, we choose 1/3 of CMY axis 1793 x[0] = x[1] = x[2] = 0.3f; 1794 } 1795 else { 1796 1797 // Only copy 3 channels from hint... 1798 for (j=0; j < 3; j++) 1799 x[j] = Hint[j]; 1800 } 1801 1802 // If Lut is 4-dimensions, then grab target[3], which is fixed 1803 if (lut ->InputChannels == 4) { 1804 x[3] = Target[3]; 1805 } 1806 else x[3] = 0; // To keep lint happy 1807 1808 1809 // Iterate 1810 for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) { 1811 1812 // Get beginning fx 1813 cmsPipelineEvalFloat(x, fx, lut); 1814 1815 // Compute error 1816 error = EuclideanDistance(fx, Target, 3); 1817 1818 // If not convergent, return last safe value 1819 if (error >= LastError) 1820 break; 1821 1822 // Keep latest values 1823 LastError = error; 1824 for (j=0; j < lut ->InputChannels; j++) 1825 Result[j] = x[j]; 1826 1827 // Found an exact match? 1828 if (error <= 0) 1829 break; 1830 1831 // Obtain slope (the Jacobian) 1832 for (j = 0; j < 3; j++) { 1833 1834 xd[0] = x[0]; 1835 xd[1] = x[1]; 1836 xd[2] = x[2]; 1837 xd[3] = x[3]; // Keep fixed channel 1838 1839 IncDelta(&xd[j]); 1840 1841 cmsPipelineEvalFloat(xd, fxd, lut); 1842 1843 Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON); 1844 Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON); 1845 Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); 1846 } 1847 1848 // Solve system 1849 tmp2.n[0] = fx[0] - Target[0]; 1850 tmp2.n[1] = fx[1] - Target[1]; 1851 tmp2.n[2] = fx[2] - Target[2]; 1852 1853 if (!_cmsMAT3solve(&tmp, &Jacobian, &tmp2)) 1854 return FALSE; 1855 1856 // Move our guess 1857 x[0] -= (cmsFloat32Number) tmp.n[0]; 1858 x[1] -= (cmsFloat32Number) tmp.n[1]; 1859 x[2] -= (cmsFloat32Number) tmp.n[2]; 1860 1861 // Some clipping.... 1862 for (j=0; j < 3; j++) { 1863 if (x[j] < 0) x[j] = 0; 1864 else 1865 if (x[j] > 1.0) x[j] = 1.0; 1866 } 1867 } 1868 1869 return TRUE; 1870 } 1871 1872