Coverage Report

Created: 2025-07-01 06:33

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