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