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