comparison mupdf-source/thirdparty/lcms2/src/cmsintrp.c @ 2:b50eed0cc0ef upstream

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