1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2010 Marti Maria Saguer
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:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
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.
24 //---------------------------------------------------------------------------------
27 #include "lcms2_internal.h"
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
32 // Interpolation routines by default
33 static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
35 // This is the default factory
36 static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory;
40 cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data)
42 cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data;
46 Interpolators = DefaultInterpolatorsFactory;
50 // Set replacement functions
51 Interpolators = Plugin ->InterpolatorsFactory;
56 // Set the interpolation method
58 cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p)
60 // Invoke factory, possibly in the Plug-in
61 p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);
63 // If unsupported by the plug-in, go for the LittleCMS default.
64 // If happens only if an extern plug-in is being used
65 if (p ->Interpolation.Lerp16 == NULL)
66 p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags);
68 // Check for valid interpolator (we just check one member of the union)
69 if (p ->Interpolation.Lerp16 == NULL) {
76 // This function precalculates as many parameters as possible to speed up the interpolation.
77 cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,
78 const cmsUInt32Number nSamples[],
79 int InputChan, int OutputChan,
81 cmsUInt32Number dwFlags)
86 // Check for maximum inputs
87 if (InputChan > MAX_INPUT_DIMENSIONS) {
88 cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS);
92 // Creates an empty object
93 p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams));
94 if (p == NULL) return NULL;
96 // Keep original parameters
97 p -> dwFlags = dwFlags;
98 p -> nInputs = InputChan;
99 p -> nOutputs = OutputChan;
101 p ->ContextID = ContextID;
103 // Fill samples per input direction and domain (which is number of nodes minus one)
104 for (i=0; i < InputChan; i++) {
106 p -> nSamples[i] = nSamples[i];
107 p -> Domain[i] = nSamples[i] - 1;
110 // Compute factors to apply to each component to index the grid array
111 p -> opta[0] = p -> nOutputs;
112 for (i=1; i < InputChan; i++)
113 p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];
116 if (!_cmsSetInterpolationRoutine(p)) {
117 cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan);
118 _cmsFree(ContextID, p);
127 // This one is a wrapper on the anterior, but assuming all directions have same number of nodes
128 cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags)
131 cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];
133 // Fill the auxiliar array
134 for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
135 Samples[i] = nSamples;
137 // Call the extended function
138 return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags);
142 // Free all associated memory
143 void _cmsFreeInterpParams(cmsInterpParams* p)
145 if (p != NULL) _cmsFree(p ->ContextID, p);
149 // Inline fixed point interpolation
150 cmsINLINE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h)
152 cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000;
153 dif = (dif >> 16) + l;
154 return (cmsUInt16Number) (dif);
158 // Linear interpolation (Fixed-point optimized)
160 void LinLerp1D(register const cmsUInt16Number Value[],
161 register cmsUInt16Number Output[],
162 register const cmsInterpParams* p)
164 cmsUInt16Number y1, y0;
167 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
170 if (Value[0] == 0xffff) {
172 Output[0] = LutTable[p -> Domain[0]];
176 val3 = p -> Domain[0] * Value[0];
177 val3 = _cmsToFixedDomain(val3); // To fixed 15.16
179 cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits
180 rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits
182 y0 = LutTable[cell0];
183 y1 = LutTable[cell0+1];
186 Output[0] = LinearInterp(rest, y0, y1);
190 // Floating-point version of 1D interpolation
192 void LinLerp1Dfloat(const cmsFloat32Number Value[],
193 cmsFloat32Number Output[],
194 const cmsInterpParams* p)
196 cmsFloat32Number y1, y0;
197 cmsFloat32Number val2, rest;
199 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
202 if (Value[0] == 1.0) {
203 Output[0] = LutTable[p -> Domain[0]];
207 val2 = p -> Domain[0] * Value[0];
209 cell0 = (int) floor(val2);
210 cell1 = (int) ceil(val2);
212 // Rest is 16 LSB bits
215 y0 = LutTable[cell0] ;
216 y1 = LutTable[cell1] ;
218 Output[0] = y0 + (y1 - y0) * rest;
223 // Eval gray LUT having only one input channel
225 void Eval1Input(register const cmsUInt16Number Input[],
226 register cmsUInt16Number Output[],
227 register const cmsInterpParams* p16)
229 cmsS15Fixed16Number fk;
230 cmsS15Fixed16Number k0, k1, rk, K0, K1;
232 cmsUInt32Number OutChan;
233 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
235 v = Input[0] * p16 -> Domain[0];
236 fk = _cmsToFixedDomain(v);
238 k0 = FIXED_TO_INT(fk);
239 rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
241 k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
243 K0 = p16 -> opta[0] * k0;
244 K1 = p16 -> opta[0] * k1;
246 for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
248 Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]);
254 // Eval gray LUT having only one input channel
256 void Eval1InputFloat(const cmsFloat32Number Value[],
257 cmsFloat32Number Output[],
258 const cmsInterpParams* p)
260 cmsFloat32Number y1, y0;
261 cmsFloat32Number val2, rest;
263 cmsUInt32Number OutChan;
264 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
267 if (Value[0] == 1.0) {
268 Output[0] = LutTable[p -> Domain[0]];
272 val2 = p -> Domain[0] * Value[0];
274 cell0 = (int) floor(val2);
275 cell1 = (int) ceil(val2);
277 // Rest is 16 LSB bits
280 cell0 *= p -> opta[0];
281 cell1 *= p -> opta[0];
283 for (OutChan=0; OutChan < p->nOutputs; OutChan++) {
285 y0 = LutTable[cell0 + OutChan] ;
286 y1 = LutTable[cell1 + OutChan] ;
288 Output[OutChan] = y0 + (y1 - y0) * rest;
292 // Bilinear interpolation (16 bits) - cmsFloat32Number version
294 void BilinearInterpFloat(const cmsFloat32Number Input[],
295 cmsFloat32Number Output[],
296 const cmsInterpParams* p)
299 # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
300 # define DENS(i,j) (LutTable[(i)+(j)+OutChan])
302 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
303 cmsFloat32Number px, py;
306 int TotalOut, OutChan;
307 cmsFloat32Number fx, fy,
312 TotalOut = p -> nOutputs;
313 px = Input[0] * p->Domain[0];
314 py = Input[1] * p->Domain[1];
316 x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;
317 y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
319 X0 = p -> opta[1] * x0;
320 X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[1]);
322 Y0 = p -> opta[0] * y0;
323 Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[0]);
325 for (OutChan = 0; OutChan < TotalOut; OutChan++) {
332 dx0 = LERP(fx, d00, d10);
333 dx1 = LERP(fx, d01, d11);
335 dxy = LERP(fy, dx0, dx1);
337 Output[OutChan] = dxy;
345 // Bilinear interpolation (16 bits) - optimized version
347 void BilinearInterp16(register const cmsUInt16Number Input[],
348 register cmsUInt16Number Output[],
349 register const cmsInterpParams* p)
352 #define DENS(i,j) (LutTable[(i)+(j)+OutChan])
353 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
355 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
356 int OutChan, TotalOut;
357 cmsS15Fixed16Number fx, fy;
360 register int X0, X1, Y0, Y1;
361 int d00, d01, d10, d11,
365 TotalOut = p -> nOutputs;
367 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
368 x0 = FIXED_TO_INT(fx);
369 rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain
372 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
373 y0 = FIXED_TO_INT(fy);
374 ry = FIXED_REST_TO_INT(fy);
377 X0 = p -> opta[1] * x0;
378 X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]);
380 Y0 = p -> opta[0] * y0;
381 Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]);
383 for (OutChan = 0; OutChan < TotalOut; OutChan++) {
390 dx0 = LERP(rx, d00, d10);
391 dx1 = LERP(rx, d01, d11);
393 dxy = LERP(ry, dx0, dx1);
395 Output[OutChan] = (cmsUInt16Number) dxy;
404 // Trilinear interpolation (16 bits) - cmsFloat32Number version
406 void TrilinearInterpFloat(const cmsFloat32Number Input[],
407 cmsFloat32Number Output[],
408 const cmsInterpParams* p)
411 # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
412 # define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
414 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
415 cmsFloat32Number px, py, pz;
417 X0, Y0, Z0, X1, Y1, Z1;
418 int TotalOut, OutChan;
419 cmsFloat32Number fx, fy, fz,
420 d000, d001, d010, d011,
421 d100, d101, d110, d111,
422 dx00, dx01, dx10, dx11,
425 TotalOut = p -> nOutputs;
427 // We need some clipping here
443 x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;
444 y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
445 z0 = (int) _cmsQuickFloor(pz); fz = pz - (cmsFloat32Number) z0;
447 X0 = p -> opta[2] * x0;
448 X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]);
450 Y0 = p -> opta[1] * y0;
451 Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]);
453 Z0 = p -> opta[0] * z0;
454 Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]);
456 for (OutChan = 0; OutChan < TotalOut; OutChan++) {
458 d000 = DENS(X0, Y0, Z0);
459 d001 = DENS(X0, Y0, Z1);
460 d010 = DENS(X0, Y1, Z0);
461 d011 = DENS(X0, Y1, Z1);
463 d100 = DENS(X1, Y0, Z0);
464 d101 = DENS(X1, Y0, Z1);
465 d110 = DENS(X1, Y1, Z0);
466 d111 = DENS(X1, Y1, Z1);
469 dx00 = LERP(fx, d000, d100);
470 dx01 = LERP(fx, d001, d101);
471 dx10 = LERP(fx, d010, d110);
472 dx11 = LERP(fx, d011, d111);
474 dxy0 = LERP(fy, dx00, dx10);
475 dxy1 = LERP(fy, dx01, dx11);
477 dxyz = LERP(fz, dxy0, dxy1);
479 Output[OutChan] = dxyz;
487 // Trilinear interpolation (16 bits) - optimized version
489 void TrilinearInterp16(register const cmsUInt16Number Input[],
490 register cmsUInt16Number Output[],
491 register const cmsInterpParams* p)
494 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
495 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
497 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
498 int OutChan, TotalOut;
499 cmsS15Fixed16Number fx, fy, fz;
500 register int rx, ry, rz;
502 register int X0, X1, Y0, Y1, Z0, Z1;
503 int d000, d001, d010, d011,
504 d100, d101, d110, d111,
505 dx00, dx01, dx10, dx11,
508 TotalOut = p -> nOutputs;
510 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
511 x0 = FIXED_TO_INT(fx);
512 rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain
515 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
516 y0 = FIXED_TO_INT(fy);
517 ry = FIXED_REST_TO_INT(fy);
519 fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
520 z0 = FIXED_TO_INT(fz);
521 rz = FIXED_REST_TO_INT(fz);
524 X0 = p -> opta[2] * x0;
525 X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
527 Y0 = p -> opta[1] * y0;
528 Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
530 Z0 = p -> opta[0] * z0;
531 Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
533 for (OutChan = 0; OutChan < TotalOut; OutChan++) {
535 d000 = DENS(X0, Y0, Z0);
536 d001 = DENS(X0, Y0, Z1);
537 d010 = DENS(X0, Y1, Z0);
538 d011 = DENS(X0, Y1, Z1);
540 d100 = DENS(X1, Y0, Z0);
541 d101 = DENS(X1, Y0, Z1);
542 d110 = DENS(X1, Y1, Z0);
543 d111 = DENS(X1, Y1, Z1);
546 dx00 = LERP(rx, d000, d100);
547 dx01 = LERP(rx, d001, d101);
548 dx10 = LERP(rx, d010, d110);
549 dx11 = LERP(rx, d011, d111);
551 dxy0 = LERP(ry, dx00, dx10);
552 dxy1 = LERP(ry, dx01, dx11);
554 dxyz = LERP(rz, dxy0, dxy1);
556 Output[OutChan] = (cmsUInt16Number) dxyz;
565 // Tetrahedral interpolation, using Sakamoto algorithm.
566 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
568 void TetrahedralInterpFloat(const cmsFloat32Number Input[],
569 cmsFloat32Number Output[],
570 const cmsInterpParams* p)
572 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
573 cmsFloat32Number px, py, pz;
575 X0, Y0, Z0, X1, Y1, Z1;
576 cmsFloat32Number rx, ry, rz;
577 cmsFloat32Number c0, c1=0, c2=0, c3=0;
578 int OutChan, TotalOut;
580 TotalOut = p -> nOutputs;
582 // We need some clipping here
598 x0 = (int) _cmsQuickFloor(px); rx = (px - (cmsFloat32Number) x0);
599 y0 = (int) _cmsQuickFloor(py); ry = (py - (cmsFloat32Number) y0);
600 z0 = (int) _cmsQuickFloor(pz); rz = (pz - (cmsFloat32Number) z0);
603 X0 = p -> opta[2] * x0;
604 X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]);
606 Y0 = p -> opta[1] * y0;
607 Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]);
609 Z0 = p -> opta[0] * z0;
610 Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]);
612 for (OutChan=0; OutChan < TotalOut; OutChan++) {
614 // These are the 6 Tetrahedral
616 c0 = DENS(X0, Y0, Z0);
618 if (rx >= ry && ry >= rz) {
620 c1 = DENS(X1, Y0, Z0) - c0;
621 c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
622 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
626 if (rx >= rz && rz >= ry) {
628 c1 = DENS(X1, Y0, Z0) - c0;
629 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
630 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
634 if (rz >= rx && rx >= ry) {
636 c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
637 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
638 c3 = DENS(X0, Y0, Z1) - c0;
642 if (ry >= rx && rx >= rz) {
644 c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
645 c2 = DENS(X0, Y1, Z0) - c0;
646 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
650 if (ry >= rz && rz >= rx) {
652 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
653 c2 = DENS(X0, Y1, Z0) - c0;
654 c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
658 if (rz >= ry && ry >= rx) {
660 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
661 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
662 c3 = DENS(X0, Y0, Z1) - c0;
669 Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz;
678 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
681 void TetrahedralInterp16(register const cmsUInt16Number Input[],
682 register cmsUInt16Number Output[],
683 register const cmsInterpParams* p)
685 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;
686 cmsS15Fixed16Number fx, fy, fz;
687 cmsS15Fixed16Number rx, ry, rz;
689 cmsS15Fixed16Number c0, c1, c2, c3, Rest;
690 cmsUInt32Number OutChan;
691 cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
692 cmsUInt32Number TotalOut = p -> nOutputs;
695 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
696 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
697 fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
699 x0 = FIXED_TO_INT(fx);
700 y0 = FIXED_TO_INT(fy);
701 z0 = FIXED_TO_INT(fz);
703 rx = FIXED_REST_TO_INT(fx);
704 ry = FIXED_REST_TO_INT(fy);
705 rz = FIXED_REST_TO_INT(fz);
707 X0 = p -> opta[2] * x0;
708 X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
710 Y0 = p -> opta[1] * y0;
711 Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
713 Z0 = p -> opta[0] * z0;
714 Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
716 // These are the 6 Tetrahedral
717 for (OutChan=0; OutChan < TotalOut; OutChan++) {
719 c0 = DENS(X0, Y0, Z0);
721 if (rx >= ry && ry >= rz) {
723 c1 = DENS(X1, Y0, Z0) - c0;
724 c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
725 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
729 if (rx >= rz && rz >= ry) {
731 c1 = DENS(X1, Y0, Z0) - c0;
732 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
733 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
737 if (rz >= rx && rx >= ry) {
739 c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
740 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
741 c3 = DENS(X0, Y0, Z1) - c0;
745 if (ry >= rx && rx >= rz) {
747 c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
748 c2 = DENS(X0, Y1, Z0) - c0;
749 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
753 if (ry >= rz && rz >= rx) {
755 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
756 c2 = DENS(X0, Y1, Z0) - c0;
757 c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
761 if (rz >= ry && ry >= rx) {
763 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
764 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
765 c3 = DENS(X0, Y0, Z1) - c0;
772 Rest = c1 * rx + c2 * ry + c3 * rz;
774 Output[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
781 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
783 void Eval4Inputs(register const cmsUInt16Number Input[],
784 register cmsUInt16Number Output[],
785 register const cmsInterpParams* p16)
787 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
788 cmsS15Fixed16Number fk;
789 cmsS15Fixed16Number k0, rk;
791 cmsS15Fixed16Number fx, fy, fz;
792 cmsS15Fixed16Number rx, ry, rz;
794 cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
796 cmsS15Fixed16Number c0, c1, c2, c3, Rest;
797 cmsUInt32Number OutChan;
798 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
801 fk = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]);
802 fx = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]);
803 fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]);
804 fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]);
806 k0 = FIXED_TO_INT(fk);
807 x0 = FIXED_TO_INT(fx);
808 y0 = FIXED_TO_INT(fy);
809 z0 = FIXED_TO_INT(fz);
811 rk = FIXED_REST_TO_INT(fk);
812 rx = FIXED_REST_TO_INT(fx);
813 ry = FIXED_REST_TO_INT(fy);
814 rz = FIXED_REST_TO_INT(fz);
816 K0 = p16 -> opta[3] * k0;
817 K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]);
819 X0 = p16 -> opta[2] * x0;
820 X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]);
822 Y0 = p16 -> opta[1] * y0;
823 Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]);
825 Z0 = p16 -> opta[0] * z0;
826 Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]);
828 LutTable = (cmsUInt16Number*) p16 -> Table;
831 for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
833 c0 = DENS(X0, Y0, Z0);
835 if (rx >= ry && ry >= rz) {
837 c1 = DENS(X1, Y0, Z0) - c0;
838 c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
839 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
843 if (rx >= rz && rz >= ry) {
845 c1 = DENS(X1, Y0, Z0) - c0;
846 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
847 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
851 if (rz >= rx && rx >= ry) {
853 c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
854 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
855 c3 = DENS(X0, Y0, Z1) - c0;
859 if (ry >= rx && rx >= rz) {
861 c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
862 c2 = DENS(X0, Y1, Z0) - c0;
863 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
867 if (ry >= rz && rz >= rx) {
869 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
870 c2 = DENS(X0, Y1, Z0) - c0;
871 c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
875 if (rz >= ry && ry >= rx) {
877 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
878 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
879 c3 = DENS(X0, Y0, Z1) - c0;
886 Rest = c1 * rx + c2 * ry + c3 * rz;
888 Tmp1[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
892 LutTable = (cmsUInt16Number*) p16 -> Table;
895 for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
897 c0 = DENS(X0, Y0, Z0);
899 if (rx >= ry && ry >= rz) {
901 c1 = DENS(X1, Y0, Z0) - c0;
902 c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
903 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
907 if (rx >= rz && rz >= ry) {
909 c1 = DENS(X1, Y0, Z0) - c0;
910 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
911 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
915 if (rz >= rx && rx >= ry) {
917 c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
918 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
919 c3 = DENS(X0, Y0, Z1) - c0;
923 if (ry >= rx && rx >= rz) {
925 c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
926 c2 = DENS(X0, Y1, Z0) - c0;
927 c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
931 if (ry >= rz && rz >= rx) {
933 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
934 c2 = DENS(X0, Y1, Z0) - c0;
935 c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
939 if (rz >= ry && ry >= rx) {
941 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
942 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
943 c3 = DENS(X0, Y0, Z1) - c0;
950 Rest = c1 * rx + c2 * ry + c3 * rz;
952 Tmp2[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest));
957 for (i=0; i < p16 -> nOutputs; i++) {
958 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
964 // For more that 3 inputs (i.e., CMYK)
965 // evaluate two 3-dimensional interpolations and then linearly interpolate between them.
969 void Eval4InputsFloat(const cmsFloat32Number Input[],
970 cmsFloat32Number Output[],
971 const cmsInterpParams* p)
973 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
974 cmsFloat32Number rest;
977 const cmsFloat32Number* T;
979 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
983 pk = Input[0] * p->Domain[0];
984 k0 = _cmsQuickFloor(pk);
985 rest = pk - (cmsFloat32Number) k0;
987 K0 = p -> opta[3] * k0;
988 K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[3]);
991 memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number));
996 TetrahedralInterpFloat(Input + 1, Tmp1, &p1);
1000 TetrahedralInterpFloat(Input + 1, Tmp2, &p1);
1002 for (i=0; i < p -> nOutputs; i++)
1004 cmsFloat32Number y0 = Tmp1[i];
1005 cmsFloat32Number y1 = Tmp2[i];
1007 Output[i] = y0 + (y1 - y0) * rest;
1013 void Eval5Inputs(register const cmsUInt16Number Input[],
1014 register cmsUInt16Number Output[],
1016 register const cmsInterpParams* p16)
1018 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1019 cmsS15Fixed16Number fk;
1020 cmsS15Fixed16Number k0, rk;
1022 const cmsUInt16Number* T;
1024 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1028 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1029 k0 = FIXED_TO_INT(fk);
1030 rk = FIXED_REST_TO_INT(fk);
1032 K0 = p16 -> opta[4] * k0;
1033 K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1036 memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number));
1041 Eval4Inputs(Input + 1, Tmp1, &p1);
1046 Eval4Inputs(Input + 1, Tmp2, &p1);
1048 for (i=0; i < p16 -> nOutputs; i++) {
1050 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1057 void Eval5InputsFloat(const cmsFloat32Number Input[],
1058 cmsFloat32Number Output[],
1059 const cmsInterpParams* p)
1061 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1062 cmsFloat32Number rest;
1063 cmsFloat32Number pk;
1065 const cmsFloat32Number* T;
1067 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1070 pk = Input[0] * p->Domain[0];
1071 k0 = _cmsQuickFloor(pk);
1072 rest = pk - (cmsFloat32Number) k0;
1074 K0 = p -> opta[4] * k0;
1075 K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[4]);
1078 memmove(&p1.Domain[0], &p ->Domain[1], 4*sizeof(cmsUInt32Number));
1083 Eval4InputsFloat(Input + 1, Tmp1, &p1);
1088 Eval4InputsFloat(Input + 1, Tmp2, &p1);
1090 for (i=0; i < p -> nOutputs; i++) {
1092 cmsFloat32Number y0 = Tmp1[i];
1093 cmsFloat32Number y1 = Tmp2[i];
1095 Output[i] = y0 + (y1 - y0) * rest;
1102 void Eval6Inputs(register const cmsUInt16Number Input[],
1103 register cmsUInt16Number Output[],
1104 register const cmsInterpParams* p16)
1106 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1107 cmsS15Fixed16Number fk;
1108 cmsS15Fixed16Number k0, rk;
1110 const cmsUInt16Number* T;
1112 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1115 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1116 k0 = FIXED_TO_INT(fk);
1117 rk = FIXED_REST_TO_INT(fk);
1119 K0 = p16 -> opta[5] * k0;
1120 K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1123 memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number));
1128 Eval5Inputs(Input + 1, Tmp1, &p1);
1133 Eval5Inputs(Input + 1, Tmp2, &p1);
1135 for (i=0; i < p16 -> nOutputs; i++) {
1137 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1144 void Eval6InputsFloat(const cmsFloat32Number Input[],
1145 cmsFloat32Number Output[],
1146 const cmsInterpParams* p)
1148 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1149 cmsFloat32Number rest;
1150 cmsFloat32Number pk;
1152 const cmsFloat32Number* T;
1154 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1157 pk = Input[0] * p->Domain[0];
1158 k0 = _cmsQuickFloor(pk);
1159 rest = pk - (cmsFloat32Number) k0;
1161 K0 = p -> opta[5] * k0;
1162 K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[5]);
1165 memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number));
1170 Eval5InputsFloat(Input + 1, Tmp1, &p1);
1175 Eval5InputsFloat(Input + 1, Tmp2, &p1);
1177 for (i=0; i < p -> nOutputs; i++) {
1179 cmsFloat32Number y0 = Tmp1[i];
1180 cmsFloat32Number y1 = Tmp2[i];
1182 Output[i] = y0 + (y1 - y0) * rest;
1188 void Eval7Inputs(register const cmsUInt16Number Input[],
1189 register cmsUInt16Number Output[],
1190 register const cmsInterpParams* p16)
1192 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1193 cmsS15Fixed16Number fk;
1194 cmsS15Fixed16Number k0, rk;
1196 const cmsUInt16Number* T;
1198 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1202 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1203 k0 = FIXED_TO_INT(fk);
1204 rk = FIXED_REST_TO_INT(fk);
1206 K0 = p16 -> opta[6] * k0;
1207 K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1210 memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number));
1215 Eval6Inputs(Input + 1, Tmp1, &p1);
1220 Eval6Inputs(Input + 1, Tmp2, &p1);
1222 for (i=0; i < p16 -> nOutputs; i++) {
1223 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1229 void Eval7InputsFloat(const cmsFloat32Number Input[],
1230 cmsFloat32Number Output[],
1231 const cmsInterpParams* p)
1233 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1234 cmsFloat32Number rest;
1235 cmsFloat32Number pk;
1237 const cmsFloat32Number* T;
1239 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1242 pk = Input[0] * p->Domain[0];
1243 k0 = _cmsQuickFloor(pk);
1244 rest = pk - (cmsFloat32Number) k0;
1246 K0 = p -> opta[6] * k0;
1247 K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[6]);
1250 memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number));
1255 Eval6InputsFloat(Input + 1, Tmp1, &p1);
1260 Eval6InputsFloat(Input + 1, Tmp2, &p1);
1263 for (i=0; i < p -> nOutputs; i++) {
1265 cmsFloat32Number y0 = Tmp1[i];
1266 cmsFloat32Number y1 = Tmp2[i];
1268 Output[i] = y0 + (y1 - y0) * rest;
1274 void Eval8Inputs(register const cmsUInt16Number Input[],
1275 register cmsUInt16Number Output[],
1276 register const cmsInterpParams* p16)
1278 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1279 cmsS15Fixed16Number fk;
1280 cmsS15Fixed16Number k0, rk;
1282 const cmsUInt16Number* T;
1284 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1287 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1288 k0 = FIXED_TO_INT(fk);
1289 rk = FIXED_REST_TO_INT(fk);
1291 K0 = p16 -> opta[7] * k0;
1292 K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1295 memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number));
1300 Eval7Inputs(Input + 1, Tmp1, &p1);
1304 Eval7Inputs(Input + 1, Tmp2, &p1);
1306 for (i=0; i < p16 -> nOutputs; i++) {
1307 Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1314 void Eval8InputsFloat(const cmsFloat32Number Input[],
1315 cmsFloat32Number Output[],
1316 const cmsInterpParams* p)
1318 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1319 cmsFloat32Number rest;
1320 cmsFloat32Number pk;
1322 const cmsFloat32Number* T;
1324 cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1327 pk = Input[0] * p->Domain[0];
1328 k0 = _cmsQuickFloor(pk);
1329 rest = pk - (cmsFloat32Number) k0;
1331 K0 = p -> opta[7] * k0;
1332 K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[7]);
1335 memmove(&p1.Domain[0], &p ->Domain[1], 7*sizeof(cmsUInt32Number));
1340 Eval7InputsFloat(Input + 1, Tmp1, &p1);
1345 Eval7InputsFloat(Input + 1, Tmp2, &p1);
1348 for (i=0; i < p -> nOutputs; i++) {
1350 cmsFloat32Number y0 = Tmp1[i];
1351 cmsFloat32Number y1 = Tmp2[i];
1353 Output[i] = y0 + (y1 - y0) * rest;
1357 // The default factory
1359 cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags)
1362 cmsInterpFunction Interpolation;
1363 cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT);
1364 cmsBool IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR);
1366 memset(&Interpolation, 0, sizeof(Interpolation));
1369 if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS)
1370 return Interpolation;
1372 switch (nInputChannels) {
1374 case 1: // Gray LUT / linear
1376 if (nOutputChannels == 1) {
1379 Interpolation.LerpFloat = LinLerp1Dfloat;
1381 Interpolation.Lerp16 = LinLerp1D;
1387 Interpolation.LerpFloat = Eval1InputFloat;
1389 Interpolation.Lerp16 = Eval1Input;
1395 Interpolation.LerpFloat = BilinearInterpFloat;
1397 Interpolation.Lerp16 = BilinearInterp16;
1400 case 3: // RGB et al
1405 Interpolation.LerpFloat = TrilinearInterpFloat;
1407 Interpolation.Lerp16 = TrilinearInterp16;
1412 Interpolation.LerpFloat = TetrahedralInterpFloat;
1415 Interpolation.Lerp16 = TetrahedralInterp16;
1423 Interpolation.LerpFloat = Eval4InputsFloat;
1425 Interpolation.Lerp16 = Eval4Inputs;
1430 Interpolation.LerpFloat = Eval5InputsFloat;
1432 Interpolation.Lerp16 = Eval5Inputs;
1437 Interpolation.LerpFloat = Eval6InputsFloat;
1439 Interpolation.Lerp16 = Eval6Inputs;
1444 Interpolation.LerpFloat = Eval7InputsFloat;
1446 Interpolation.Lerp16 = Eval7Inputs;
1451 Interpolation.LerpFloat = Eval8InputsFloat;
1453 Interpolation.Lerp16 = Eval8Inputs;
1459 Interpolation.Lerp16 = NULL;
1462 return Interpolation;