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-2020 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 // This module incorporates several interpolation routines, for 1 to 8 channels on input and 59 // up to 65535 channels on output. The user may change those by using the interpolation plug-in 60 61 // Some people may want to compile as C++ with all warnings on, in this case make compiler silent 62 #ifdef _MSC_VER 63 # if (_MSC_VER >= 1400) 64 # pragma warning( disable : 4365 ) 65 # endif 66 #endif 67 68 // Interpolation routines by default 69 static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); 70 71 // This is the default factory 72 _cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL }; 73 74 // The interpolation plug-in memory chunk allocator/dup 75 void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) 76 { 77 void* from; 78 79 _cmsAssert(ctx != NULL); 80 81 if (src != NULL) { 82 from = src ->chunks[InterpPlugin]; 83 } 84 else { 85 static _cmsInterpPluginChunkType InterpPluginChunk = { NULL }; 86 87 from = &InterpPluginChunk; 88 } 89 90 _cmsAssert(from != NULL); 91 ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType)); 92 } 93 94 95 // Main plug-in entry 96 cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data) 97 { 98 cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data; 99 _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); 100 101 if (Data == NULL) { 102 103 ptr ->Interpolators = NULL; 104 return TRUE; 105 } 106 107 // Set replacement functions 108 ptr ->Interpolators = Plugin ->InterpolatorsFactory; 109 return TRUE; 110 } 111 112 113 // Set the interpolation method 114 cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p) 115 { 116 _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); 117 118 p ->Interpolation.Lerp16 = NULL; 119 120 // Invoke factory, possibly in the Plug-in 121 if (ptr ->Interpolators != NULL) 122 p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); 123 124 // If unsupported by the plug-in, go for the LittleCMS default. 125 // If happens only if an extern plug-in is being used 126 if (p ->Interpolation.Lerp16 == NULL) 127 p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags); 128 129 // Check for valid interpolator (we just check one member of the union) 130 if (p ->Interpolation.Lerp16 == NULL) { 131 return FALSE; 132 } 133 134 return TRUE; 135 } 136 137 138 // This function precalculates as many parameters as possible to speed up the interpolation. 139 cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, 140 const cmsUInt32Number nSamples[], 141 cmsUInt32Number InputChan, cmsUInt32Number OutputChan, 142 const void *Table, 143 cmsUInt32Number dwFlags) 144 { 145 cmsInterpParams* p; 146 cmsUInt32Number i; 147 148 // Check for maximum inputs 149 if (InputChan > MAX_INPUT_DIMENSIONS) { 150 cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS); 151 return NULL; 152 } 153 154 // Creates an empty object 155 p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams)); 156 if (p == NULL) return NULL; 157 158 // Keep original parameters 159 p -> dwFlags = dwFlags; 160 p -> nInputs = InputChan; 161 p -> nOutputs = OutputChan; 162 p ->Table = Table; 163 p ->ContextID = ContextID; 164 165 // Fill samples per input direction and domain (which is number of nodes minus one) 166 for (i=0; i < InputChan; i++) { 167 168 p -> nSamples[i] = nSamples[i]; 169 p -> Domain[i] = nSamples[i] - 1; 170 } 171 172 // Compute factors to apply to each component to index the grid array 173 p -> opta[0] = p -> nOutputs; 174 for (i=1; i < InputChan; i++) 175 p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i]; 176 177 178 if (!_cmsSetInterpolationRoutine(ContextID, p)) { 179 cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan); 180 _cmsFree(ContextID, p); 181 return NULL; 182 } 183 184 // All seems ok 185 return p; 186 } 187 188 189 // This one is a wrapper on the anterior, but assuming all directions have same number of nodes 190 cmsInterpParams* CMSEXPORT _cmsComputeInterpParams(cmsContext ContextID, cmsUInt32Number nSamples, 191 cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags) 192 { 193 int i; 194 cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS]; 195 196 // Fill the auxiliary array 197 for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 198 Samples[i] = nSamples; 199 200 // Call the extended function 201 return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags); 202 } 203 204 205 // Free all associated memory 206 void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p) 207 { 208 if (p != NULL) _cmsFree(p ->ContextID, p); 209 } 210 211 212 // Inline fixed point interpolation 213 cmsINLINE CMS_NO_SANITIZE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h) 214 { 215 cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000; 216 dif = (dif >> 16) + l; 217 return (cmsUInt16Number) (dif); 218 } 219 220 221 // Linear interpolation (Fixed-point optimized) 222 static 223 void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[], 224 CMSREGISTER cmsUInt16Number Output[], 225 CMSREGISTER const cmsInterpParams* p) 226 { 227 cmsUInt16Number y1, y0; 228 int cell0, rest; 229 int val3; 230 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; 231 232 // if last value... 233 if (Value[0] == 0xffff) { 234 235 Output[0] = LutTable[p -> Domain[0]]; 236 } 237 else 238 { 239 val3 = p->Domain[0] * Value[0]; 240 val3 = _cmsToFixedDomain(val3); // To fixed 15.16 241 242 cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits 243 rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits 244 245 y0 = LutTable[cell0]; 246 y1 = LutTable[cell0 + 1]; 247 248 Output[0] = LinearInterp(rest, y0, y1); 249 } 250 } 251 252 // To prevent out of bounds indexing 253 cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v) 254 { 255 return ((v < 1.0e-9f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v); 256 } 257 258 // Floating-point version of 1D interpolation 259 static 260 void LinLerp1Dfloat(const cmsFloat32Number Value[], 261 cmsFloat32Number Output[], 262 const cmsInterpParams* p) 263 { 264 cmsFloat32Number y1, y0; 265 cmsFloat32Number val2, rest; 266 int cell0, cell1; 267 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; 268 269 val2 = fclamp(Value[0]); 270 271 // if last value... 272 if (val2 == 1.0) { 273 Output[0] = LutTable[p -> Domain[0]]; 274 } 275 else 276 { 277 val2 *= p->Domain[0]; 278 279 cell0 = (int)floor(val2); 280 cell1 = (int)ceil(val2); 281 282 // Rest is 16 LSB bits 283 rest = val2 - cell0; 284 285 y0 = LutTable[cell0]; 286 y1 = LutTable[cell1]; 287 288 Output[0] = y0 + (y1 - y0) * rest; 289 } 290 } 291 292 293 294 // Eval gray LUT having only one input channel 295 static CMS_NO_SANITIZE 296 void Eval1Input(CMSREGISTER const cmsUInt16Number Input[], 297 CMSREGISTER cmsUInt16Number Output[], 298 CMSREGISTER const cmsInterpParams* p16) 299 { 300 cmsS15Fixed16Number fk; 301 cmsS15Fixed16Number k0, k1, rk, K0, K1; 302 int v; 303 cmsUInt32Number OutChan; 304 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; 305 306 v = Input[0] * p16 -> Domain[0]; 307 fk = _cmsToFixedDomain(v); 308 309 k0 = FIXED_TO_INT(fk); 310 rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk); 311 312 k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0); 313 314 K0 = p16 -> opta[0] * k0; 315 K1 = p16 -> opta[0] * k1; 316 317 for (OutChan=0; OutChan < p16->nOutputs; OutChan++) { 318 319 Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]); 320 } 321 } 322 323 324 325 // Eval gray LUT having only one input channel 326 static 327 void Eval1InputFloat(const cmsFloat32Number Value[], 328 cmsFloat32Number Output[], 329 const cmsInterpParams* p) 330 { 331 cmsFloat32Number y1, y0; 332 cmsFloat32Number val2, rest; 333 int cell0, cell1; 334 cmsUInt32Number OutChan; 335 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; 336 337 val2 = fclamp(Value[0]); 338 339 // if last value... 340 if (val2 == 1.0) { 341 342 y0 = LutTable[p->Domain[0]]; 343 344 for (OutChan = 0; OutChan < p->nOutputs; OutChan++) { 345 Output[OutChan] = y0; 346 } 347 } 348 else 349 { 350 val2 *= p->Domain[0]; 351 352 cell0 = (int)floor(val2); 353 cell1 = (int)ceil(val2); 354 355 // Rest is 16 LSB bits 356 rest = val2 - cell0; 357 358 cell0 *= p->opta[0]; 359 cell1 *= p->opta[0]; 360 361 for (OutChan = 0; OutChan < p->nOutputs; OutChan++) { 362 363 y0 = LutTable[cell0 + OutChan]; 364 y1 = LutTable[cell1 + OutChan]; 365 366 Output[OutChan] = y0 + (y1 - y0) * rest; 367 } 368 } 369 } 370 371 // Bilinear interpolation (16 bits) - cmsFloat32Number version 372 static 373 void BilinearInterpFloat(const cmsFloat32Number Input[], 374 cmsFloat32Number Output[], 375 const cmsInterpParams* p) 376 377 { 378 # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) 379 # define DENS(i,j) (LutTable[(i)+(j)+OutChan]) 380 381 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; 382 cmsFloat32Number px, py; 383 int x0, y0, 384 X0, Y0, X1, Y1; 385 int TotalOut, OutChan; 386 cmsFloat32Number fx, fy, 387 d00, d01, d10, d11, 388 dx0, dx1, 389 dxy; 390 391 TotalOut = p -> nOutputs; 392 px = fclamp(Input[0]) * p->Domain[0]; 393 py = fclamp(Input[1]) * p->Domain[1]; 394 395 x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0; 396 y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0; 397 398 X0 = p -> opta[1] * x0; 399 X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[1]); 400 401 Y0 = p -> opta[0] * y0; 402 Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[0]); 403 404 for (OutChan = 0; OutChan < TotalOut; OutChan++) { 405 406 d00 = DENS(X0, Y0); 407 d01 = DENS(X0, Y1); 408 d10 = DENS(X1, Y0); 409 d11 = DENS(X1, Y1); 410 411 dx0 = LERP(fx, d00, d10); 412 dx1 = LERP(fx, d01, d11); 413 414 dxy = LERP(fy, dx0, dx1); 415 416 Output[OutChan] = dxy; 417 } 418 419 420 # undef LERP 421 # undef DENS 422 } 423 424 // Bilinear interpolation (16 bits) - optimized version 425 static CMS_NO_SANITIZE 426 void BilinearInterp16(CMSREGISTER const cmsUInt16Number Input[], 427 CMSREGISTER cmsUInt16Number Output[], 428 CMSREGISTER const cmsInterpParams* p) 429 430 { 431 #define DENS(i,j) (LutTable[(i)+(j)+OutChan]) 432 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) 433 434 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; 435 int OutChan, TotalOut; 436 cmsS15Fixed16Number fx, fy; 437 CMSREGISTER int rx, ry; 438 int x0, y0; 439 CMSREGISTER int X0, X1, Y0, Y1; 440 int d00, d01, d10, d11, 441 dx0, dx1, 442 dxy; 443 444 TotalOut = p -> nOutputs; 445 446 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); 447 x0 = FIXED_TO_INT(fx); 448 rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain 449 450 451 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); 452 y0 = FIXED_TO_INT(fy); 453 ry = FIXED_REST_TO_INT(fy); 454 455 456 X0 = p -> opta[1] * x0; 457 X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]); 458 459 Y0 = p -> opta[0] * y0; 460 Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]); 461 462 for (OutChan = 0; OutChan < TotalOut; OutChan++) { 463 464 d00 = DENS(X0, Y0); 465 d01 = DENS(X0, Y1); 466 d10 = DENS(X1, Y0); 467 d11 = DENS(X1, Y1); 468 469 dx0 = LERP(rx, d00, d10); 470 dx1 = LERP(rx, d01, d11); 471 472 dxy = LERP(ry, dx0, dx1); 473 474 Output[OutChan] = (cmsUInt16Number) dxy; 475 } 476 477 478 # undef LERP 479 # undef DENS 480 } 481 482 483 // Trilinear interpolation (16 bits) - cmsFloat32Number version 484 static 485 void TrilinearInterpFloat(const cmsFloat32Number Input[], 486 cmsFloat32Number Output[], 487 const cmsInterpParams* p) 488 489 { 490 # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a))) 491 # define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) 492 493 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table; 494 cmsFloat32Number px, py, pz; 495 int x0, y0, z0, 496 X0, Y0, Z0, X1, Y1, Z1; 497 int TotalOut, OutChan; 498 cmsFloat32Number fx, fy, fz, 499 d000, d001, d010, d011, 500 d100, d101, d110, d111, 501 dx00, dx01, dx10, dx11, 502 dxy0, dxy1, dxyz; 503 504 TotalOut = p -> nOutputs; 505 506 // We need some clipping here 507 px = fclamp(Input[0]) * p->Domain[0]; 508 py = fclamp(Input[1]) * p->Domain[1]; 509 pz = fclamp(Input[2]) * p->Domain[2]; 510 511 x0 = (int) floor(px); fx = px - (cmsFloat32Number) x0; // We need full floor funcionality here 512 y0 = (int) floor(py); fy = py - (cmsFloat32Number) y0; 513 z0 = (int) floor(pz); fz = pz - (cmsFloat32Number) z0; 514 515 X0 = p -> opta[2] * x0; 516 X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]); 517 518 Y0 = p -> opta[1] * y0; 519 Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]); 520 521 Z0 = p -> opta[0] * z0; 522 Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]); 523 524 for (OutChan = 0; OutChan < TotalOut; OutChan++) { 525 526 d000 = DENS(X0, Y0, Z0); 527 d001 = DENS(X0, Y0, Z1); 528 d010 = DENS(X0, Y1, Z0); 529 d011 = DENS(X0, Y1, Z1); 530 531 d100 = DENS(X1, Y0, Z0); 532 d101 = DENS(X1, Y0, Z1); 533 d110 = DENS(X1, Y1, Z0); 534 d111 = DENS(X1, Y1, Z1); 535 536 537 dx00 = LERP(fx, d000, d100); 538 dx01 = LERP(fx, d001, d101); 539 dx10 = LERP(fx, d010, d110); 540 dx11 = LERP(fx, d011, d111); 541 542 dxy0 = LERP(fy, dx00, dx10); 543 dxy1 = LERP(fy, dx01, dx11); 544 545 dxyz = LERP(fz, dxy0, dxy1); 546 547 Output[OutChan] = dxyz; 548 } 549 550 551 # undef LERP 552 # undef DENS 553 } 554 555 // Trilinear interpolation (16 bits) - optimized version 556 static CMS_NO_SANITIZE 557 void TrilinearInterp16(CMSREGISTER const cmsUInt16Number Input[], 558 CMSREGISTER cmsUInt16Number Output[], 559 CMSREGISTER const cmsInterpParams* p) 560 561 { 562 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) 563 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a))) 564 565 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; 566 int OutChan, TotalOut; 567 cmsS15Fixed16Number fx, fy, fz; 568 CMSREGISTER int rx, ry, rz; 569 int x0, y0, z0; 570 CMSREGISTER int X0, X1, Y0, Y1, Z0, Z1; 571 int d000, d001, d010, d011, 572 d100, d101, d110, d111, 573 dx00, dx01, dx10, dx11, 574 dxy0, dxy1, dxyz; 575 576 TotalOut = p -> nOutputs; 577 578 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); 579 x0 = FIXED_TO_INT(fx); 580 rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain 581 582 583 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); 584 y0 = FIXED_TO_INT(fy); 585 ry = FIXED_REST_TO_INT(fy); 586 587 fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); 588 z0 = FIXED_TO_INT(fz); 589 rz = FIXED_REST_TO_INT(fz); 590 591 592 X0 = p -> opta[2] * x0; 593 X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]); 594 595 Y0 = p -> opta[1] * y0; 596 Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]); 597 598 Z0 = p -> opta[0] * z0; 599 Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]); 600 601 for (OutChan = 0; OutChan < TotalOut; OutChan++) { 602 603 d000 = DENS(X0, Y0, Z0); 604 d001 = DENS(X0, Y0, Z1); 605 d010 = DENS(X0, Y1, Z0); 606 d011 = DENS(X0, Y1, Z1); 607 608 d100 = DENS(X1, Y0, Z0); 609 d101 = DENS(X1, Y0, Z1); 610 d110 = DENS(X1, Y1, Z0); 611 d111 = DENS(X1, Y1, Z1); 612 613 614 dx00 = LERP(rx, d000, d100); 615 dx01 = LERP(rx, d001, d101); 616 dx10 = LERP(rx, d010, d110); 617 dx11 = LERP(rx, d011, d111); 618 619 dxy0 = LERP(ry, dx00, dx10); 620 dxy1 = LERP(ry, dx01, dx11); 621 622 dxyz = LERP(rz, dxy0, dxy1); 623 624 Output[OutChan] = (cmsUInt16Number) dxyz; 625 } 626 627 628 # undef LERP 629 # undef DENS 630 } 631 632 633 // Tetrahedral interpolation, using Sakamoto algorithm. 634 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) 635 static 636 void TetrahedralInterpFloat(const cmsFloat32Number Input[], 637 cmsFloat32Number Output[], 638 const cmsInterpParams* p) 639 { 640 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; 641 cmsFloat32Number px, py, pz; 642 int x0, y0, z0, 643 X0, Y0, Z0, X1, Y1, Z1; 644 cmsFloat32Number rx, ry, rz; 645 cmsFloat32Number c0, c1=0, c2=0, c3=0; 646 int OutChan, TotalOut; 647 648 TotalOut = p -> nOutputs; 649 650 // We need some clipping here 651 px = fclamp(Input[0]) * p->Domain[0]; 652 py = fclamp(Input[1]) * p->Domain[1]; 653 pz = fclamp(Input[2]) * p->Domain[2]; 654 655 x0 = (int) floor(px); rx = (px - (cmsFloat32Number) x0); // We need full floor functionality here 656 y0 = (int) floor(py); ry = (py - (cmsFloat32Number) y0); 657 z0 = (int) floor(pz); rz = (pz - (cmsFloat32Number) z0); 658 659 660 X0 = p -> opta[2] * x0; 661 X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]); 662 663 Y0 = p -> opta[1] * y0; 664 Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]); 665 666 Z0 = p -> opta[0] * z0; 667 Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]); 668 669 for (OutChan=0; OutChan < TotalOut; OutChan++) { 670 671 // These are the 6 Tetrahedral 672 673 c0 = DENS(X0, Y0, Z0); 674 675 if (rx >= ry && ry >= rz) { 676 677 c1 = DENS(X1, Y0, Z0) - c0; 678 c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); 679 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); 680 681 } 682 else 683 if (rx >= rz && rz >= ry) { 684 685 c1 = DENS(X1, Y0, Z0) - c0; 686 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); 687 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); 688 689 } 690 else 691 if (rz >= rx && rx >= ry) { 692 693 c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); 694 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); 695 c3 = DENS(X0, Y0, Z1) - c0; 696 697 } 698 else 699 if (ry >= rx && rx >= rz) { 700 701 c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); 702 c2 = DENS(X0, Y1, Z0) - c0; 703 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); 704 705 } 706 else 707 if (ry >= rz && rz >= rx) { 708 709 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); 710 c2 = DENS(X0, Y1, Z0) - c0; 711 c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); 712 713 } 714 else 715 if (rz >= ry && ry >= rx) { 716 717 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); 718 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); 719 c3 = DENS(X0, Y0, Z1) - c0; 720 721 } 722 else { 723 c1 = c2 = c3 = 0; 724 } 725 726 Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz; 727 } 728 729 } 730 731 #undef DENS 732 733 734 735 736 static CMS_NO_SANITIZE 737 void TetrahedralInterp16(CMSREGISTER const cmsUInt16Number Input[], 738 CMSREGISTER cmsUInt16Number Output[], 739 CMSREGISTER const cmsInterpParams* p) 740 { 741 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table; 742 cmsS15Fixed16Number fx, fy, fz; 743 cmsS15Fixed16Number rx, ry, rz; 744 int x0, y0, z0; 745 cmsS15Fixed16Number c0, c1, c2, c3, Rest; 746 cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; 747 cmsUInt32Number TotalOut = p -> nOutputs; 748 749 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]); 750 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]); 751 fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]); 752 753 x0 = FIXED_TO_INT(fx); 754 y0 = FIXED_TO_INT(fy); 755 z0 = FIXED_TO_INT(fz); 756 757 rx = FIXED_REST_TO_INT(fx); 758 ry = FIXED_REST_TO_INT(fy); 759 rz = FIXED_REST_TO_INT(fz); 760 761 X0 = p -> opta[2] * x0; 762 X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]); 763 764 Y0 = p -> opta[1] * y0; 765 Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]); 766 767 Z0 = p -> opta[0] * z0; 768 Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]); 769 770 LutTable = &LutTable[X0+Y0+Z0]; 771 772 // Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)) 773 // which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16 774 // This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16 775 // at the cost of being off by one at 7fff and 17ffe. 776 777 if (rx >= ry) { 778 if (ry >= rz) { 779 Y1 += X1; 780 Z1 += Y1; 781 for (; TotalOut; TotalOut--) { 782 c1 = LutTable[X1]; 783 c2 = LutTable[Y1]; 784 c3 = LutTable[Z1]; 785 c0 = *LutTable++; 786 c3 -= c2; 787 c2 -= c1; 788 c1 -= c0; 789 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; 790 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); 791 } 792 } else if (rz >= rx) { 793 X1 += Z1; 794 Y1 += X1; 795 for (; TotalOut; TotalOut--) { 796 c1 = LutTable[X1]; 797 c2 = LutTable[Y1]; 798 c3 = LutTable[Z1]; 799 c0 = *LutTable++; 800 c2 -= c1; 801 c1 -= c3; 802 c3 -= c0; 803 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; 804 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); 805 } 806 } else { 807 Z1 += X1; 808 Y1 += Z1; 809 for (; TotalOut; TotalOut--) { 810 c1 = LutTable[X1]; 811 c2 = LutTable[Y1]; 812 c3 = LutTable[Z1]; 813 c0 = *LutTable++; 814 c2 -= c3; 815 c3 -= c1; 816 c1 -= c0; 817 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; 818 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); 819 } 820 } 821 } else { 822 if (rx >= rz) { 823 X1 += Y1; 824 Z1 += X1; 825 for (; TotalOut; TotalOut--) { 826 c1 = LutTable[X1]; 827 c2 = LutTable[Y1]; 828 c3 = LutTable[Z1]; 829 c0 = *LutTable++; 830 c3 -= c1; 831 c1 -= c2; 832 c2 -= c0; 833 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; 834 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); 835 } 836 } else if (ry >= rz) { 837 Z1 += Y1; 838 X1 += Z1; 839 for (; TotalOut; TotalOut--) { 840 c1 = LutTable[X1]; 841 c2 = LutTable[Y1]; 842 c3 = LutTable[Z1]; 843 c0 = *LutTable++; 844 c1 -= c3; 845 c3 -= c2; 846 c2 -= c0; 847 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; 848 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); 849 } 850 } else { 851 Y1 += Z1; 852 X1 += Y1; 853 for (; TotalOut; TotalOut--) { 854 c1 = LutTable[X1]; 855 c2 = LutTable[Y1]; 856 c3 = LutTable[Z1]; 857 c0 = *LutTable++; 858 c1 -= c2; 859 c2 -= c3; 860 c3 -= c0; 861 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; 862 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16); 863 } 864 } 865 } 866 } 867 868 869 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) 870 static CMS_NO_SANITIZE 871 void Eval4Inputs(CMSREGISTER const cmsUInt16Number Input[], 872 CMSREGISTER cmsUInt16Number Output[], 873 CMSREGISTER const cmsInterpParams* p16) 874 { 875 const cmsUInt16Number* LutTable; 876 cmsS15Fixed16Number fk; 877 cmsS15Fixed16Number k0, rk; 878 int K0, K1; 879 cmsS15Fixed16Number fx, fy, fz; 880 cmsS15Fixed16Number rx, ry, rz; 881 int x0, y0, z0; 882 cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; 883 cmsUInt32Number i; 884 cmsS15Fixed16Number c0, c1, c2, c3, Rest; 885 cmsUInt32Number OutChan; 886 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 887 888 889 fk = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]); 890 fx = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]); 891 fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]); 892 fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]); 893 894 k0 = FIXED_TO_INT(fk); 895 x0 = FIXED_TO_INT(fx); 896 y0 = FIXED_TO_INT(fy); 897 z0 = FIXED_TO_INT(fz); 898 899 rk = FIXED_REST_TO_INT(fk); 900 rx = FIXED_REST_TO_INT(fx); 901 ry = FIXED_REST_TO_INT(fy); 902 rz = FIXED_REST_TO_INT(fz); 903 904 K0 = p16 -> opta[3] * k0; 905 K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]); 906 907 X0 = p16 -> opta[2] * x0; 908 X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]); 909 910 Y0 = p16 -> opta[1] * y0; 911 Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]); 912 913 Z0 = p16 -> opta[0] * z0; 914 Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]); 915 916 LutTable = (cmsUInt16Number*) p16 -> Table; 917 LutTable += K0; 918 919 for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) { 920 921 c0 = DENS(X0, Y0, Z0); 922 923 if (rx >= ry && ry >= rz) { 924 925 c1 = DENS(X1, Y0, Z0) - c0; 926 c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); 927 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); 928 929 } 930 else 931 if (rx >= rz && rz >= ry) { 932 933 c1 = DENS(X1, Y0, Z0) - c0; 934 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); 935 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); 936 937 } 938 else 939 if (rz >= rx && rx >= ry) { 940 941 c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); 942 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); 943 c3 = DENS(X0, Y0, Z1) - c0; 944 945 } 946 else 947 if (ry >= rx && rx >= rz) { 948 949 c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); 950 c2 = DENS(X0, Y1, Z0) - c0; 951 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); 952 953 } 954 else 955 if (ry >= rz && rz >= rx) { 956 957 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); 958 c2 = DENS(X0, Y1, Z0) - c0; 959 c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); 960 961 } 962 else 963 if (rz >= ry && ry >= rx) { 964 965 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); 966 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); 967 c3 = DENS(X0, Y0, Z1) - c0; 968 969 } 970 else { 971 c1 = c2 = c3 = 0; 972 } 973 974 Rest = c1 * rx + c2 * ry + c3 * rz; 975 976 Tmp1[OutChan] = (cmsUInt16Number)(c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))); 977 } 978 979 980 LutTable = (cmsUInt16Number*) p16 -> Table; 981 LutTable += K1; 982 983 for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) { 984 985 c0 = DENS(X0, Y0, Z0); 986 987 if (rx >= ry && ry >= rz) { 988 989 c1 = DENS(X1, Y0, Z0) - c0; 990 c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); 991 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); 992 993 } 994 else 995 if (rx >= rz && rz >= ry) { 996 997 c1 = DENS(X1, Y0, Z0) - c0; 998 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); 999 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); 1000 1001 } 1002 else 1003 if (rz >= rx && rx >= ry) { 1004 1005 c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); 1006 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); 1007 c3 = DENS(X0, Y0, Z1) - c0; 1008 1009 } 1010 else 1011 if (ry >= rx && rx >= rz) { 1012 1013 c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); 1014 c2 = DENS(X0, Y1, Z0) - c0; 1015 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); 1016 1017 } 1018 else 1019 if (ry >= rz && rz >= rx) { 1020 1021 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); 1022 c2 = DENS(X0, Y1, Z0) - c0; 1023 c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); 1024 1025 } 1026 else 1027 if (rz >= ry && ry >= rx) { 1028 1029 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); 1030 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); 1031 c3 = DENS(X0, Y0, Z1) - c0; 1032 1033 } 1034 else { 1035 c1 = c2 = c3 = 0; 1036 } 1037 1038 Rest = c1 * rx + c2 * ry + c3 * rz; 1039 1040 Tmp2[OutChan] = (cmsUInt16Number) (c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))); 1041 } 1042 1043 1044 1045 for (i=0; i < p16 -> nOutputs; i++) { 1046 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); 1047 } 1048 } 1049 #undef DENS 1050 1051 1052 // For more that 3 inputs (i.e., CMYK) 1053 // evaluate two 3-dimensional interpolations and then linearly interpolate between them. 1054 1055 1056 static 1057 void Eval4InputsFloat(const cmsFloat32Number Input[], 1058 cmsFloat32Number Output[], 1059 const cmsInterpParams* p) 1060 { 1061 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; 1062 cmsFloat32Number rest; 1063 cmsFloat32Number pk; 1064 int k0, K0, K1; 1065 const cmsFloat32Number* T; 1066 cmsUInt32Number i; 1067 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 1068 cmsInterpParams p1; 1069 1070 pk = fclamp(Input[0]) * p->Domain[0]; 1071 k0 = _cmsQuickFloor(pk); 1072 rest = pk - (cmsFloat32Number) k0; 1073 1074 K0 = p -> opta[3] * k0; 1075 K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[3]); 1076 1077 p1 = *p; 1078 memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number)); 1079 1080 T = LutTable + K0; 1081 p1.Table = T; 1082 1083 TetrahedralInterpFloat(Input + 1, Tmp1, &p1); 1084 1085 T = LutTable + K1; 1086 p1.Table = T; 1087 TetrahedralInterpFloat(Input + 1, Tmp2, &p1); 1088 1089 for (i=0; i < p -> nOutputs; i++) 1090 { 1091 cmsFloat32Number y0 = Tmp1[i]; 1092 cmsFloat32Number y1 = Tmp2[i]; 1093 1094 Output[i] = y0 + (y1 - y0) * rest; 1095 } 1096 } 1097 1098 1099 static CMS_NO_SANITIZE 1100 void Eval5Inputs(CMSREGISTER const cmsUInt16Number Input[], 1101 CMSREGISTER cmsUInt16Number Output[], 1102 1103 CMSREGISTER const cmsInterpParams* p16) 1104 { 1105 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; 1106 cmsS15Fixed16Number fk; 1107 cmsS15Fixed16Number k0, rk; 1108 int K0, K1; 1109 const cmsUInt16Number* T; 1110 cmsUInt32Number i; 1111 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 1112 cmsInterpParams p1; 1113 1114 1115 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); 1116 k0 = FIXED_TO_INT(fk); 1117 rk = FIXED_REST_TO_INT(fk); 1118 1119 K0 = p16 -> opta[4] * k0; 1120 K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); 1121 1122 p1 = *p16; 1123 memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number)); 1124 1125 T = LutTable + K0; 1126 p1.Table = T; 1127 1128 Eval4Inputs(Input + 1, Tmp1, &p1); 1129 1130 T = LutTable + K1; 1131 p1.Table = T; 1132 1133 Eval4Inputs(Input + 1, Tmp2, &p1); 1134 1135 for (i=0; i < p16 -> nOutputs; i++) { 1136 1137 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); 1138 } 1139 1140 } 1141 1142 1143 static 1144 void Eval5InputsFloat(const cmsFloat32Number Input[], 1145 cmsFloat32Number Output[], 1146 const cmsInterpParams* p) 1147 { 1148 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; 1149 cmsFloat32Number rest; 1150 cmsFloat32Number pk; 1151 int k0, K0, K1; 1152 const cmsFloat32Number* T; 1153 cmsUInt32Number i; 1154 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 1155 cmsInterpParams p1; 1156 1157 pk = fclamp(Input[0]) * p->Domain[0]; 1158 k0 = _cmsQuickFloor(pk); 1159 rest = pk - (cmsFloat32Number) k0; 1160 1161 K0 = p -> opta[4] * k0; 1162 K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[4]); 1163 1164 p1 = *p; 1165 memmove(&p1.Domain[0], &p ->Domain[1], 4*sizeof(cmsUInt32Number)); 1166 1167 T = LutTable + K0; 1168 p1.Table = T; 1169 1170 Eval4InputsFloat(Input + 1, Tmp1, &p1); 1171 1172 T = LutTable + K1; 1173 p1.Table = T; 1174 1175 Eval4InputsFloat(Input + 1, Tmp2, &p1); 1176 1177 for (i=0; i < p -> nOutputs; i++) { 1178 1179 cmsFloat32Number y0 = Tmp1[i]; 1180 cmsFloat32Number y1 = Tmp2[i]; 1181 1182 Output[i] = y0 + (y1 - y0) * rest; 1183 } 1184 } 1185 1186 1187 1188 static CMS_NO_SANITIZE 1189 void Eval6Inputs(CMSREGISTER const cmsUInt16Number Input[], 1190 CMSREGISTER cmsUInt16Number Output[], 1191 CMSREGISTER const cmsInterpParams* p16) 1192 { 1193 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; 1194 cmsS15Fixed16Number fk; 1195 cmsS15Fixed16Number k0, rk; 1196 int K0, K1; 1197 const cmsUInt16Number* T; 1198 cmsUInt32Number i; 1199 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 1200 cmsInterpParams p1; 1201 1202 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); 1203 k0 = FIXED_TO_INT(fk); 1204 rk = FIXED_REST_TO_INT(fk); 1205 1206 K0 = p16 -> opta[5] * k0; 1207 K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); 1208 1209 p1 = *p16; 1210 memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number)); 1211 1212 T = LutTable + K0; 1213 p1.Table = T; 1214 1215 Eval5Inputs(Input + 1, Tmp1, &p1); 1216 1217 T = LutTable + K1; 1218 p1.Table = T; 1219 1220 Eval5Inputs(Input + 1, Tmp2, &p1); 1221 1222 for (i=0; i < p16 -> nOutputs; i++) { 1223 1224 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); 1225 } 1226 1227 } 1228 1229 1230 static 1231 void Eval6InputsFloat(const cmsFloat32Number Input[], 1232 cmsFloat32Number Output[], 1233 const cmsInterpParams* p) 1234 { 1235 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; 1236 cmsFloat32Number rest; 1237 cmsFloat32Number pk; 1238 int k0, K0, K1; 1239 const cmsFloat32Number* T; 1240 cmsUInt32Number i; 1241 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 1242 cmsInterpParams p1; 1243 1244 pk = fclamp(Input[0]) * p->Domain[0]; 1245 k0 = _cmsQuickFloor(pk); 1246 rest = pk - (cmsFloat32Number) k0; 1247 1248 K0 = p -> opta[5] * k0; 1249 K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[5]); 1250 1251 p1 = *p; 1252 memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number)); 1253 1254 T = LutTable + K0; 1255 p1.Table = T; 1256 1257 Eval5InputsFloat(Input + 1, Tmp1, &p1); 1258 1259 T = LutTable + K1; 1260 p1.Table = T; 1261 1262 Eval5InputsFloat(Input + 1, Tmp2, &p1); 1263 1264 for (i=0; i < p -> nOutputs; i++) { 1265 1266 cmsFloat32Number y0 = Tmp1[i]; 1267 cmsFloat32Number y1 = Tmp2[i]; 1268 1269 Output[i] = y0 + (y1 - y0) * rest; 1270 } 1271 } 1272 1273 1274 static CMS_NO_SANITIZE 1275 void Eval7Inputs(CMSREGISTER const cmsUInt16Number Input[], 1276 CMSREGISTER cmsUInt16Number Output[], 1277 CMSREGISTER const cmsInterpParams* p16) 1278 { 1279 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; 1280 cmsS15Fixed16Number fk; 1281 cmsS15Fixed16Number k0, rk; 1282 int K0, K1; 1283 const cmsUInt16Number* T; 1284 cmsUInt32Number i; 1285 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 1286 cmsInterpParams p1; 1287 1288 1289 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); 1290 k0 = FIXED_TO_INT(fk); 1291 rk = FIXED_REST_TO_INT(fk); 1292 1293 K0 = p16 -> opta[6] * k0; 1294 K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); 1295 1296 p1 = *p16; 1297 memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number)); 1298 1299 T = LutTable + K0; 1300 p1.Table = T; 1301 1302 Eval6Inputs(Input + 1, Tmp1, &p1); 1303 1304 T = LutTable + K1; 1305 p1.Table = T; 1306 1307 Eval6Inputs(Input + 1, Tmp2, &p1); 1308 1309 for (i=0; i < p16 -> nOutputs; i++) { 1310 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); 1311 } 1312 } 1313 1314 1315 static 1316 void Eval7InputsFloat(const cmsFloat32Number Input[], 1317 cmsFloat32Number Output[], 1318 const cmsInterpParams* p) 1319 { 1320 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; 1321 cmsFloat32Number rest; 1322 cmsFloat32Number pk; 1323 int k0, K0, K1; 1324 const cmsFloat32Number* T; 1325 cmsUInt32Number i; 1326 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 1327 cmsInterpParams p1; 1328 1329 pk = fclamp(Input[0]) * p->Domain[0]; 1330 k0 = _cmsQuickFloor(pk); 1331 rest = pk - (cmsFloat32Number) k0; 1332 1333 K0 = p -> opta[6] * k0; 1334 K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[6]); 1335 1336 p1 = *p; 1337 memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number)); 1338 1339 T = LutTable + K0; 1340 p1.Table = T; 1341 1342 Eval6InputsFloat(Input + 1, Tmp1, &p1); 1343 1344 T = LutTable + K1; 1345 p1.Table = T; 1346 1347 Eval6InputsFloat(Input + 1, Tmp2, &p1); 1348 1349 1350 for (i=0; i < p -> nOutputs; i++) { 1351 1352 cmsFloat32Number y0 = Tmp1[i]; 1353 cmsFloat32Number y1 = Tmp2[i]; 1354 1355 Output[i] = y0 + (y1 - y0) * rest; 1356 1357 } 1358 } 1359 1360 static CMS_NO_SANITIZE 1361 void Eval8Inputs(CMSREGISTER const cmsUInt16Number Input[], 1362 CMSREGISTER cmsUInt16Number Output[], 1363 CMSREGISTER const cmsInterpParams* p16) 1364 { 1365 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; 1366 cmsS15Fixed16Number fk; 1367 cmsS15Fixed16Number k0, rk; 1368 int K0, K1; 1369 const cmsUInt16Number* T; 1370 cmsUInt32Number i; 1371 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 1372 cmsInterpParams p1; 1373 1374 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]); 1375 k0 = FIXED_TO_INT(fk); 1376 rk = FIXED_REST_TO_INT(fk); 1377 1378 K0 = p16 -> opta[7] * k0; 1379 K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); 1380 1381 p1 = *p16; 1382 memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number)); 1383 1384 T = LutTable + K0; 1385 p1.Table = T; 1386 1387 Eval7Inputs(Input + 1, Tmp1, &p1); 1388 1389 T = LutTable + K1; 1390 p1.Table = T; 1391 Eval7Inputs(Input + 1, Tmp2, &p1); 1392 1393 for (i=0; i < p16 -> nOutputs; i++) { 1394 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]); 1395 } 1396 } 1397 1398 1399 1400 static 1401 void Eval8InputsFloat(const cmsFloat32Number Input[], 1402 cmsFloat32Number Output[], 1403 const cmsInterpParams* p) 1404 { 1405 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table; 1406 cmsFloat32Number rest; 1407 cmsFloat32Number pk; 1408 int k0, K0, K1; 1409 const cmsFloat32Number* T; 1410 cmsUInt32Number i; 1411 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS]; 1412 cmsInterpParams p1; 1413 1414 pk = fclamp(Input[0]) * p->Domain[0]; 1415 k0 = _cmsQuickFloor(pk); 1416 rest = pk - (cmsFloat32Number) k0; 1417 1418 K0 = p -> opta[7] * k0; 1419 K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[7]); 1420 1421 p1 = *p; 1422 memmove(&p1.Domain[0], &p ->Domain[1], 7*sizeof(cmsUInt32Number)); 1423 1424 T = LutTable + K0; 1425 p1.Table = T; 1426 1427 Eval7InputsFloat(Input + 1, Tmp1, &p1); 1428 1429 T = LutTable + K1; 1430 p1.Table = T; 1431 1432 Eval7InputsFloat(Input + 1, Tmp2, &p1); 1433 1434 1435 for (i=0; i < p -> nOutputs; i++) { 1436 1437 cmsFloat32Number y0 = Tmp1[i]; 1438 cmsFloat32Number y1 = Tmp2[i]; 1439 1440 Output[i] = y0 + (y1 - y0) * rest; 1441 } 1442 } 1443 1444 // The default factory 1445 static 1446 cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags) 1447 { 1448 1449 cmsInterpFunction Interpolation; 1450 cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT); 1451 cmsBool IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR); 1452 1453 memset(&Interpolation, 0, sizeof(Interpolation)); 1454 1455 // Safety check 1456 if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS) 1457 return Interpolation; 1458 1459 switch (nInputChannels) { 1460 1461 case 1: // Gray LUT / linear 1462 1463 if (nOutputChannels == 1) { 1464 1465 if (IsFloat) 1466 Interpolation.LerpFloat = LinLerp1Dfloat; 1467 else 1468 Interpolation.Lerp16 = LinLerp1D; 1469 1470 } 1471 else { 1472 1473 if (IsFloat) 1474 Interpolation.LerpFloat = Eval1InputFloat; 1475 else 1476 Interpolation.Lerp16 = Eval1Input; 1477 } 1478 break; 1479 1480 case 2: // Duotone 1481 if (IsFloat) 1482 Interpolation.LerpFloat = BilinearInterpFloat; 1483 else 1484 Interpolation.Lerp16 = BilinearInterp16; 1485 break; 1486 1487 case 3: // RGB et al 1488 1489 if (IsTrilinear) { 1490 1491 if (IsFloat) 1492 Interpolation.LerpFloat = TrilinearInterpFloat; 1493 else 1494 Interpolation.Lerp16 = TrilinearInterp16; 1495 } 1496 else { 1497 1498 if (IsFloat) 1499 Interpolation.LerpFloat = TetrahedralInterpFloat; 1500 else { 1501 1502 Interpolation.Lerp16 = TetrahedralInterp16; 1503 } 1504 } 1505 break; 1506 1507 case 4: // CMYK lut 1508 1509 if (IsFloat) 1510 Interpolation.LerpFloat = Eval4InputsFloat; 1511 else 1512 Interpolation.Lerp16 = Eval4Inputs; 1513 break; 1514 1515 case 5: // 5 Inks 1516 if (IsFloat) 1517 Interpolation.LerpFloat = Eval5InputsFloat; 1518 else 1519 Interpolation.Lerp16 = Eval5Inputs; 1520 break; 1521 1522 case 6: // 6 Inks 1523 if (IsFloat) 1524 Interpolation.LerpFloat = Eval6InputsFloat; 1525 else 1526 Interpolation.Lerp16 = Eval6Inputs; 1527 break; 1528 1529 case 7: // 7 inks 1530 if (IsFloat) 1531 Interpolation.LerpFloat = Eval7InputsFloat; 1532 else 1533 Interpolation.Lerp16 = Eval7Inputs; 1534 break; 1535 1536 case 8: // 8 inks 1537 if (IsFloat) 1538 Interpolation.LerpFloat = Eval8InputsFloat; 1539 else 1540 Interpolation.Lerp16 = Eval8Inputs; 1541 break; 1542 1543 break; 1544 1545 default: 1546 Interpolation.Lerp16 = NULL; 1547 } 1548 1549 return Interpolation; 1550 }