Coverage Report

Created: 2026-09-01 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/lcms/src/cmsintrp.c
Line
Count
Source
1
//---------------------------------------------------------------------------------
2
//
3
//  Little Color Management System
4
//  Copyright (c) 1998-2026 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
7.08k
{
48
7.08k
    void* from;
49
50
7.08k
    _cmsAssert(ctx != NULL);
51
52
7.08k
    if (src != NULL) {
53
0
        from = src ->chunks[InterpPlugin];       
54
0
    }
55
7.08k
    else { 
56
7.08k
        static _cmsInterpPluginChunkType InterpPluginChunk = { NULL };
57
58
7.08k
        from = &InterpPluginChunk;
59
7.08k
    }
60
61
7.08k
    _cmsAssert(from != NULL);
62
7.08k
    ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType));
63
7.08k
}
64
65
66
// Main plug-in entry
67
cmsBool  _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data)
68
7.08k
{
69
7.08k
    cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data;
70
7.08k
    _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
71
72
7.08k
    if (Data == NULL) {
73
74
7.08k
        ptr ->Interpolators = NULL;
75
7.08k
        return TRUE;
76
7.08k
    }
77
78
    // Set replacement functions
79
0
    ptr ->Interpolators = Plugin ->InterpolatorsFactory;
80
0
    return TRUE;
81
7.08k
}
82
83
84
// Set the interpolation method
85
cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p)
86
167k
{      
87
167k
    _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
88
89
167k
    p ->Interpolation.Lerp16 = NULL;
90
91
   // Invoke factory, possibly in the Plug-in
92
167k
    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
167k
    if (p ->Interpolation.Lerp16 == NULL)
98
167k
        p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags);
99
100
    // Check for valid interpolator (we just check one member of the union)
101
167k
    if (p ->Interpolation.Lerp16 == NULL) {
102
0
            return FALSE;
103
0
    }
104
105
167k
    return TRUE;
106
167k
}
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
165k
{
116
165k
    cmsInterpParams* p;
117
165k
    cmsUInt32Number i;
118
119
    // Check for maximum inputs
120
165k
    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
165k
    p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams));
127
165k
    if (p == NULL) return NULL;
128
129
    // Keep original parameters
130
165k
    p -> dwFlags  = dwFlags;
131
165k
    p -> nInputs  = InputChan;
132
165k
    p -> nOutputs = OutputChan;
133
165k
    p ->Table     = Table;
134
165k
    p ->ContextID  = ContextID;
135
136
    // Fill samples per input direction and domain (which is number of nodes minus one)
137
366k
    for (i=0; i < InputChan; i++) {
138
139
200k
        p -> nSamples[i] = nSamples[i];
140
200k
        p -> Domain[i]   = nSamples[i] - 1;
141
200k
    }
142
143
    // Compute factors to apply to each component to index the grid array
144
165k
    p -> opta[0] = p -> nOutputs;
145
200k
    for (i=1; i < InputChan; i++)
146
34.7k
        p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];
147
148
149
165k
    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
165k
    return p;
157
165k
}
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
150k
{
164
150k
    int i;
165
150k
    cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];
166
167
    // Fill the auxiliary array
168
2.40M
    for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
169
2.25M
        Samples[i] = nSamples;
170
171
    // Call the extended function
172
150k
    return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags);
173
150k
}
174
175
176
// Free all associated memory
177
void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p)
178
165k
{
179
165k
    if (p != NULL) _cmsFree(p ->ContextID, p);
180
165k
}
181
182
183
// Inline fixed point interpolation
184
cmsINLINE CMS_NO_SANITIZE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h)
185
124M
{
186
124M
    cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000;
187
124M
    dif = (dif >> 16) + l;
188
124M
    return (cmsUInt16Number) (dif);
189
124M
}
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
108M
{
198
108M
    cmsUInt16Number y1, y0;
199
108M
    int cell0, rest;
200
108M
    int val3;
201
108M
    const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
202
203
    // if last value or just one point
204
108M
    if (Value[0] == 0xffff || p->Domain[0] == 0) {
205
206
23.4M
        Output[0] = LutTable[p -> Domain[0]];      
207
23.4M
    }
208
85.5M
    else
209
85.5M
    {
210
85.5M
        val3 = p->Domain[0] * Value[0];
211
85.5M
        val3 = _cmsToFixedDomain(val3);    // To fixed 15.16
212
213
85.5M
        cell0 = FIXED_TO_INT(val3);             // Cell is 16 MSB bits
214
85.5M
        rest = FIXED_REST_TO_INT(val3);        // Rest is 16 LSB bits
215
216
85.5M
        y0 = LutTable[cell0];
217
85.5M
        y1 = LutTable[cell0 + 1];
218
219
85.5M
        Output[0] = LinearInterp(rest, y0, y1);
220
85.5M
    }
221
108M
}
222
223
// To prevent out of bounds indexing
224
cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v) 
225
1.18M
{
226
1.18M
    return ((v < 1.0e-9f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v);
227
1.18M
}
228
229
// Floating-point version of 1D interpolation
230
static
231
void LinLerp1Dfloat(const cmsFloat32Number Value[],
232
                    cmsFloat32Number Output[],
233
                    const cmsInterpParams* p)
234
1.18M
{
235
1.18M
       cmsFloat32Number y1, y0;
236
1.18M
       cmsFloat32Number val2, rest;
237
1.18M
       int cell0, cell1;
238
1.18M
       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
239
240
1.18M
       val2 = fclamp(Value[0]);
241
242
       // if last value...
243
1.18M
       if (val2 == 1.0 || p->Domain[0] == 0) {
244
133k
           Output[0] = LutTable[p -> Domain[0]];          
245
133k
       }
246
1.04M
       else
247
1.04M
       {
248
1.04M
           val2 *= p->Domain[0];
249
250
1.04M
           cell0 = (int)floor(val2);
251
1.04M
           cell1 = (int)ceil(val2);
252
253
           // Rest is 16 LSB bits
254
1.04M
           rest = val2 - cell0;
255
256
1.04M
           y0 = LutTable[cell0];
257
1.04M
           y1 = LutTable[cell1];
258
259
1.04M
           Output[0] = y0 + (y1 - y0) * rest;
260
1.04M
       }
261
1.18M
}
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
8.50k
{
271
8.50k
       cmsS15Fixed16Number fk;
272
8.50k
       cmsS15Fixed16Number k0, k1, rk, K0, K1;
273
8.50k
       int v;
274
8.50k
       cmsUInt32Number OutChan;
275
8.50k
       const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
276
277
278
       // if last value...
279
8.50k
       if (Input[0] == 0xffff || p16->Domain[0] == 0) {
280
281
1.26k
           cmsUInt32Number y0 = p16->Domain[0] * p16->opta[0];
282
           
283
5.04k
           for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
284
3.78k
               Output[OutChan] = LutTable[y0 + OutChan];
285
3.78k
           }
286
1.26k
       }
287
7.24k
       else
288
7.24k
       {
289
290
7.24k
           v = Input[0] * p16->Domain[0];
291
7.24k
           fk = _cmsToFixedDomain(v);
292
293
7.24k
           k0 = FIXED_TO_INT(fk);
294
7.24k
           rk = (cmsUInt16Number)FIXED_REST_TO_INT(fk);
295
296
7.24k
           k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
297
298
7.24k
           K0 = p16->opta[0] * k0;
299
7.24k
           K1 = p16->opta[0] * k1;
300
301
28.9k
           for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
302
303
21.7k
               Output[OutChan] = LinearInterp(rk, LutTable[K0 + OutChan], LutTable[K1 + OutChan]);
304
21.7k
           }
305
7.24k
       }
306
8.50k
}
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) floor(px); fx = px - (cmsFloat32Number) x0;
381
0
    y0 = (int) floor(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
18.5M
{
549
483M
#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
550
422M
#define LERP(a,l,h)     (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
551
552
18.5M
           const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
553
18.5M
           int        OutChan, TotalOut;
554
18.5M
           cmsS15Fixed16Number    fx, fy, fz;
555
18.5M
           CMSREGISTER int        rx, ry, rz;
556
18.5M
           int                    x0, y0, z0;
557
18.5M
           CMSREGISTER int        X0, X1, Y0, Y1, Z0, Z1;
558
18.5M
           int                    d000, d001, d010, d011,
559
18.5M
                                  d100, d101, d110, d111,
560
18.5M
                                  dx00, dx01, dx10, dx11,
561
18.5M
                                  dxy0, dxy1, dxyz;
562
563
18.5M
    TotalOut   = p -> nOutputs;
564
565
18.5M
    fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
566
18.5M
    x0  = FIXED_TO_INT(fx);
567
18.5M
    rx  = FIXED_REST_TO_INT(fx);    // Rest in 0..1.0 domain
568
569
570
18.5M
    fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
571
18.5M
    y0  = FIXED_TO_INT(fy);
572
18.5M
    ry  = FIXED_REST_TO_INT(fy);
573
574
18.5M
    fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
575
18.5M
    z0 = FIXED_TO_INT(fz);
576
18.5M
    rz = FIXED_REST_TO_INT(fz);
577
578
579
18.5M
    X0 = p -> opta[2] * x0;
580
18.5M
    X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
581
582
18.5M
    Y0 = p -> opta[1] * y0;
583
18.5M
    Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
584
585
18.5M
    Z0 = p -> opta[0] * z0;
586
18.5M
    Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
587
588
78.9M
    for (OutChan = 0; OutChan < TotalOut; OutChan++) {
589
590
60.4M
        d000 = DENS(X0, Y0, Z0);
591
60.4M
        d001 = DENS(X0, Y0, Z1);
592
60.4M
        d010 = DENS(X0, Y1, Z0);
593
60.4M
        d011 = DENS(X0, Y1, Z1);
594
595
60.4M
        d100 = DENS(X1, Y0, Z0);
596
60.4M
        d101 = DENS(X1, Y0, Z1);
597
60.4M
        d110 = DENS(X1, Y1, Z0);
598
60.4M
        d111 = DENS(X1, Y1, Z1);
599
600
601
60.4M
        dx00 = LERP(rx, d000, d100);
602
60.4M
        dx01 = LERP(rx, d001, d101);
603
60.4M
        dx10 = LERP(rx, d010, d110);
604
60.4M
        dx11 = LERP(rx, d011, d111);
605
606
60.4M
        dxy0 = LERP(ry, dx00, dx10);
607
60.4M
        dxy1 = LERP(ry, dx01, dx11);
608
609
60.4M
        dxyz = LERP(rz, dxy0, dxy1);
610
611
60.4M
        Output[OutChan] = (cmsUInt16Number) dxyz;
612
60.4M
    }
613
614
615
18.5M
#   undef LERP
616
18.5M
#   undef DENS
617
18.5M
}
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
35.1M
{
725
35.1M
    const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;
726
35.1M
    cmsS15Fixed16Number fx, fy, fz;
727
35.1M
    cmsS15Fixed16Number rx, ry, rz;
728
35.1M
    int x0, y0, z0;
729
35.1M
    cmsS15Fixed16Number c0, c1, c2, c3, Rest;
730
35.1M
    cmsUInt32Number X0, X1, Y0, Y1, Z0, Z1;
731
35.1M
    cmsUInt32Number TotalOut = p -> nOutputs;
732
733
35.1M
    fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
734
35.1M
    fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
735
35.1M
    fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
736
737
35.1M
    x0 = FIXED_TO_INT(fx);
738
35.1M
    y0 = FIXED_TO_INT(fy);
739
35.1M
    z0 = FIXED_TO_INT(fz);
740
741
35.1M
    rx = FIXED_REST_TO_INT(fx);
742
35.1M
    ry = FIXED_REST_TO_INT(fy);
743
35.1M
    rz = FIXED_REST_TO_INT(fz);
744
745
35.1M
    X0 = p -> opta[2] * x0;
746
35.1M
    X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
747
748
35.1M
    Y0 = p -> opta[1] * y0;
749
35.1M
    Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
750
751
35.1M
    Z0 = p -> opta[0] * z0;
752
35.1M
    Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
753
    
754
35.1M
    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
35.1M
    if (rx >= ry) {
762
32.3M
        if (ry >= rz) {
763
28.7M
            Y1 += X1;
764
28.7M
            Z1 += Y1;
765
102M
            for (; TotalOut; TotalOut--) {
766
73.2M
                c1 = LutTable[X1];
767
73.2M
                c2 = LutTable[Y1];
768
73.2M
                c3 = LutTable[Z1];
769
73.2M
                c0 = *LutTable++;
770
73.2M
                c3 -= c2;
771
73.2M
                c2 -= c1;
772
73.2M
                c1 -= c0;
773
73.2M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
774
73.2M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
775
73.2M
            }
776
28.7M
        } else if (rz >= rx) {
777
2.14M
            X1 += Z1;
778
2.14M
            Y1 += X1;
779
8.07M
            for (; TotalOut; TotalOut--) {
780
5.93M
                c1 = LutTable[X1];
781
5.93M
                c2 = LutTable[Y1];
782
5.93M
                c3 = LutTable[Z1];
783
5.93M
                c0 = *LutTable++;
784
5.93M
                c2 -= c1;
785
5.93M
                c1 -= c3;
786
5.93M
                c3 -= c0;
787
5.93M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
788
5.93M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
789
5.93M
            }
790
2.14M
        } else {
791
1.41M
            Z1 += X1;
792
1.41M
            Y1 += Z1;
793
5.66M
            for (; TotalOut; TotalOut--) {
794
4.24M
                c1 = LutTable[X1];
795
4.24M
                c2 = LutTable[Y1];
796
4.24M
                c3 = LutTable[Z1];
797
4.24M
                c0 = *LutTable++;
798
4.24M
                c2 -= c3;
799
4.24M
                c3 -= c1;
800
4.24M
                c1 -= c0;
801
4.24M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
802
4.24M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
803
4.24M
            }
804
1.41M
        }
805
32.3M
    } else {
806
2.79M
        if (rx >= rz) {
807
2.66M
            X1 += Y1;
808
2.66M
            Z1 += X1;
809
10.1M
            for (; TotalOut; TotalOut--) {
810
7.48M
                c1 = LutTable[X1];
811
7.48M
                c2 = LutTable[Y1];
812
7.48M
                c3 = LutTable[Z1];
813
7.48M
                c0 = *LutTable++;
814
7.48M
                c3 -= c1;
815
7.48M
                c1 -= c2;
816
7.48M
                c2 -= c0;
817
7.48M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
818
7.48M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
819
7.48M
            }
820
2.66M
        } else if (ry >= rz) {
821
35.2k
            Z1 += Y1;
822
35.2k
            X1 += Z1;
823
140k
            for (; TotalOut; TotalOut--) {
824
105k
                c1 = LutTable[X1];
825
105k
                c2 = LutTable[Y1];
826
105k
                c3 = LutTable[Z1];
827
105k
                c0 = *LutTable++;
828
105k
                c1 -= c3;
829
105k
                c3 -= c2;
830
105k
                c2 -= c0;
831
105k
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
832
105k
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
833
105k
            }
834
96.3k
        } else {
835
96.3k
            Y1 += Z1;
836
96.3k
            X1 += Y1;
837
385k
            for (; TotalOut; TotalOut--) {
838
288k
                c1 = LutTable[X1];
839
288k
                c2 = LutTable[Y1];
840
288k
                c3 = LutTable[Z1];
841
288k
                c0 = *LutTable++;
842
288k
                c1 -= c2;
843
288k
                c2 -= c3;
844
288k
                c3 -= c0;
845
288k
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
846
288k
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
847
288k
            }
848
96.3k
        }
849
2.79M
    }
850
35.1M
}
851
852
853
471M
#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
13.0M
{
859
13.0M
    const cmsUInt16Number* LutTable;
860
13.0M
    cmsS15Fixed16Number fk;
861
13.0M
    cmsS15Fixed16Number k0, rk;
862
13.0M
    int K0, K1;
863
13.0M
    cmsS15Fixed16Number    fx, fy, fz;
864
13.0M
    cmsS15Fixed16Number    rx, ry, rz;
865
13.0M
    int                    x0, y0, z0;
866
13.0M
    cmsS15Fixed16Number    X0, X1, Y0, Y1, Z0, Z1;
867
13.0M
    cmsUInt32Number i;
868
13.0M
    cmsS15Fixed16Number    c0, c1, c2, c3, Rest;
869
13.0M
    cmsUInt32Number        OutChan;
870
13.0M
    cmsUInt16Number        Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
871
872
873
13.0M
    fk  = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]);
874
13.0M
    fx  = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]);
875
13.0M
    fy  = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]);
876
13.0M
    fz  = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]);
877
878
13.0M
    k0  = FIXED_TO_INT(fk);
879
13.0M
    x0  = FIXED_TO_INT(fx);
880
13.0M
    y0  = FIXED_TO_INT(fy);
881
13.0M
    z0  = FIXED_TO_INT(fz);
882
883
13.0M
    rk  = FIXED_REST_TO_INT(fk);
884
13.0M
    rx  = FIXED_REST_TO_INT(fx);
885
13.0M
    ry  = FIXED_REST_TO_INT(fy);
886
13.0M
    rz  = FIXED_REST_TO_INT(fz);
887
888
13.0M
    K0 = p16 -> opta[3] * k0;
889
13.0M
    K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]);
890
891
13.0M
    X0 = p16 -> opta[2] * x0;
892
13.0M
    X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]);
893
894
13.0M
    Y0 = p16 -> opta[1] * y0;
895
13.0M
    Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]);
896
897
13.0M
    Z0 = p16 -> opta[0] * z0;
898
13.0M
    Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]);
899
900
13.0M
    LutTable = (cmsUInt16Number*) p16 -> Table;
901
13.0M
    LutTable += K0;
902
903
52.3M
    for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
904
905
39.2M
        c0 = DENS(X0, Y0, Z0);
906
907
39.2M
        if (rx >= ry && ry >= rz) {
908
909
6.83M
            c1 = DENS(X1, Y0, Z0) - c0;
910
6.83M
            c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
911
6.83M
            c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
912
913
6.83M
        }
914
32.4M
        else
915
32.4M
            if (rx >= rz && rz >= ry) {
916
917
7.18M
                c1 = DENS(X1, Y0, Z0) - c0;
918
7.18M
                c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
919
7.18M
                c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
920
921
7.18M
            }
922
25.2M
            else
923
25.2M
                if (rz >= rx && rx >= ry) {
924
925
7.95M
                    c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
926
7.95M
                    c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
927
7.95M
                    c3 = DENS(X0, Y0, Z1) - c0;
928
929
7.95M
                }
930
17.3M
                else
931
17.3M
                    if (ry >= rx && rx >= rz) {
932
933
5.49M
                        c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
934
5.49M
                        c2 = DENS(X0, Y1, Z0) - c0;
935
5.49M
                        c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
936
937
5.49M
                    }
938
11.8M
                    else
939
11.8M
                        if (ry >= rz && rz >= rx) {
940
941
5.89M
                            c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
942
5.89M
                            c2 = DENS(X0, Y1, Z0) - c0;
943
5.89M
                            c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
944
945
5.89M
                        }
946
5.93M
                        else
947
5.93M
                            if (rz >= ry && ry >= rx) {
948
949
5.93M
                                c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
950
5.93M
                                c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
951
5.93M
                                c3 = DENS(X0, Y0, Z1) - c0;
952
953
5.93M
                            }
954
0
                            else {
955
0
                                c1 = c2 = c3 = 0;
956
0
                            }
957
958
39.2M
        Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
959
960
39.2M
        Tmp1[OutChan] = (cmsUInt16Number)c0 + ((Rest + (Rest >> 16)) >> 16);
961
39.2M
    }
962
963
964
13.0M
    LutTable = (cmsUInt16Number*) p16 -> Table;
965
13.0M
    LutTable += K1;
966
967
52.3M
    for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
968
969
39.2M
        c0 = DENS(X0, Y0, Z0);
970
971
39.2M
        if (rx >= ry && ry >= rz) {
972
973
6.83M
            c1 = DENS(X1, Y0, Z0) - c0;
974
6.83M
            c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
975
6.83M
            c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
976
977
6.83M
        }
978
32.4M
        else
979
32.4M
            if (rx >= rz && rz >= ry) {
980
981
7.18M
                c1 = DENS(X1, Y0, Z0) - c0;
982
7.18M
                c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
983
7.18M
                c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
984
985
7.18M
            }
986
25.2M
            else
987
25.2M
                if (rz >= rx && rx >= ry) {
988
989
7.95M
                    c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
990
7.95M
                    c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
991
7.95M
                    c3 = DENS(X0, Y0, Z1) - c0;
992
993
7.95M
                }
994
17.3M
                else
995
17.3M
                    if (ry >= rx && rx >= rz) {
996
997
5.49M
                        c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
998
5.49M
                        c2 = DENS(X0, Y1, Z0) - c0;
999
5.49M
                        c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
1000
1001
5.49M
                    }
1002
11.8M
                    else
1003
11.8M
                        if (ry >= rz && rz >= rx) {
1004
1005
5.89M
                            c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
1006
5.89M
                            c2 = DENS(X0, Y1, Z0) - c0;
1007
5.89M
                            c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
1008
1009
5.89M
                        }
1010
5.93M
                        else
1011
5.93M
                            if (rz >= ry && ry >= rx) {
1012
1013
5.93M
                                c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
1014
5.93M
                                c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
1015
5.93M
                                c3 = DENS(X0, Y0, Z1) - c0;
1016
1017
5.93M
                            }
1018
0
                            else  {
1019
0
                                c1 = c2 = c3 = 0;
1020
0
                            }
1021
1022
39.2M
        Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
1023
1024
39.2M
        Tmp2[OutChan] = (cmsUInt16Number) c0 + ((Rest + (Rest >> 16)) >> 16);
1025
39.2M
    }
1026
1027
1028
1029
52.3M
    for (i=0; i < p16 -> nOutputs; i++) {
1030
39.2M
        Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1031
39.2M
    }
1032
13.0M
}
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 = (int)floor(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 = (int) floor(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
167k
{
1181
1182
167k
    cmsInterpFunction Interpolation;
1183
167k
    cmsBool  IsFloat     = (dwFlags & CMS_LERP_FLAGS_FLOAT);
1184
167k
    cmsBool  IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR);
1185
1186
167k
    memset(&Interpolation, 0, sizeof(Interpolation));
1187
1188
    // Safety check
1189
167k
    if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS)
1190
0
        return Interpolation;
1191
1192
167k
    switch (nInputChannels) {
1193
1194
150k
           case 1: // Gray LUT / linear
1195
1196
150k
               if (nOutputChannels == 1) {
1197
1198
150k
                   if (IsFloat)
1199
323
                       Interpolation.LerpFloat = LinLerp1Dfloat;
1200
149k
                   else
1201
149k
                       Interpolation.Lerp16 = LinLerp1D;
1202
1203
150k
               }
1204
734
               else {
1205
1206
734
                   if (IsFloat)
1207
17
                       Interpolation.LerpFloat = Eval1InputFloat;
1208
717
                   else
1209
717
                       Interpolation.Lerp16 = Eval1Input;
1210
734
               }
1211
150k
               break;
1212
1213
181
           case 2: // Duotone
1214
181
               if (IsFloat)
1215
11
                      Interpolation.LerpFloat =  BilinearInterpFloat;
1216
170
               else
1217
170
                      Interpolation.Lerp16    =  BilinearInterp16;
1218
181
               break;
1219
1220
14.7k
           case 3:  // RGB et al
1221
1222
14.7k
               if (IsTrilinear) {
1223
1224
3.78k
                   if (IsFloat)
1225
0
                       Interpolation.LerpFloat = TrilinearInterpFloat;
1226
3.78k
                   else
1227
3.78k
                       Interpolation.Lerp16 = TrilinearInterp16;
1228
3.78k
               }
1229
10.9k
               else {
1230
1231
10.9k
                   if (IsFloat)
1232
11
                       Interpolation.LerpFloat = TetrahedralInterpFloat;
1233
10.9k
                   else {
1234
1235
10.9k
                       Interpolation.Lerp16 = TetrahedralInterp16;
1236
10.9k
                   }
1237
10.9k
               }
1238
14.7k
               break;
1239
1240
1.23k
           case 4:  // CMYK lut
1241
1242
1.23k
               if (IsFloat)
1243
3
                   Interpolation.LerpFloat =  Eval4InputsFloat;
1244
1.23k
               else
1245
1.23k
                   Interpolation.Lerp16    =  Eval4Inputs;
1246
1.23k
               break;
1247
1248
36
           case 5: // 5 Inks
1249
36
               if (IsFloat)
1250
16
                   Interpolation.LerpFloat =  Eval5InputsFloat;
1251
20
               else
1252
20
                   Interpolation.Lerp16    =  Eval5Inputs;
1253
36
               break;
1254
1255
38
           case 6: // 6 Inks
1256
38
               if (IsFloat)
1257
16
                   Interpolation.LerpFloat =  Eval6InputsFloat;
1258
22
               else
1259
22
                   Interpolation.Lerp16    =  Eval6Inputs;
1260
38
               break;
1261
1262
46
           case 7: // 7 inks
1263
46
               if (IsFloat)
1264
21
                   Interpolation.LerpFloat =  Eval7InputsFloat;
1265
25
               else
1266
25
                   Interpolation.Lerp16    =  Eval7Inputs;
1267
46
               break;
1268
1269
36
           case 8: // 8 inks
1270
36
               if (IsFloat)
1271
11
                   Interpolation.LerpFloat =  Eval8InputsFloat;
1272
25
               else
1273
25
                   Interpolation.Lerp16    =  Eval8Inputs;
1274
36
               break;
1275
1276
88
           case 9: 
1277
88
               if (IsFloat)
1278
11
                   Interpolation.LerpFloat = Eval9InputsFloat;
1279
77
               else
1280
77
                   Interpolation.Lerp16 = Eval9Inputs;
1281
88
               break;
1282
1283
106
           case 10: 
1284
106
               if (IsFloat)
1285
11
                   Interpolation.LerpFloat = Eval10InputsFloat;
1286
95
               else
1287
95
                   Interpolation.Lerp16 = Eval10Inputs;
1288
106
               break;
1289
1290
60
           case 11:
1291
60
               if (IsFloat)
1292
11
                   Interpolation.LerpFloat = Eval11InputsFloat;
1293
49
               else
1294
49
                   Interpolation.Lerp16 = Eval11Inputs;
1295
60
               break;
1296
1297
49
           case 12: 
1298
49
               if (IsFloat)
1299
8
                   Interpolation.LerpFloat = Eval12InputsFloat;
1300
41
               else
1301
41
                   Interpolation.Lerp16 = Eval12Inputs;
1302
49
               break;
1303
1304
29
           case 13: 
1305
29
               if (IsFloat)
1306
11
                   Interpolation.LerpFloat = Eval13InputsFloat;
1307
18
               else
1308
18
                   Interpolation.Lerp16 = Eval13Inputs;
1309
29
               break;
1310
1311
47
           case 14: 
1312
47
               if (IsFloat)
1313
14
                   Interpolation.LerpFloat = Eval14InputsFloat;
1314
33
               else
1315
33
                   Interpolation.Lerp16 = Eval14Inputs;
1316
47
               break;
1317
1318
37
           case 15: 
1319
37
               if (IsFloat)
1320
11
                   Interpolation.LerpFloat = Eval15InputsFloat;
1321
26
               else
1322
26
                   Interpolation.Lerp16 = Eval15Inputs;
1323
37
               break;
1324
1325
0
           default:
1326
0
               Interpolation.Lerp16 = NULL;
1327
167k
    }
1328
1329
167k
    return Interpolation;
1330
167k
}