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-2017 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 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(register const cmsUInt16Number Value[],register cmsUInt16Number Output[],register const cmsInterpParams * p)223 void LinLerp1D(register const cmsUInt16Number Value[],
224                register cmsUInt16Number Output[],
225                register 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         return;
237     }
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 
249     Output[0] = LinearInterp(rest, y0, y1);
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            return;
275        }
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 // Eval gray LUT having only one input channel
294 static
Eval1Input(register const cmsUInt16Number Input[],register cmsUInt16Number Output[],register const cmsInterpParams * p16)295 void Eval1Input(register const cmsUInt16Number Input[],
296                 register cmsUInt16Number Output[],
297                 register const cmsInterpParams* p16)
298 {
299        cmsS15Fixed16Number fk;
300        cmsS15Fixed16Number k0, k1, rk, K0, K1;
301        int v;
302        cmsUInt32Number OutChan;
303        const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
304 
305        v = Input[0] * p16 -> Domain[0];
306        fk = _cmsToFixedDomain(v);
307 
308        k0 = FIXED_TO_INT(fk);
309        rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
310 
311        k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
312 
313        K0 = p16 -> opta[0] * k0;
314        K1 = p16 -> opta[0] * k1;
315 
316        for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
317 
318            Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]);
319        }
320 }
321 
322 
323 
324 // Eval gray LUT having only one input channel
325 static
Eval1InputFloat(const cmsFloat32Number Value[],cmsFloat32Number Output[],const cmsInterpParams * p)326 void Eval1InputFloat(const cmsFloat32Number Value[],
327                      cmsFloat32Number Output[],
328                      const cmsInterpParams* p)
329 {
330     cmsFloat32Number y1, y0;
331     cmsFloat32Number val2, rest;
332     int cell0, cell1;
333     cmsUInt32Number OutChan;
334     const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
335 
336     val2 = fclamp(Value[0]);
337 
338         // if last value...
339        if (val2 == 1.0) {
340            Output[0] = LutTable[p -> Domain[0]];
341            return;
342        }
343 
344        val2 *= p -> Domain[0];
345 
346        cell0 = (int) floor(val2);
347        cell1 = (int) ceil(val2);
348 
349        // Rest is 16 LSB bits
350        rest = val2 - cell0;
351 
352        cell0 *= p -> opta[0];
353        cell1 *= p -> opta[0];
354 
355        for (OutChan=0; OutChan < p->nOutputs; OutChan++) {
356 
357             y0 = LutTable[cell0 + OutChan] ;
358             y1 = LutTable[cell1 + OutChan] ;
359 
360             Output[OutChan] = y0 + (y1 - y0) * rest;
361        }
362 }
363 
364 // Bilinear interpolation (16 bits) - cmsFloat32Number version
365 static
BilinearInterpFloat(const cmsFloat32Number Input[],cmsFloat32Number Output[],const cmsInterpParams * p)366 void BilinearInterpFloat(const cmsFloat32Number Input[],
367                          cmsFloat32Number Output[],
368                          const cmsInterpParams* p)
369 
370 {
371 #   define LERP(a,l,h)    (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
372 #   define DENS(i,j)      (LutTable[(i)+(j)+OutChan])
373 
374     const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
375     cmsFloat32Number      px, py;
376     int        x0, y0,
377                X0, Y0, X1, Y1;
378     int        TotalOut, OutChan;
379     cmsFloat32Number      fx, fy,
380         d00, d01, d10, d11,
381         dx0, dx1,
382         dxy;
383 
384     TotalOut   = p -> nOutputs;
385     px = fclamp(Input[0]) * p->Domain[0];
386     py = fclamp(Input[1]) * p->Domain[1];
387 
388     x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;
389     y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
390 
391     X0 = p -> opta[1] * x0;
392     X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[1]);
393 
394     Y0 = p -> opta[0] * y0;
395     Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[0]);
396 
397     for (OutChan = 0; OutChan < TotalOut; OutChan++) {
398 
399         d00 = DENS(X0, Y0);
400         d01 = DENS(X0, Y1);
401         d10 = DENS(X1, Y0);
402         d11 = DENS(X1, Y1);
403 
404         dx0 = LERP(fx, d00, d10);
405         dx1 = LERP(fx, d01, d11);
406 
407         dxy = LERP(fy, dx0, dx1);
408 
409         Output[OutChan] = dxy;
410     }
411 
412 
413 #   undef LERP
414 #   undef DENS
415 }
416 
417 // Bilinear interpolation (16 bits) - optimized version
418 static
BilinearInterp16(register const cmsUInt16Number Input[],register cmsUInt16Number Output[],register const cmsInterpParams * p)419 void BilinearInterp16(register const cmsUInt16Number Input[],
420                       register cmsUInt16Number Output[],
421                       register const cmsInterpParams* p)
422 
423 {
424 #define DENS(i,j) (LutTable[(i)+(j)+OutChan])
425 #define LERP(a,l,h)     (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
426 
427            const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
428            int        OutChan, TotalOut;
429            cmsS15Fixed16Number    fx, fy;
430   register int        rx, ry;
431            int        x0, y0;
432   register int        X0, X1, Y0, Y1;
433            int        d00, d01, d10, d11,
434                       dx0, dx1,
435                       dxy;
436 
437     TotalOut   = p -> nOutputs;
438 
439     fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
440     x0  = FIXED_TO_INT(fx);
441     rx  = FIXED_REST_TO_INT(fx);    // Rest in 0..1.0 domain
442 
443 
444     fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
445     y0  = FIXED_TO_INT(fy);
446     ry  = FIXED_REST_TO_INT(fy);
447 
448 
449     X0 = p -> opta[1] * x0;
450     X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]);
451 
452     Y0 = p -> opta[0] * y0;
453     Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]);
454 
455     for (OutChan = 0; OutChan < TotalOut; OutChan++) {
456 
457         d00 = DENS(X0, Y0);
458         d01 = DENS(X0, Y1);
459         d10 = DENS(X1, Y0);
460         d11 = DENS(X1, Y1);
461 
462         dx0 = LERP(rx, d00, d10);
463         dx1 = LERP(rx, d01, d11);
464 
465         dxy = LERP(ry, dx0, dx1);
466 
467         Output[OutChan] = (cmsUInt16Number) dxy;
468     }
469 
470 
471 #   undef LERP
472 #   undef DENS
473 }
474 
475 
476 // Trilinear interpolation (16 bits) - cmsFloat32Number version
477 static
TrilinearInterpFloat(const cmsFloat32Number Input[],cmsFloat32Number Output[],const cmsInterpParams * p)478 void TrilinearInterpFloat(const cmsFloat32Number Input[],
479                           cmsFloat32Number Output[],
480                           const cmsInterpParams* p)
481 
482 {
483 #   define LERP(a,l,h)      (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
484 #   define DENS(i,j,k)      (LutTable[(i)+(j)+(k)+OutChan])
485 
486     const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
487     cmsFloat32Number      px, py, pz;
488     int        x0, y0, z0,
489                X0, Y0, Z0, X1, Y1, Z1;
490     int        TotalOut, OutChan;
491     cmsFloat32Number      fx, fy, fz,
492         d000, d001, d010, d011,
493         d100, d101, d110, d111,
494         dx00, dx01, dx10, dx11,
495         dxy0, dxy1, dxyz;
496 
497     TotalOut   = p -> nOutputs;
498 
499     // We need some clipping here
500     px = fclamp(Input[0]) * p->Domain[0];
501     py = fclamp(Input[1]) * p->Domain[1];
502     pz = fclamp(Input[2]) * p->Domain[2];
503 
504     x0 = (int) floor(px); fx = px - (cmsFloat32Number) x0;  // We need full floor funcionality here
505     y0 = (int) floor(py); fy = py - (cmsFloat32Number) y0;
506     z0 = (int) floor(pz); fz = pz - (cmsFloat32Number) z0;
507 
508     X0 = p -> opta[2] * x0;
509     X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);
510 
511     Y0 = p -> opta[1] * y0;
512     Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);
513 
514     Z0 = p -> opta[0] * z0;
515     Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);
516 
517     for (OutChan = 0; OutChan < TotalOut; OutChan++) {
518 
519         d000 = DENS(X0, Y0, Z0);
520         d001 = DENS(X0, Y0, Z1);
521         d010 = DENS(X0, Y1, Z0);
522         d011 = DENS(X0, Y1, Z1);
523 
524         d100 = DENS(X1, Y0, Z0);
525         d101 = DENS(X1, Y0, Z1);
526         d110 = DENS(X1, Y1, Z0);
527         d111 = DENS(X1, Y1, Z1);
528 
529 
530         dx00 = LERP(fx, d000, d100);
531         dx01 = LERP(fx, d001, d101);
532         dx10 = LERP(fx, d010, d110);
533         dx11 = LERP(fx, d011, d111);
534 
535         dxy0 = LERP(fy, dx00, dx10);
536         dxy1 = LERP(fy, dx01, dx11);
537 
538         dxyz = LERP(fz, dxy0, dxy1);
539 
540         Output[OutChan] = dxyz;
541     }
542 
543 
544 #   undef LERP
545 #   undef DENS
546 }
547 
548 // Trilinear interpolation (16 bits) - optimized version
549 static
TrilinearInterp16(register const cmsUInt16Number Input[],register cmsUInt16Number Output[],register const cmsInterpParams * p)550 void TrilinearInterp16(register const cmsUInt16Number Input[],
551                        register cmsUInt16Number Output[],
552                        register const cmsInterpParams* p)
553 
554 {
555 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
556 #define LERP(a,l,h)     (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
557 
558            const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
559            int        OutChan, TotalOut;
560            cmsS15Fixed16Number    fx, fy, fz;
561   register int        rx, ry, rz;
562            int        x0, y0, z0;
563   register int        X0, X1, Y0, Y1, Z0, Z1;
564            int        d000, d001, d010, d011,
565                       d100, d101, d110, d111,
566                       dx00, dx01, dx10, dx11,
567                       dxy0, dxy1, dxyz;
568 
569     TotalOut   = p -> nOutputs;
570 
571     fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
572     x0  = FIXED_TO_INT(fx);
573     rx  = FIXED_REST_TO_INT(fx);    // Rest in 0..1.0 domain
574 
575 
576     fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
577     y0  = FIXED_TO_INT(fy);
578     ry  = FIXED_REST_TO_INT(fy);
579 
580     fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
581     z0 = FIXED_TO_INT(fz);
582     rz = FIXED_REST_TO_INT(fz);
583 
584 
585     X0 = p -> opta[2] * x0;
586     X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
587 
588     Y0 = p -> opta[1] * y0;
589     Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
590 
591     Z0 = p -> opta[0] * z0;
592     Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
593 
594     for (OutChan = 0; OutChan < TotalOut; OutChan++) {
595 
596         d000 = DENS(X0, Y0, Z0);
597         d001 = DENS(X0, Y0, Z1);
598         d010 = DENS(X0, Y1, Z0);
599         d011 = DENS(X0, Y1, Z1);
600 
601         d100 = DENS(X1, Y0, Z0);
602         d101 = DENS(X1, Y0, Z1);
603         d110 = DENS(X1, Y1, Z0);
604         d111 = DENS(X1, Y1, Z1);
605 
606 
607         dx00 = LERP(rx, d000, d100);
608         dx01 = LERP(rx, d001, d101);
609         dx10 = LERP(rx, d010, d110);
610         dx11 = LERP(rx, d011, d111);
611 
612         dxy0 = LERP(ry, dx00, dx10);
613         dxy1 = LERP(ry, dx01, dx11);
614 
615         dxyz = LERP(rz, dxy0, dxy1);
616 
617         Output[OutChan] = (cmsUInt16Number) dxyz;
618     }
619 
620 
621 #   undef LERP
622 #   undef DENS
623 }
624 
625 
626 // Tetrahedral interpolation, using Sakamoto algorithm.
627 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
628 static
TetrahedralInterpFloat(const cmsFloat32Number Input[],cmsFloat32Number Output[],const cmsInterpParams * p)629 void TetrahedralInterpFloat(const cmsFloat32Number Input[],
630                             cmsFloat32Number Output[],
631                             const cmsInterpParams* p)
632 {
633     const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
634     cmsFloat32Number     px, py, pz;
635     int        x0, y0, z0,
636                X0, Y0, Z0, X1, Y1, Z1;
637     cmsFloat32Number     rx, ry, rz;
638     cmsFloat32Number     c0, c1=0, c2=0, c3=0;
639     int                  OutChan, TotalOut;
640 
641     TotalOut   = p -> nOutputs;
642 
643     // We need some clipping here
644     px = fclamp(Input[0]) * p->Domain[0];
645     py = fclamp(Input[1]) * p->Domain[1];
646     pz = fclamp(Input[2]) * p->Domain[2];
647 
648     x0 = (int) floor(px); rx = (px - (cmsFloat32Number) x0);  // We need full floor functionality here
649     y0 = (int) floor(py); ry = (py - (cmsFloat32Number) y0);
650     z0 = (int) floor(pz); rz = (pz - (cmsFloat32Number) z0);
651 
652 
653     X0 = p -> opta[2] * x0;
654     X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);
655 
656     Y0 = p -> opta[1] * y0;
657     Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);
658 
659     Z0 = p -> opta[0] * z0;
660     Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);
661 
662     for (OutChan=0; OutChan < TotalOut; OutChan++) {
663 
664        // These are the 6 Tetrahedral
665 
666         c0 = DENS(X0, Y0, Z0);
667 
668         if (rx >= ry && ry >= rz) {
669 
670             c1 = DENS(X1, Y0, Z0) - c0;
671             c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
672             c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
673 
674         }
675         else
676             if (rx >= rz && rz >= ry) {
677 
678                 c1 = DENS(X1, Y0, Z0) - c0;
679                 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
680                 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
681 
682             }
683             else
684                 if (rz >= rx && rx >= ry) {
685 
686                     c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
687                     c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
688                     c3 = DENS(X0, Y0, Z1) - c0;
689 
690                 }
691                 else
692                     if (ry >= rx && rx >= rz) {
693 
694                         c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
695                         c2 = DENS(X0, Y1, Z0) - c0;
696                         c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
697 
698                     }
699                     else
700                         if (ry >= rz && rz >= rx) {
701 
702                             c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
703                             c2 = DENS(X0, Y1, Z0) - c0;
704                             c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
705 
706                         }
707                         else
708                             if (rz >= ry && ry >= rx) {
709 
710                                 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
711                                 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
712                                 c3 = DENS(X0, Y0, Z1) - c0;
713 
714                             }
715                             else  {
716                                 c1 = c2 = c3 = 0;
717                             }
718 
719        Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz;
720        }
721 
722 }
723 
724 #undef DENS
725 
726 
727 
728 
729 static
TetrahedralInterp16(register const cmsUInt16Number Input[],register cmsUInt16Number Output[],register const cmsInterpParams * p)730 void TetrahedralInterp16(register const cmsUInt16Number Input[],
731                          register cmsUInt16Number Output[],
732                          register const cmsInterpParams* p)
733 {
734     const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;
735     cmsS15Fixed16Number fx, fy, fz;
736     cmsS15Fixed16Number rx, ry, rz;
737     int x0, y0, z0;
738     cmsS15Fixed16Number c0, c1, c2, c3, Rest;
739     cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
740     cmsUInt32Number TotalOut = p -> nOutputs;
741 
742     fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
743     fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
744     fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
745 
746     x0 = FIXED_TO_INT(fx);
747     y0 = FIXED_TO_INT(fy);
748     z0 = FIXED_TO_INT(fz);
749 
750     rx = FIXED_REST_TO_INT(fx);
751     ry = FIXED_REST_TO_INT(fy);
752     rz = FIXED_REST_TO_INT(fz);
753 
754     X0 = p -> opta[2] * x0;
755     X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
756 
757     Y0 = p -> opta[1] * y0;
758     Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
759 
760     Z0 = p -> opta[0] * z0;
761     Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
762 
763     LutTable = &LutTable[X0+Y0+Z0];
764 
765     // Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))
766     // which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16
767     // This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16
768     // at the cost of being off by one at 7fff and 17ffe.
769 
770     if (rx >= ry) {
771         if (ry >= rz) {
772             Y1 += X1;
773             Z1 += Y1;
774             for (; TotalOut; TotalOut--) {
775                 c1 = LutTable[X1];
776                 c2 = LutTable[Y1];
777                 c3 = LutTable[Z1];
778                 c0 = *LutTable++;
779                 c3 -= c2;
780                 c2 -= c1;
781                 c1 -= c0;
782                 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
783                 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
784             }
785         } else if (rz >= rx) {
786             X1 += Z1;
787             Y1 += X1;
788             for (; TotalOut; TotalOut--) {
789                 c1 = LutTable[X1];
790                 c2 = LutTable[Y1];
791                 c3 = LutTable[Z1];
792                 c0 = *LutTable++;
793                 c2 -= c1;
794                 c1 -= c3;
795                 c3 -= c0;
796                 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
797                 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
798             }
799         } else {
800             Z1 += X1;
801             Y1 += Z1;
802             for (; TotalOut; TotalOut--) {
803                 c1 = LutTable[X1];
804                 c2 = LutTable[Y1];
805                 c3 = LutTable[Z1];
806                 c0 = *LutTable++;
807                 c2 -= c3;
808                 c3 -= c1;
809                 c1 -= c0;
810                 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
811                 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
812             }
813         }
814     } else {
815         if (rx >= rz) {
816             X1 += Y1;
817             Z1 += X1;
818             for (; TotalOut; TotalOut--) {
819                 c1 = LutTable[X1];
820                 c2 = LutTable[Y1];
821                 c3 = LutTable[Z1];
822                 c0 = *LutTable++;
823                 c3 -= c1;
824                 c1 -= c2;
825                 c2 -= c0;
826                 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
827                 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
828             }
829         } else if (ry >= rz) {
830             Z1 += Y1;
831             X1 += Z1;
832             for (; TotalOut; TotalOut--) {
833                 c1 = LutTable[X1];
834                 c2 = LutTable[Y1];
835                 c3 = LutTable[Z1];
836                 c0 = *LutTable++;
837                 c1 -= c3;
838                 c3 -= c2;
839                 c2 -= c0;
840                 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
841                 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
842             }
843         } else {
844             Y1 += Z1;
845             X1 += Y1;
846             for (; TotalOut; TotalOut--) {
847                 c1 = LutTable[X1];
848                 c2 = LutTable[Y1];
849                 c3 = LutTable[Z1];
850                 c0 = *LutTable++;
851                 c1 -= c2;
852                 c2 -= c3;
853                 c3 -= c0;
854                 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
855                 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
856             }
857         }
858     }
859 }
860 
861 
862 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
863 static
Eval4Inputs(register const cmsUInt16Number Input[],register cmsUInt16Number Output[],register const cmsInterpParams * p16)864 void Eval4Inputs(register const cmsUInt16Number Input[],
865                      register cmsUInt16Number Output[],
866                      register const cmsInterpParams* p16)
867 {
868     const cmsUInt16Number* LutTable;
869     cmsS15Fixed16Number fk;
870     cmsS15Fixed16Number k0, rk;
871     int K0, K1;
872     cmsS15Fixed16Number    fx, fy, fz;
873     cmsS15Fixed16Number    rx, ry, rz;
874     int                    x0, y0, z0;
875     cmsS15Fixed16Number    X0, X1, Y0, Y1, Z0, Z1;
876     cmsUInt32Number i;
877     cmsS15Fixed16Number    c0, c1, c2, c3, Rest;
878     cmsUInt32Number        OutChan;
879     cmsUInt16Number        Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
880 
881 
882     fk  = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]);
883     fx  = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]);
884     fy  = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]);
885     fz  = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]);
886 
887     k0  = FIXED_TO_INT(fk);
888     x0  = FIXED_TO_INT(fx);
889     y0  = FIXED_TO_INT(fy);
890     z0  = FIXED_TO_INT(fz);
891 
892     rk  = FIXED_REST_TO_INT(fk);
893     rx  = FIXED_REST_TO_INT(fx);
894     ry  = FIXED_REST_TO_INT(fy);
895     rz  = FIXED_REST_TO_INT(fz);
896 
897     K0 = p16 -> opta[3] * k0;
898     K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]);
899 
900     X0 = p16 -> opta[2] * x0;
901     X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]);
902 
903     Y0 = p16 -> opta[1] * y0;
904     Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]);
905 
906     Z0 = p16 -> opta[0] * z0;
907     Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]);
908 
909     LutTable = (cmsUInt16Number*) p16 -> Table;
910     LutTable += K0;
911 
912     for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
913 
914         c0 = DENS(X0, Y0, Z0);
915 
916         if (rx >= ry && ry >= rz) {
917 
918             c1 = DENS(X1, Y0, Z0) - c0;
919             c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
920             c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
921 
922         }
923         else
924             if (rx >= rz && rz >= ry) {
925 
926                 c1 = DENS(X1, Y0, Z0) - c0;
927                 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
928                 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
929 
930             }
931             else
932                 if (rz >= rx && rx >= ry) {
933 
934                     c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
935                     c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
936                     c3 = DENS(X0, Y0, Z1) - c0;
937 
938                 }
939                 else
940                     if (ry >= rx && rx >= rz) {
941 
942                         c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
943                         c2 = DENS(X0, Y1, Z0) - c0;
944                         c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
945 
946                     }
947                     else
948                         if (ry >= rz && rz >= rx) {
949 
950                             c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
951                             c2 = DENS(X0, Y1, Z0) - c0;
952                             c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
953 
954                         }
955                         else
956                             if (rz >= ry && ry >= rx) {
957 
958                                 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
959                                 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
960                                 c3 = DENS(X0, Y0, Z1) - c0;
961 
962                             }
963                             else {
964                                 c1 = c2 = c3 = 0;
965                             }
966 
967                             Rest = c1 * rx + c2 * ry + c3 * rz;
968 
969                             Tmp1[OutChan] = (cmsUInt16Number)(c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
970     }
971 
972 
973     LutTable = (cmsUInt16Number*) p16 -> Table;
974     LutTable += K1;
975 
976     for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
977 
978         c0 = DENS(X0, Y0, Z0);
979 
980         if (rx >= ry && ry >= rz) {
981 
982             c1 = DENS(X1, Y0, Z0) - c0;
983             c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
984             c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
985 
986         }
987         else
988             if (rx >= rz && rz >= ry) {
989 
990                 c1 = DENS(X1, Y0, Z0) - c0;
991                 c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
992                 c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
993 
994             }
995             else
996                 if (rz >= rx && rx >= ry) {
997 
998                     c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
999                     c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
1000                     c3 = DENS(X0, Y0, Z1) - c0;
1001 
1002                 }
1003                 else
1004                     if (ry >= rx && rx >= rz) {
1005 
1006                         c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
1007                         c2 = DENS(X0, Y1, Z0) - c0;
1008                         c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
1009 
1010                     }
1011                     else
1012                         if (ry >= rz && rz >= rx) {
1013 
1014                             c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
1015                             c2 = DENS(X0, Y1, Z0) - c0;
1016                             c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
1017 
1018                         }
1019                         else
1020                             if (rz >= ry && ry >= rx) {
1021 
1022                                 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
1023                                 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
1024                                 c3 = DENS(X0, Y0, Z1) - c0;
1025 
1026                             }
1027                             else  {
1028                                 c1 = c2 = c3 = 0;
1029                             }
1030 
1031                             Rest = c1 * rx + c2 * ry + c3 * rz;
1032 
1033                             Tmp2[OutChan] = (cmsUInt16Number) (c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
1034     }
1035 
1036 
1037 
1038     for (i=0; i < p16 -> nOutputs; i++) {
1039         Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1040     }
1041 }
1042 #undef DENS
1043 
1044 
1045 // For more that 3 inputs (i.e., CMYK)
1046 // evaluate two 3-dimensional interpolations and then linearly interpolate between them.
1047 
1048 
1049 static
Eval4InputsFloat(const cmsFloat32Number Input[],cmsFloat32Number Output[],const cmsInterpParams * p)1050 void Eval4InputsFloat(const cmsFloat32Number Input[],
1051                       cmsFloat32Number Output[],
1052                       const cmsInterpParams* p)
1053 {
1054        const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1055        cmsFloat32Number rest;
1056        cmsFloat32Number pk;
1057        int k0, K0, K1;
1058        const cmsFloat32Number* T;
1059        cmsUInt32Number i;
1060        cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1061        cmsInterpParams p1;
1062 
1063        pk = fclamp(Input[0]) * p->Domain[0];
1064        k0 = _cmsQuickFloor(pk);
1065        rest = pk - (cmsFloat32Number) k0;
1066 
1067        K0 = p -> opta[3] * k0;
1068        K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[3]);
1069 
1070        p1 = *p;
1071        memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number));
1072 
1073        T = LutTable + K0;
1074        p1.Table = T;
1075 
1076        TetrahedralInterpFloat(Input + 1,  Tmp1, &p1);
1077 
1078        T = LutTable + K1;
1079        p1.Table = T;
1080        TetrahedralInterpFloat(Input + 1,  Tmp2, &p1);
1081 
1082        for (i=0; i < p -> nOutputs; i++)
1083        {
1084               cmsFloat32Number y0 = Tmp1[i];
1085               cmsFloat32Number y1 = Tmp2[i];
1086 
1087               Output[i] = y0 + (y1 - y0) * rest;
1088        }
1089 }
1090 
1091 
1092 static
Eval5Inputs(register const cmsUInt16Number Input[],register cmsUInt16Number Output[],register const cmsInterpParams * p16)1093 void Eval5Inputs(register const cmsUInt16Number Input[],
1094                  register cmsUInt16Number Output[],
1095 
1096                  register 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 
1108        fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1109        k0 = FIXED_TO_INT(fk);
1110        rk = FIXED_REST_TO_INT(fk);
1111 
1112        K0 = p16 -> opta[4] * k0;
1113        K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1114 
1115        p1 = *p16;
1116        memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number));
1117 
1118        T = LutTable + K0;
1119        p1.Table = T;
1120 
1121        Eval4Inputs(Input + 1, Tmp1, &p1);
1122 
1123        T = LutTable + K1;
1124        p1.Table = T;
1125 
1126        Eval4Inputs(Input + 1, Tmp2, &p1);
1127 
1128        for (i=0; i < p16 -> nOutputs; i++) {
1129 
1130               Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1131        }
1132 
1133 }
1134 
1135 
1136 static
Eval5InputsFloat(const cmsFloat32Number Input[],cmsFloat32Number Output[],const cmsInterpParams * p)1137 void Eval5InputsFloat(const cmsFloat32Number Input[],
1138                       cmsFloat32Number Output[],
1139                       const cmsInterpParams* p)
1140 {
1141        const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1142        cmsFloat32Number rest;
1143        cmsFloat32Number pk;
1144        int k0, K0, K1;
1145        const cmsFloat32Number* T;
1146        cmsUInt32Number i;
1147        cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1148        cmsInterpParams p1;
1149 
1150        pk = fclamp(Input[0]) * p->Domain[0];
1151        k0 = _cmsQuickFloor(pk);
1152        rest = pk - (cmsFloat32Number) k0;
1153 
1154        K0 = p -> opta[4] * k0;
1155        K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[4]);
1156 
1157        p1 = *p;
1158        memmove(&p1.Domain[0], &p ->Domain[1], 4*sizeof(cmsUInt32Number));
1159 
1160        T = LutTable + K0;
1161        p1.Table = T;
1162 
1163        Eval4InputsFloat(Input + 1,  Tmp1, &p1);
1164 
1165        T = LutTable + K1;
1166        p1.Table = T;
1167 
1168        Eval4InputsFloat(Input + 1,  Tmp2, &p1);
1169 
1170        for (i=0; i < p -> nOutputs; i++) {
1171 
1172               cmsFloat32Number y0 = Tmp1[i];
1173               cmsFloat32Number y1 = Tmp2[i];
1174 
1175               Output[i] = y0 + (y1 - y0) * rest;
1176        }
1177 }
1178 
1179 
1180 
1181 static
Eval6Inputs(register const cmsUInt16Number Input[],register cmsUInt16Number Output[],register const cmsInterpParams * p16)1182 void Eval6Inputs(register const cmsUInt16Number Input[],
1183                  register cmsUInt16Number Output[],
1184                  register const cmsInterpParams* p16)
1185 {
1186        const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1187        cmsS15Fixed16Number fk;
1188        cmsS15Fixed16Number k0, rk;
1189        int K0, K1;
1190        const cmsUInt16Number* T;
1191        cmsUInt32Number i;
1192        cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1193        cmsInterpParams p1;
1194 
1195        fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1196        k0 = FIXED_TO_INT(fk);
1197        rk = FIXED_REST_TO_INT(fk);
1198 
1199        K0 = p16 -> opta[5] * k0;
1200        K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1201 
1202        p1 = *p16;
1203        memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number));
1204 
1205        T = LutTable + K0;
1206        p1.Table = T;
1207 
1208        Eval5Inputs(Input + 1, Tmp1, &p1);
1209 
1210        T = LutTable + K1;
1211        p1.Table = T;
1212 
1213        Eval5Inputs(Input + 1, Tmp2, &p1);
1214 
1215        for (i=0; i < p16 -> nOutputs; i++) {
1216 
1217               Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1218        }
1219 
1220 }
1221 
1222 
1223 static
Eval6InputsFloat(const cmsFloat32Number Input[],cmsFloat32Number Output[],const cmsInterpParams * p)1224 void Eval6InputsFloat(const cmsFloat32Number Input[],
1225                       cmsFloat32Number Output[],
1226                       const cmsInterpParams* p)
1227 {
1228        const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1229        cmsFloat32Number rest;
1230        cmsFloat32Number pk;
1231        int k0, K0, K1;
1232        const cmsFloat32Number* T;
1233        cmsUInt32Number i;
1234        cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1235        cmsInterpParams p1;
1236 
1237        pk = fclamp(Input[0]) * p->Domain[0];
1238        k0 = _cmsQuickFloor(pk);
1239        rest = pk - (cmsFloat32Number) k0;
1240 
1241        K0 = p -> opta[5] * k0;
1242        K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[5]);
1243 
1244        p1 = *p;
1245        memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number));
1246 
1247        T = LutTable + K0;
1248        p1.Table = T;
1249 
1250        Eval5InputsFloat(Input + 1,  Tmp1, &p1);
1251 
1252        T = LutTable + K1;
1253        p1.Table = T;
1254 
1255        Eval5InputsFloat(Input + 1,  Tmp2, &p1);
1256 
1257        for (i=0; i < p -> nOutputs; i++) {
1258 
1259               cmsFloat32Number y0 = Tmp1[i];
1260               cmsFloat32Number y1 = Tmp2[i];
1261 
1262               Output[i] = y0 + (y1 - y0) * rest;
1263        }
1264 }
1265 
1266 
1267 static
Eval7Inputs(register const cmsUInt16Number Input[],register cmsUInt16Number Output[],register const cmsInterpParams * p16)1268 void Eval7Inputs(register const cmsUInt16Number Input[],
1269                  register cmsUInt16Number Output[],
1270                  register const cmsInterpParams* p16)
1271 {
1272        const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1273        cmsS15Fixed16Number fk;
1274        cmsS15Fixed16Number k0, rk;
1275        int K0, K1;
1276        const cmsUInt16Number* T;
1277        cmsUInt32Number i;
1278        cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1279        cmsInterpParams p1;
1280 
1281 
1282        fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1283        k0 = FIXED_TO_INT(fk);
1284        rk = FIXED_REST_TO_INT(fk);
1285 
1286        K0 = p16 -> opta[6] * k0;
1287        K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1288 
1289        p1 = *p16;
1290        memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number));
1291 
1292        T = LutTable + K0;
1293        p1.Table = T;
1294 
1295        Eval6Inputs(Input + 1, Tmp1, &p1);
1296 
1297        T = LutTable + K1;
1298        p1.Table = T;
1299 
1300        Eval6Inputs(Input + 1, Tmp2, &p1);
1301 
1302        for (i=0; i < p16 -> nOutputs; i++) {
1303               Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1304        }
1305 }
1306 
1307 
1308 static
Eval7InputsFloat(const cmsFloat32Number Input[],cmsFloat32Number Output[],const cmsInterpParams * p)1309 void Eval7InputsFloat(const cmsFloat32Number Input[],
1310                       cmsFloat32Number Output[],
1311                       const cmsInterpParams* p)
1312 {
1313        const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1314        cmsFloat32Number rest;
1315        cmsFloat32Number pk;
1316        int k0, K0, K1;
1317        const cmsFloat32Number* T;
1318        cmsUInt32Number i;
1319        cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1320        cmsInterpParams p1;
1321 
1322        pk = fclamp(Input[0]) * p->Domain[0];
1323        k0 = _cmsQuickFloor(pk);
1324        rest = pk - (cmsFloat32Number) k0;
1325 
1326        K0 = p -> opta[6] * k0;
1327        K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[6]);
1328 
1329        p1 = *p;
1330        memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number));
1331 
1332        T = LutTable + K0;
1333        p1.Table = T;
1334 
1335        Eval6InputsFloat(Input + 1,  Tmp1, &p1);
1336 
1337        T = LutTable + K1;
1338        p1.Table = T;
1339 
1340        Eval6InputsFloat(Input + 1,  Tmp2, &p1);
1341 
1342 
1343        for (i=0; i < p -> nOutputs; i++) {
1344 
1345               cmsFloat32Number y0 = Tmp1[i];
1346               cmsFloat32Number y1 = Tmp2[i];
1347 
1348               Output[i] = y0 + (y1 - y0) * rest;
1349 
1350        }
1351 }
1352 
1353 static
Eval8Inputs(register const cmsUInt16Number Input[],register cmsUInt16Number Output[],register const cmsInterpParams * p16)1354 void Eval8Inputs(register const cmsUInt16Number Input[],
1355                  register cmsUInt16Number Output[],
1356                  register const cmsInterpParams* p16)
1357 {
1358        const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1359        cmsS15Fixed16Number fk;
1360        cmsS15Fixed16Number k0, rk;
1361        int K0, K1;
1362        const cmsUInt16Number* T;
1363        cmsUInt32Number i;
1364        cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1365        cmsInterpParams p1;
1366 
1367        fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1368        k0 = FIXED_TO_INT(fk);
1369        rk = FIXED_REST_TO_INT(fk);
1370 
1371        K0 = p16 -> opta[7] * k0;
1372        K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1373 
1374        p1 = *p16;
1375        memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number));
1376 
1377        T = LutTable + K0;
1378        p1.Table = T;
1379 
1380        Eval7Inputs(Input + 1, Tmp1, &p1);
1381 
1382        T = LutTable + K1;
1383        p1.Table = T;
1384        Eval7Inputs(Input + 1, Tmp2, &p1);
1385 
1386        for (i=0; i < p16 -> nOutputs; i++) {
1387               Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1388        }
1389 }
1390 
1391 
1392 
1393 static
Eval8InputsFloat(const cmsFloat32Number Input[],cmsFloat32Number Output[],const cmsInterpParams * p)1394 void Eval8InputsFloat(const cmsFloat32Number Input[],
1395                       cmsFloat32Number Output[],
1396                       const cmsInterpParams* p)
1397 {
1398        const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1399        cmsFloat32Number rest;
1400        cmsFloat32Number pk;
1401        int k0, K0, K1;
1402        const cmsFloat32Number* T;
1403        cmsUInt32Number i;
1404        cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1405        cmsInterpParams p1;
1406 
1407        pk = fclamp(Input[0]) * p->Domain[0];
1408        k0 = _cmsQuickFloor(pk);
1409        rest = pk - (cmsFloat32Number) k0;
1410 
1411        K0 = p -> opta[7] * k0;
1412        K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[7]);
1413 
1414        p1 = *p;
1415        memmove(&p1.Domain[0], &p ->Domain[1], 7*sizeof(cmsUInt32Number));
1416 
1417        T = LutTable + K0;
1418        p1.Table = T;
1419 
1420        Eval7InputsFloat(Input + 1,  Tmp1, &p1);
1421 
1422        T = LutTable + K1;
1423        p1.Table = T;
1424 
1425        Eval7InputsFloat(Input + 1,  Tmp2, &p1);
1426 
1427 
1428        for (i=0; i < p -> nOutputs; i++) {
1429 
1430               cmsFloat32Number y0 = Tmp1[i];
1431               cmsFloat32Number y1 = Tmp2[i];
1432 
1433               Output[i] = y0 + (y1 - y0) * rest;
1434        }
1435 }
1436 
1437 // The default factory
1438 static
DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels,cmsUInt32Number nOutputChannels,cmsUInt32Number dwFlags)1439 cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags)
1440 {
1441 
1442     cmsInterpFunction Interpolation;
1443     cmsBool  IsFloat     = (dwFlags & CMS_LERP_FLAGS_FLOAT);
1444     cmsBool  IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR);
1445 
1446     memset(&Interpolation, 0, sizeof(Interpolation));
1447 
1448     // Safety check
1449     if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS)
1450         return Interpolation;
1451 
1452     switch (nInputChannels) {
1453 
1454            case 1: // Gray LUT / linear
1455 
1456                if (nOutputChannels == 1) {
1457 
1458                    if (IsFloat)
1459                        Interpolation.LerpFloat = LinLerp1Dfloat;
1460                    else
1461                        Interpolation.Lerp16 = LinLerp1D;
1462 
1463                }
1464                else {
1465 
1466                    if (IsFloat)
1467                        Interpolation.LerpFloat = Eval1InputFloat;
1468                    else
1469                        Interpolation.Lerp16 = Eval1Input;
1470                }
1471                break;
1472 
1473            case 2: // Duotone
1474                if (IsFloat)
1475                       Interpolation.LerpFloat =  BilinearInterpFloat;
1476                else
1477                       Interpolation.Lerp16    =  BilinearInterp16;
1478                break;
1479 
1480            case 3:  // RGB et al
1481 
1482                if (IsTrilinear) {
1483 
1484                    if (IsFloat)
1485                        Interpolation.LerpFloat = TrilinearInterpFloat;
1486                    else
1487                        Interpolation.Lerp16 = TrilinearInterp16;
1488                }
1489                else {
1490 
1491                    if (IsFloat)
1492                        Interpolation.LerpFloat = TetrahedralInterpFloat;
1493                    else {
1494 
1495                        Interpolation.Lerp16 = TetrahedralInterp16;
1496                    }
1497                }
1498                break;
1499 
1500            case 4:  // CMYK lut
1501 
1502                if (IsFloat)
1503                    Interpolation.LerpFloat =  Eval4InputsFloat;
1504                else
1505                    Interpolation.Lerp16    =  Eval4Inputs;
1506                break;
1507 
1508            case 5: // 5 Inks
1509                if (IsFloat)
1510                    Interpolation.LerpFloat =  Eval5InputsFloat;
1511                else
1512                    Interpolation.Lerp16    =  Eval5Inputs;
1513                break;
1514 
1515            case 6: // 6 Inks
1516                if (IsFloat)
1517                    Interpolation.LerpFloat =  Eval6InputsFloat;
1518                else
1519                    Interpolation.Lerp16    =  Eval6Inputs;
1520                break;
1521 
1522            case 7: // 7 inks
1523                if (IsFloat)
1524                    Interpolation.LerpFloat =  Eval7InputsFloat;
1525                else
1526                    Interpolation.Lerp16    =  Eval7Inputs;
1527                break;
1528 
1529            case 8: // 8 inks
1530                if (IsFloat)
1531                    Interpolation.LerpFloat =  Eval8InputsFloat;
1532                else
1533                    Interpolation.Lerp16    =  Eval8Inputs;
1534                break;
1535 
1536                break;
1537 
1538            default:
1539                Interpolation.Lerp16 = NULL;
1540     }
1541 
1542     return Interpolation;
1543 }
1544