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