Coverage Report

Created: 2026-04-29 07:28

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