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-2012 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 157 Type = (cmsStageSignature)va_arg(args, cmsStageSignature); 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(Data ->TheCurves[i]); 268 } 269 } 270 _cmsFree(mpe ->ContextID, Data ->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* _cmsStageAllocIdentityCurves(cmsContext ContextID, int 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 ->Double) 396 _cmsFree(mpe ->ContextID, Data ->Double); 397 398 if (Data ->Offset) 399 _cmsFree(mpe ->ContextID, Data ->Offset); 400 401 _cmsFree(mpe ->ContextID, mpe ->Data); 402 } 403 404 405 406 cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, 407 const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset) 408 { 409 cmsUInt32Number i, n; 410 _cmsStageMatrixData* NewElem; 411 cmsStage* NewMPE; 412 413 n = Rows * Cols; 414 415 // Check for overflow 416 if (n == 0) return NULL; 417 if (n >= UINT_MAX / Cols) return NULL; 418 if (n >= UINT_MAX / Rows) return NULL; 419 if (n < Rows || n < Cols) return NULL; 420 421 NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigMatrixElemType, Cols, Rows, 422 EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL ); 423 if (NewMPE == NULL) return NULL; 424 425 426 NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData)); 427 if (NewElem == NULL) return NULL; 428 429 430 NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number)); 431 432 if (NewElem->Double == NULL) { 433 MatrixElemTypeFree(NewMPE); 434 return NULL; 435 } 436 437 for (i=0; i < n; i++) { 438 NewElem ->Double[i] = Matrix[i]; 439 } 440 441 442 if (Offset != NULL) { 443 444 NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number)); 445 if (NewElem->Offset == NULL) { 446 MatrixElemTypeFree(NewMPE); 447 return NULL; 448 } 449 450 for (i=0; i < Cols; i++) { 451 NewElem ->Offset[i] = Offset[i]; 452 } 453 454 } 455 456 NewMPE ->Data = (void*) NewElem; 457 return NewMPE; 458 } 459 460 461 // ************************************************************************************************* 462 // Type cmsSigCLutElemType 463 // ************************************************************************************************* 464 465 466 // Evaluate in true floating point 467 static 468 void EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 469 { 470 _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 471 472 Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params); 473 } 474 475 476 // Convert to 16 bits, evaluate, and back to floating point 477 static 478 void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 479 { 480 _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 481 cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS]; 482 483 _cmsAssert(mpe ->InputChannels <= MAX_STAGE_CHANNELS); 484 _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS); 485 486 FromFloatTo16(In, In16, mpe ->InputChannels); 487 Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params); 488 From16ToFloat(Out16, Out, mpe ->OutputChannels); 489 } 490 491 492 // Given an hypercube of b dimensions, with Dims[] number of nodes by dimension, calculate the total amount of nodes 493 static 494 cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) 495 { 496 cmsUInt32Number rv, dim; 497 498 _cmsAssert(Dims != NULL); 499 500 for (rv = 1; b > 0; b--) { 501 502 dim = Dims[b-1]; 503 if (dim == 0) return 0; // Error 504 505 rv *= dim; 506 507 // Check for overflow 508 if (rv > UINT_MAX / dim) return 0; 509 } 510 511 return rv; 512 } 513 514 static 515 void* CLUTElemDup(cmsStage* mpe) 516 { 517 _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 518 _cmsStageCLutData* NewElem; 519 520 521 NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData)); 522 if (NewElem == NULL) return NULL; 523 524 NewElem ->nEntries = Data ->nEntries; 525 NewElem ->HasFloatValues = Data ->HasFloatValues; 526 527 if (Data ->Tab.T) { 528 529 if (Data ->HasFloatValues) 530 NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); 531 else 532 NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); 533 } 534 535 NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, 536 Data ->Params ->nSamples, 537 Data ->Params ->nInputs, 538 Data ->Params ->nOutputs, 539 NewElem ->Tab.T, 540 Data ->Params ->dwFlags); 541 542 return (void*) NewElem; 543 } 544 545 546 static 547 void CLutElemTypeFree(cmsStage* mpe) 548 { 549 550 _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 551 552 // Already empty 553 if (Data == NULL) return; 554 555 // This works for both types 556 if (Data -> Tab.T) 557 _cmsFree(mpe ->ContextID, Data -> Tab.T); 558 559 _cmsFreeInterpParams(Data ->Params); 560 _cmsFree(mpe ->ContextID, mpe ->Data); 561 } 562 563 564 // Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different 565 // granularity on each dimension. 566 cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, 567 const cmsUInt32Number clutPoints[], 568 cmsUInt32Number inputChan, 569 cmsUInt32Number outputChan, 570 const cmsUInt16Number* Table) 571 { 572 cmsUInt32Number i, n; 573 _cmsStageCLutData* NewElem; 574 cmsStage* NewMPE; 575 576 _cmsAssert(clutPoints != NULL); 577 578 if (inputChan > MAX_INPUT_DIMENSIONS) { 579 cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); 580 return NULL; 581 } 582 583 NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, 584 EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL ); 585 586 if (NewMPE == NULL) return NULL; 587 588 NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); 589 if (NewElem == NULL) { 590 cmsStageFree(NewMPE); 591 return NULL; 592 } 593 594 NewMPE ->Data = (void*) NewElem; 595 596 NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); 597 NewElem -> HasFloatValues = FALSE; 598 599 if (n == 0) { 600 cmsStageFree(NewMPE); 601 return NULL; 602 } 603 604 605 NewElem ->Tab.T = (cmsUInt16Number*) _cmsCalloc(ContextID, n, sizeof(cmsUInt16Number)); 606 if (NewElem ->Tab.T == NULL) { 607 cmsStageFree(NewMPE); 608 return NULL; 609 } 610 611 if (Table != NULL) { 612 for (i=0; i < n; i++) { 613 NewElem ->Tab.T[i] = Table[i]; 614 } 615 } 616 617 NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.T, CMS_LERP_FLAGS_16BITS); 618 if (NewElem ->Params == NULL) { 619 cmsStageFree(NewMPE); 620 return NULL; 621 } 622 623 return NewMPE; 624 } 625 626 cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, 627 cmsUInt32Number nGridPoints, 628 cmsUInt32Number inputChan, 629 cmsUInt32Number outputChan, 630 const cmsUInt16Number* Table) 631 { 632 cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 633 int i; 634 635 // Our resulting LUT would be same gridpoints on all dimensions 636 for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 637 Dimensions[i] = nGridPoints; 638 639 640 return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); 641 } 642 643 644 cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, 645 cmsUInt32Number nGridPoints, 646 cmsUInt32Number inputChan, 647 cmsUInt32Number outputChan, 648 const cmsFloat32Number* Table) 649 { 650 cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 651 int i; 652 653 // Our resulting LUT would be same gridpoints on all dimensions 654 for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 655 Dimensions[i] = nGridPoints; 656 657 return cmsStageAllocCLutFloatGranular(ContextID, Dimensions, inputChan, outputChan, Table); 658 } 659 660 661 662 cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table) 663 { 664 cmsUInt32Number i, n; 665 _cmsStageCLutData* NewElem; 666 cmsStage* NewMPE; 667 668 _cmsAssert(clutPoints != NULL); 669 670 if (inputChan > MAX_INPUT_DIMENSIONS) { 671 cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); 672 return NULL; 673 } 674 675 NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, 676 EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL); 677 if (NewMPE == NULL) return NULL; 678 679 680 NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); 681 if (NewElem == NULL) { 682 cmsStageFree(NewMPE); 683 return NULL; 684 } 685 686 NewMPE ->Data = (void*) NewElem; 687 688 // There is a potential integer overflow on conputing n and nEntries. 689 NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); 690 NewElem -> HasFloatValues = TRUE; 691 692 if (n == 0) { 693 cmsStageFree(NewMPE); 694 return NULL; 695 } 696 697 NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat32Number)); 698 if (NewElem ->Tab.TFloat == NULL) { 699 cmsStageFree(NewMPE); 700 return NULL; 701 } 702 703 if (Table != NULL) { 704 for (i=0; i < n; i++) { 705 NewElem ->Tab.TFloat[i] = Table[i]; 706 } 707 } 708 709 710 NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); 711 if (NewElem ->Params == NULL) { 712 cmsStageFree(NewMPE); 713 return NULL; 714 } 715 716 717 718 return NewMPE; 719 } 720 721 722 static 723 int IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) 724 { 725 int nChan = *(int*) Cargo; 726 int i; 727 728 for (i=0; i < nChan; i++) 729 Out[i] = In[i]; 730 731 return 1; 732 } 733 734 // Creates an MPE that just copies input to output 735 cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan) 736 { 737 cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 738 cmsStage* mpe ; 739 int i; 740 741 for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 742 Dimensions[i] = 2; 743 744 mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL); 745 if (mpe == NULL) return NULL; 746 747 if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) { 748 cmsStageFree(mpe); 749 return NULL; 750 } 751 752 mpe ->Implements = cmsSigIdentityElemType; 753 return mpe; 754 } 755 756 757 758 // Quantize a value 0 <= i < MaxSamples to 0..0xffff 759 cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples) 760 { 761 cmsFloat64Number x; 762 763 x = ((cmsFloat64Number) i * 65535.) / (cmsFloat64Number) (MaxSamples - 1); 764 return _cmsQuickSaturateWord(x); 765 } 766 767 768 // This routine does a sweep on whole input space, and calls its callback 769 // function on knots. returns TRUE if all ok, FALSE otherwise. 770 cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags) 771 { 772 int i, t, nTotalPoints, index, rest; 773 int nInputs, nOutputs; 774 cmsUInt32Number* nSamples; 775 cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; 776 _cmsStageCLutData* clut; 777 778 if (mpe == NULL) return FALSE; 779 780 clut = (_cmsStageCLutData*) mpe->Data; 781 782 if (clut == NULL) return FALSE; 783 784 nSamples = clut->Params ->nSamples; 785 nInputs = clut->Params ->nInputs; 786 nOutputs = clut->Params ->nOutputs; 787 788 if (nInputs >= cmsMAXCHANNELS) return FALSE; 789 if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; 790 791 nTotalPoints = CubeSize(nSamples, nInputs); 792 if (nTotalPoints == 0) return FALSE; 793 794 index = 0; 795 for (i = 0; i < nTotalPoints; i++) { 796 797 rest = i; 798 for (t = nInputs-1; t >=0; --t) { 799 800 cmsUInt32Number Colorant = rest % nSamples[t]; 801 802 rest /= nSamples[t]; 803 804 In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); 805 } 806 807 if (clut ->Tab.T != NULL) { 808 for (t=0; t < nOutputs; t++) 809 Out[t] = clut->Tab.T[index + t]; 810 } 811 812 if (!Sampler(In, Out, Cargo)) 813 return FALSE; 814 815 if (!(dwFlags & SAMPLER_INSPECT)) { 816 817 if (clut ->Tab.T != NULL) { 818 for (t=0; t < nOutputs; t++) 819 clut->Tab.T[index + t] = Out[t]; 820 } 821 } 822 823 index += nOutputs; 824 } 825 826 return TRUE; 827 } 828 829 // Same as anterior, but for floting point 830 cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void * Cargo, cmsUInt32Number dwFlags) 831 { 832 int i, t, nTotalPoints, index, rest; 833 int nInputs, nOutputs; 834 cmsUInt32Number* nSamples; 835 cmsFloat32Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; 836 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; 837 838 nSamples = clut->Params ->nSamples; 839 nInputs = clut->Params ->nInputs; 840 nOutputs = clut->Params ->nOutputs; 841 842 if (nInputs >= cmsMAXCHANNELS) return FALSE; 843 if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; 844 845 nTotalPoints = CubeSize(nSamples, nInputs); 846 if (nTotalPoints == 0) return FALSE; 847 848 index = 0; 849 for (i = 0; i < nTotalPoints; i++) { 850 851 rest = i; 852 for (t = nInputs-1; t >=0; --t) { 853 854 cmsUInt32Number Colorant = rest % nSamples[t]; 855 856 rest /= nSamples[t]; 857 858 In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); 859 } 860 861 if (clut ->Tab.TFloat != NULL) { 862 for (t=0; t < nOutputs; t++) 863 Out[t] = clut->Tab.TFloat[index + t]; 864 } 865 866 if (!Sampler(In, Out, Cargo)) 867 return FALSE; 868 869 if (!(dwFlags & SAMPLER_INSPECT)) { 870 871 if (clut ->Tab.TFloat != NULL) { 872 for (t=0; t < nOutputs; t++) 873 clut->Tab.TFloat[index + t] = Out[t]; 874 } 875 } 876 877 index += nOutputs; 878 } 879 880 return TRUE; 881 } 882 883 884 885 // This routine does a sweep on whole input space, and calls its callback 886 // function on knots. returns TRUE if all ok, FALSE otherwise. 887 cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], 888 cmsSAMPLER16 Sampler, void * Cargo) 889 { 890 int i, t, nTotalPoints, rest; 891 cmsUInt16Number In[cmsMAXCHANNELS]; 892 893 if (nInputs >= cmsMAXCHANNELS) return FALSE; 894 895 nTotalPoints = CubeSize(clutPoints, nInputs); 896 if (nTotalPoints == 0) return FALSE; 897 898 for (i = 0; i < nTotalPoints; i++) { 899 900 rest = i; 901 for (t = nInputs-1; t >=0; --t) { 902 903 cmsUInt32Number Colorant = rest % clutPoints[t]; 904 905 rest /= clutPoints[t]; 906 In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); 907 908 } 909 910 if (!Sampler(In, NULL, Cargo)) 911 return FALSE; 912 } 913 914 return TRUE; 915 } 916 917 cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], 918 cmsSAMPLERFLOAT Sampler, void * Cargo) 919 { 920 int i, t, nTotalPoints, rest; 921 cmsFloat32Number In[cmsMAXCHANNELS]; 922 923 if (nInputs >= cmsMAXCHANNELS) return FALSE; 924 925 nTotalPoints = CubeSize(clutPoints, nInputs); 926 if (nTotalPoints == 0) return FALSE; 927 928 for (i = 0; i < nTotalPoints; i++) { 929 930 rest = i; 931 for (t = nInputs-1; t >=0; --t) { 932 933 cmsUInt32Number Colorant = rest % clutPoints[t]; 934 935 rest /= clutPoints[t]; 936 In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); 937 938 } 939 940 if (!Sampler(In, NULL, Cargo)) 941 return FALSE; 942 } 943 944 return TRUE; 945 } 946 947 // ******************************************************************************** 948 // Type cmsSigLab2XYZElemType 949 // ******************************************************************************** 950 951 952 static 953 void EvaluateLab2XYZ(const cmsFloat32Number In[], 954 cmsFloat32Number Out[], 955 const cmsStage *mpe) 956 { 957 cmsCIELab Lab; 958 cmsCIEXYZ XYZ; 959 const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; 960 961 // V4 rules 962 Lab.L = In[0] * 100.0; 963 Lab.a = In[1] * 255.0 - 128.0; 964 Lab.b = In[2] * 255.0 - 128.0; 965 966 cmsLab2XYZ(NULL, &XYZ, &Lab); 967 968 // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff 969 // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0) 970 971 Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); 972 Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); 973 Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); 974 return; 975 976 cmsUNUSED_PARAMETER(mpe); 977 } 978 979 980 // No dup or free routines needed, as the structure has no pointers in it. 981 cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID) 982 { 983 return _cmsStageAllocPlaceholder(ContextID, cmsSigLab2XYZElemType, 3, 3, EvaluateLab2XYZ, NULL, NULL, NULL); 984 } 985 986 // ******************************************************************************** 987 988 // v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable 989 // number of gridpoints that would make exact match. However, a prelinearization 990 // of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. 991 // Almost all what we need but unfortunately, the rest of entries should be scaled by 992 // (255*257/256) and this is not exact. 993 994 cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) 995 { 996 cmsStage* mpe; 997 cmsToneCurve* LabTable[3]; 998 int i, j; 999 1000 LabTable[0] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); 1001 LabTable[1] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); 1002 LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); 1003 1004 for (j=0; j < 3; j++) { 1005 1006 if (LabTable[j] == NULL) { 1007 cmsFreeToneCurveTriple(LabTable); 1008 return NULL; 1009 } 1010 1011 // We need to map * (0xffff / 0xff00), thats same as (257 / 256) 1012 // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256); 1013 for (i=0; i < 257; i++) { 1014 1015 LabTable[j]->Table16[i] = (cmsUInt16Number) ((i * 0xffff + 0x80) >> 8); 1016 } 1017 1018 LabTable[j] ->Table16[257] = 0xffff; 1019 } 1020 1021 mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); 1022 cmsFreeToneCurveTriple(LabTable); 1023 1024 if (mpe == NULL) return mpe; 1025 1026 mpe ->Implements = cmsSigLabV2toV4; 1027 return mpe; 1028 } 1029 1030 // ******************************************************************************** 1031 1032 // Matrix-based conversion, which is more accurate, but slower and cannot properly be saved in devicelink profiles 1033 cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID) 1034 { 1035 static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0, 1036 0, 65535.0/65280.0, 0, 1037 0, 0, 65535.0/65280.0 1038 }; 1039 1040 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL); 1041 1042 if (mpe == NULL) return mpe; 1043 mpe ->Implements = cmsSigLabV2toV4; 1044 return mpe; 1045 } 1046 1047 1048 // Reverse direction 1049 cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID) 1050 { 1051 static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0, 1052 0, 65280.0/65535.0, 0, 1053 0, 0, 65280.0/65535.0 1054 }; 1055 1056 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL); 1057 1058 if (mpe == NULL) return mpe; 1059 mpe ->Implements = cmsSigLabV4toV2; 1060 return mpe; 1061 } 1062 1063 1064 // To Lab to float. Note that the MPE gives numbers in normal Lab range 1065 // and we need 0..1.0 range for the formatters 1066 // L* : 0...100 => 0...1.0 (L* / 100) 1067 // ab* : -128..+127 to 0..1 ((ab* + 128) / 255) 1068 1069 cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID) 1070 { 1071 static const cmsFloat64Number a1[] = { 1072 1.0/100.0, 0, 0, 1073 0, 1.0/255.0, 0, 1074 0, 0, 1.0/255.0 1075 }; 1076 1077 static const cmsFloat64Number o1[] = { 1078 0, 1079 128.0/255.0, 1080 128.0/255.0 1081 }; 1082 1083 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); 1084 1085 if (mpe == NULL) return mpe; 1086 mpe ->Implements = cmsSigLab2FloatPCS; 1087 return mpe; 1088 } 1089 1090 // Fom XYZ to floating point PCS 1091 cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID) 1092 { 1093 #define n (32768.0/65535.0) 1094 static const cmsFloat64Number a1[] = { 1095 n, 0, 0, 1096 0, n, 0, 1097 0, 0, n 1098 }; 1099 #undef n 1100 1101 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); 1102 1103 if (mpe == NULL) return mpe; 1104 mpe ->Implements = cmsSigXYZ2FloatPCS; 1105 return mpe; 1106 } 1107 1108 cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID) 1109 { 1110 static const cmsFloat64Number a1[] = { 1111 100.0, 0, 0, 1112 0, 255.0, 0, 1113 0, 0, 255.0 1114 }; 1115 1116 static const cmsFloat64Number o1[] = { 1117 0, 1118 -128.0, 1119 -128.0 1120 }; 1121 1122 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); 1123 if (mpe == NULL) return mpe; 1124 mpe ->Implements = cmsSigFloatPCS2Lab; 1125 return mpe; 1126 } 1127 1128 cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID) 1129 { 1130 #define n (65535.0/32768.0) 1131 1132 static const cmsFloat64Number a1[] = { 1133 n, 0, 0, 1134 0, n, 0, 1135 0, 0, n 1136 }; 1137 #undef n 1138 1139 cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); 1140 if (mpe == NULL) return mpe; 1141 mpe ->Implements = cmsSigFloatPCS2XYZ; 1142 return mpe; 1143 } 1144 1145 1146 1147 // ******************************************************************************** 1148 // Type cmsSigXYZ2LabElemType 1149 // ******************************************************************************** 1150 1151 static 1152 void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 1153 { 1154 cmsCIELab Lab; 1155 cmsCIEXYZ XYZ; 1156 const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; 1157 1158 // From 0..1.0 to XYZ 1159 1160 XYZ.X = In[0] * XYZadj; 1161 XYZ.Y = In[1] * XYZadj; 1162 XYZ.Z = In[2] * XYZadj; 1163 1164 cmsXYZ2Lab(NULL, &Lab, &XYZ); 1165 1166 // From V4 Lab to 0..1.0 1167 1168 Out[0] = (cmsFloat32Number) (Lab.L / 100.0); 1169 Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); 1170 Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0); 1171 return; 1172 1173 cmsUNUSED_PARAMETER(mpe); 1174 } 1175 1176 cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID) 1177 { 1178 return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL); 1179 1180 } 1181 1182 // ******************************************************************************** 1183 1184 // For v4, S-Shaped curves are placed in a/b axis to increase resolution near gray 1185 1186 cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID) 1187 { 1188 cmsToneCurve* LabTable[3]; 1189 cmsFloat64Number Params[1] = {2.4} ; 1190 1191 LabTable[0] = cmsBuildGamma(ContextID, 1.0); 1192 LabTable[1] = cmsBuildParametricToneCurve(ContextID, 108, Params); 1193 LabTable[2] = cmsBuildParametricToneCurve(ContextID, 108, Params); 1194 1195 return cmsStageAllocToneCurves(ContextID, 3, LabTable); 1196 } 1197 1198 1199 // Free a single MPE 1200 void CMSEXPORT cmsStageFree(cmsStage* mpe) 1201 { 1202 if (mpe ->FreePtr) 1203 mpe ->FreePtr(mpe); 1204 1205 _cmsFree(mpe ->ContextID, mpe); 1206 } 1207 1208 1209 cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe) 1210 { 1211 return mpe ->InputChannels; 1212 } 1213 1214 cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe) 1215 { 1216 return mpe ->OutputChannels; 1217 } 1218 1219 cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe) 1220 { 1221 return mpe -> Type; 1222 } 1223 1224 void* CMSEXPORT cmsStageData(const cmsStage* mpe) 1225 { 1226 return mpe -> Data; 1227 } 1228 1229 cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) 1230 { 1231 return mpe -> Next; 1232 } 1233 1234 1235 // Duplicates an MPE 1236 cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) 1237 { 1238 cmsStage* NewMPE; 1239 1240 if (mpe == NULL) return NULL; 1241 NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, 1242 mpe ->Type, 1243 mpe ->InputChannels, 1244 mpe ->OutputChannels, 1245 mpe ->EvalPtr, 1246 mpe ->DupElemPtr, 1247 mpe ->FreePtr, 1248 NULL); 1249 if (NewMPE == NULL) return NULL; 1250 1251 NewMPE ->Implements = mpe ->Implements; 1252 1253 if (mpe ->DupElemPtr) 1254 NewMPE ->Data = mpe ->DupElemPtr(mpe); 1255 else 1256 NewMPE ->Data = NULL; 1257 1258 return NewMPE; 1259 } 1260 1261 1262 // *********************************************************************************************************** 1263 1264 // This function sets up the channel count 1265 1266 static 1267 void BlessLUT(cmsPipeline* lut) 1268 { 1269 // We can set the input/output channels only if we have elements. 1270 if (lut ->Elements != NULL) { 1271 1272 cmsStage *First, *Last; 1273 1274 First = cmsPipelineGetPtrToFirstStage(lut); 1275 Last = cmsPipelineGetPtrToLastStage(lut); 1276 1277 if (First != NULL)lut ->InputChannels = First ->InputChannels; 1278 if (Last != NULL) lut ->OutputChannels = Last ->OutputChannels; 1279 } 1280 } 1281 1282 1283 // Default to evaluate the LUT on 16 bit-basis. Precision is retained. 1284 static 1285 void _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* D) 1286 { 1287 cmsPipeline* lut = (cmsPipeline*) D; 1288 cmsStage *mpe; 1289 cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; 1290 int Phase = 0, NextPhase; 1291 1292 From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels); 1293 1294 for (mpe = lut ->Elements; 1295 mpe != NULL; 1296 mpe = mpe ->Next) { 1297 1298 NextPhase = Phase ^ 1; 1299 mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); 1300 Phase = NextPhase; 1301 } 1302 1303 1304 FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels); 1305 } 1306 1307 1308 1309 // Does evaluate the LUT on cmsFloat32Number-basis. 1310 static 1311 void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Number Out[], const void* D) 1312 { 1313 cmsPipeline* lut = (cmsPipeline*) D; 1314 cmsStage *mpe; 1315 cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; 1316 int Phase = 0, NextPhase; 1317 1318 memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number)); 1319 1320 for (mpe = lut ->Elements; 1321 mpe != NULL; 1322 mpe = mpe ->Next) { 1323 1324 NextPhase = Phase ^ 1; 1325 mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); 1326 Phase = NextPhase; 1327 } 1328 1329 memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number)); 1330 } 1331 1332 1333 1334 1335 // LUT Creation & Destruction 1336 1337 cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels) 1338 { 1339 cmsPipeline* NewLUT; 1340 1341 if (InputChannels >= cmsMAXCHANNELS || 1342 OutputChannels >= cmsMAXCHANNELS) return NULL; 1343 1344 NewLUT = (cmsPipeline*) _cmsMallocZero(ContextID, sizeof(cmsPipeline)); 1345 if (NewLUT == NULL) return NULL; 1346 1347 1348 NewLUT -> InputChannels = InputChannels; 1349 NewLUT -> OutputChannels = OutputChannels; 1350 1351 NewLUT ->Eval16Fn = _LUTeval16; 1352 NewLUT ->EvalFloatFn = _LUTevalFloat; 1353 NewLUT ->DupDataFn = NULL; 1354 NewLUT ->FreeDataFn = NULL; 1355 NewLUT ->Data = NewLUT; 1356 NewLUT ->ContextID = ContextID; 1357 1358 BlessLUT(NewLUT); 1359 1360 return NewLUT; 1361 } 1362 1363 cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut) 1364 { 1365 _cmsAssert(lut != NULL); 1366 return lut ->ContextID; 1367 } 1368 1369 cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut) 1370 { 1371 _cmsAssert(lut != NULL); 1372 return lut ->InputChannels; 1373 } 1374 1375 cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut) 1376 { 1377 _cmsAssert(lut != NULL); 1378 return lut ->OutputChannels; 1379 } 1380 1381 // Free a profile elements LUT 1382 void CMSEXPORT cmsPipelineFree(cmsPipeline* lut) 1383 { 1384 cmsStage *mpe, *Next; 1385 1386 if (lut == NULL) return; 1387 1388 for (mpe = lut ->Elements; 1389 mpe != NULL; 1390 mpe = Next) { 1391 1392 Next = mpe ->Next; 1393 cmsStageFree(mpe); 1394 } 1395 1396 if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data); 1397 1398 _cmsFree(lut ->ContextID, lut); 1399 } 1400 1401 1402 // Default to evaluate the LUT on 16 bit-basis. 1403 void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut) 1404 { 1405 _cmsAssert(lut != NULL); 1406 lut ->Eval16Fn(In, Out, lut->Data); 1407 } 1408 1409 1410 // Does evaluate the LUT on cmsFloat32Number-basis. 1411 void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut) 1412 { 1413 _cmsAssert(lut != NULL); 1414 lut ->EvalFloatFn(In, Out, lut); 1415 } 1416 1417 1418 1419 // Duplicates a LUT 1420 cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) 1421 { 1422 cmsPipeline* NewLUT; 1423 cmsStage *NewMPE, *Anterior = NULL, *mpe; 1424 cmsBool First = TRUE; 1425 1426 if (lut == NULL) return NULL; 1427 1428 NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); 1429 if (NewLUT == NULL) return NULL; 1430 1431 for (mpe = lut ->Elements; 1432 mpe != NULL; 1433 mpe = mpe ->Next) { 1434 1435 NewMPE = cmsStageDup(mpe); 1436 1437 if (NewMPE == NULL) { 1438 cmsPipelineFree(NewLUT); 1439 return NULL; 1440 } 1441 1442 if (First) { 1443 NewLUT ->Elements = NewMPE; 1444 First = FALSE; 1445 } 1446 else { 1447 Anterior ->Next = NewMPE; 1448 } 1449 1450 Anterior = NewMPE; 1451 } 1452 1453 NewLUT ->Eval16Fn = lut ->Eval16Fn; 1454 NewLUT ->EvalFloatFn = lut ->EvalFloatFn; 1455 NewLUT ->DupDataFn = lut ->DupDataFn; 1456 NewLUT ->FreeDataFn = lut ->FreeDataFn; 1457 1458 if (NewLUT ->DupDataFn != NULL) 1459 NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data); 1460 1461 1462 NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits; 1463 1464 BlessLUT(NewLUT); 1465 return NewLUT; 1466 } 1467 1468 1469 void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) 1470 { 1471 cmsStage* Anterior = NULL, *pt; 1472 1473 _cmsAssert(lut != NULL); 1474 _cmsAssert(mpe != NULL); 1475 1476 switch (loc) { 1477 1478 case cmsAT_BEGIN: 1479 mpe ->Next = lut ->Elements; 1480 lut ->Elements = mpe; 1481 break; 1482 1483 case cmsAT_END: 1484 1485 if (lut ->Elements == NULL) 1486 lut ->Elements = mpe; 1487 else { 1488 1489 for (pt = lut ->Elements; 1490 pt != NULL; 1491 pt = pt -> Next) Anterior = pt; 1492 1493 Anterior ->Next = mpe; 1494 mpe ->Next = NULL; 1495 } 1496 break; 1497 default:; 1498 } 1499 1500 BlessLUT(lut); 1501 } 1502 1503 // Unlink an element and return the pointer to it 1504 void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe) 1505 { 1506 cmsStage *Anterior, *pt, *Last; 1507 cmsStage *Unlinked = NULL; 1508 1509 1510 // If empty LUT, there is nothing to remove 1511 if (lut ->Elements == NULL) { 1512 if (mpe) *mpe = NULL; 1513 return; 1514 } 1515 1516 // On depending on the strategy... 1517 switch (loc) { 1518 1519 case cmsAT_BEGIN: 1520 { 1521 cmsStage* elem = lut ->Elements; 1522 1523 lut ->Elements = elem -> Next; 1524 elem ->Next = NULL; 1525 Unlinked = elem; 1526 1527 } 1528 break; 1529 1530 case cmsAT_END: 1531 Anterior = Last = NULL; 1532 for (pt = lut ->Elements; 1533 pt != NULL; 1534 pt = pt -> Next) { 1535 Anterior = Last; 1536 Last = pt; 1537 } 1538 1539 Unlinked = Last; // Next already points to NULL 1540 1541 // Truncate the chain 1542 if (Anterior) 1543 Anterior ->Next = NULL; 1544 else 1545 lut ->Elements = NULL; 1546 break; 1547 default:; 1548 } 1549 1550 if (mpe) 1551 *mpe = Unlinked; 1552 else 1553 cmsStageFree(Unlinked); 1554 1555 BlessLUT(lut); 1556 } 1557 1558 1559 // Concatenate two LUT into a new single one 1560 cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) 1561 { 1562 cmsStage* mpe, *NewMPE; 1563 1564 // If both LUTS does not have elements, we need to inherit 1565 // the number of channels 1566 if (l1 ->Elements == NULL && l2 ->Elements == NULL) { 1567 l1 ->InputChannels = l2 ->InputChannels; 1568 l1 ->OutputChannels = l2 ->OutputChannels; 1569 } 1570 1571 // Cat second 1572 for (mpe = l2 ->Elements; 1573 mpe != NULL; 1574 mpe = mpe ->Next) { 1575 1576 // We have to dup each element 1577 NewMPE = cmsStageDup(mpe); 1578 1579 if (NewMPE == NULL) { 1580 return FALSE; 1581 } 1582 1583 cmsPipelineInsertStage(l1, cmsAT_END, NewMPE); 1584 } 1585 1586 BlessLUT(l1); 1587 return TRUE; 1588 } 1589 1590 1591 cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On) 1592 { 1593 cmsBool Anterior = lut ->SaveAs8Bits; 1594 1595 lut ->SaveAs8Bits = On; 1596 return Anterior; 1597 } 1598 1599 1600 cmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut) 1601 { 1602 return lut ->Elements; 1603 } 1604 1605 cmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut) 1606 { 1607 cmsStage *mpe, *Anterior = NULL; 1608 1609 for (mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) 1610 Anterior = mpe; 1611 1612 return Anterior; 1613 } 1614 1615 cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut) 1616 { 1617 cmsStage *mpe; 1618 cmsUInt32Number n; 1619 1620 for (n=0, mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) 1621 n++; 1622 1623 return n; 1624 } 1625 1626 // This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional 1627 // duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. 1628 void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, 1629 _cmsOPTeval16Fn Eval16, 1630 void* PrivateData, 1631 _cmsFreeUserDataFn FreePrivateDataFn, 1632 _cmsDupUserDataFn DupPrivateDataFn) 1633 { 1634 1635 Lut ->Eval16Fn = Eval16; 1636 Lut ->DupDataFn = DupPrivateDataFn; 1637 Lut ->FreeDataFn = FreePrivateDataFn; 1638 Lut ->Data = PrivateData; 1639 } 1640 1641 1642 // ----------------------------------------------------------- Reverse interpolation 1643 // Here's how it goes. The derivative Df(x) of the function f is the linear 1644 // transformation that best approximates f near the point x. It can be represented 1645 // by a matrix A whose entries are the partial derivatives of the components of f 1646 // with respect to all the coordinates. This is know as the Jacobian 1647 // 1648 // The best linear approximation to f is given by the matrix equation: 1649 // 1650 // y-y0 = A (x-x0) 1651 // 1652 // So, if x0 is a good "guess" for the zero of f, then solving for the zero of this 1653 // linear approximation will give a "better guess" for the zero of f. Thus let y=0, 1654 // and since y0=f(x0) one can solve the above equation for x. This leads to the 1655 // Newton's method formula: 1656 // 1657 // xn+1 = xn - A-1 f(xn) 1658 // 1659 // where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the 1660 // fashion described above. Iterating this will give better and better approximations 1661 // if you have a "good enough" initial guess. 1662 1663 1664 #define JACOBIAN_EPSILON 0.001f 1665 #define INVERSION_MAX_ITERATIONS 30 1666 1667 // Increment with reflexion on boundary 1668 static 1669 void IncDelta(cmsFloat32Number *Val) 1670 { 1671 if (*Val < (1.0 - JACOBIAN_EPSILON)) 1672 1673 *Val += JACOBIAN_EPSILON; 1674 1675 else 1676 *Val -= JACOBIAN_EPSILON; 1677 1678 } 1679 1680 1681 1682 // Euclidean distance between two vectors of n elements each one 1683 static 1684 cmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], int n) 1685 { 1686 cmsFloat32Number sum = 0; 1687 int i; 1688 1689 for (i=0; i < n; i++) { 1690 cmsFloat32Number dif = b[i] - a[i]; 1691 sum += dif * dif; 1692 } 1693 1694 return sqrtf(sum); 1695 } 1696 1697 1698 // Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method 1699 // 1700 // x1 <- x - [J(x)]^-1 * f(x) 1701 // 1702 // lut: The LUT on where to do the search 1703 // Target: LabK, 3 values of Lab plus destination K which is fixed 1704 // Result: The obtained CMYK 1705 // Hint: Location where begin the search 1706 1707 cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], 1708 cmsFloat32Number Result[], 1709 cmsFloat32Number Hint[], 1710 const cmsPipeline* lut) 1711 { 1712 cmsUInt32Number i, j; 1713 cmsFloat64Number error, LastError = 1E20; 1714 cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; 1715 cmsVEC3 tmp, tmp2; 1716 cmsMAT3 Jacobian; 1717 cmsFloat64Number LastResult[4]; 1718 1719 1720 // Only 3->3 and 4->3 are supported 1721 if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; 1722 if (lut ->OutputChannels != 3) return FALSE; 1723 1724 // Mark result of -1 1725 LastResult[0] = LastResult[1] = LastResult[2] = -1.0f; 1726 1727 // Take the hint as starting point if specified 1728 if (Hint == NULL) { 1729 1730 // Begin at any point, we choose 1/3 of CMY axis 1731 x[0] = x[1] = x[2] = 0.3f; 1732 } 1733 else { 1734 1735 // Only copy 3 channels from hint... 1736 for (j=0; j < 3; j++) 1737 x[j] = Hint[j]; 1738 } 1739 1740 // If Lut is 4-dimensions, then grab target[3], which is fixed 1741 if (lut ->InputChannels == 4) { 1742 x[3] = Target[3]; 1743 } 1744 else x[3] = 0; // To keep lint happy 1745 1746 1747 // Iterate 1748 for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) { 1749 1750 // Get beginning fx 1751 cmsPipelineEvalFloat(x, fx, lut); 1752 1753 // Compute error 1754 error = EuclideanDistance(fx, Target, 3); 1755 1756 // If not convergent, return last safe value 1757 if (error >= LastError) 1758 break; 1759 1760 // Keep latest values 1761 LastError = error; 1762 for (j=0; j < lut ->InputChannels; j++) 1763 Result[j] = x[j]; 1764 1765 // Found an exact match? 1766 if (error <= 0) 1767 break; 1768 1769 // Obtain slope (the Jacobian) 1770 for (j = 0; j < 3; j++) { 1771 1772 xd[0] = x[0]; 1773 xd[1] = x[1]; 1774 xd[2] = x[2]; 1775 xd[3] = x[3]; // Keep fixed channel 1776 1777 IncDelta(&xd[j]); 1778 1779 cmsPipelineEvalFloat(xd, fxd, lut); 1780 1781 Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON); 1782 Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON); 1783 Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); 1784 } 1785 1786 // Solve system 1787 tmp2.n[0] = fx[0] - Target[0]; 1788 tmp2.n[1] = fx[1] - Target[1]; 1789 tmp2.n[2] = fx[2] - Target[2]; 1790 1791 if (!_cmsMAT3solve(&tmp, &Jacobian, &tmp2)) 1792 return FALSE; 1793 1794 // Move our guess 1795 x[0] -= (cmsFloat32Number) tmp.n[0]; 1796 x[1] -= (cmsFloat32Number) tmp.n[1]; 1797 x[2] -= (cmsFloat32Number) tmp.n[2]; 1798 1799 // Some clipping.... 1800 for (j=0; j < 3; j++) { 1801 if (x[j] < 0) x[j] = 0; 1802 else 1803 if (x[j] > 1.0) x[j] = 1.0; 1804 } 1805 } 1806 1807 return TRUE; 1808 } 1809 1810