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