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