13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 // This file is available under and governed by the GNU General Public
26 // License version 2 only, as published by the Free Software Foundation.
27 // However, the following notice accompanied the original version of this
28 // file:
29 //
30 //---------------------------------------------------------------------------------
31 //
32 // Little Color Management System
33 // Copyright (c) 1998-2017 Marti Maria Saguer
34 //
35 // Permission is hereby granted, free of charge, to any person obtaining
36 // a copy of this software and associated documentation files (the "Software"),
37 // to deal in the Software without restriction, including without limitation
38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
39 // and/or sell copies of the Software, and to permit persons to whom the Software
40 // is furnished to do so, subject to the following conditions:
41 //
42 // The above copyright notice and this permission notice shall be included in
43 // all copies or substantial portions of the Software.
44 //
45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 //
53 //---------------------------------------------------------------------------------
193 int i;
194 cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];
195
196 // Fill the auxiliary array
197 for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
198 Samples[i] = nSamples;
199
200 // Call the extended function
201 return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags);
202 }
203
204
205 // Free all associated memory
206 void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p)
207 {
208 if (p != NULL) _cmsFree(p ->ContextID, p);
209 }
210
211
212 // Inline fixed point interpolation
213 cmsINLINE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h)
214 {
215 cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000;
216 dif = (dif >> 16) + l;
217 return (cmsUInt16Number) (dif);
218 }
219
220
221 // Linear interpolation (Fixed-point optimized)
222 static
223 void LinLerp1D(register const cmsUInt16Number Value[],
224 register cmsUInt16Number Output[],
225 register const cmsInterpParams* p)
226 {
227 cmsUInt16Number y1, y0;
228 int cell0, rest;
229 int val3;
230 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
231
232 // if last value...
233 if (Value[0] == 0xffff) {
234
235 Output[0] = LutTable[p -> Domain[0]];
236 return;
237 }
238
239 val3 = p -> Domain[0] * Value[0];
240 val3 = _cmsToFixedDomain(val3); // To fixed 15.16
241
242 cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits
243 rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits
244
245 y0 = LutTable[cell0];
246 y1 = LutTable[cell0+1];
247
248
249 Output[0] = LinearInterp(rest, y0, y1);
250 }
251
252 // To prevent out of bounds indexing
253 cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v)
254 {
255 return ((v < 1.0e-9f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v);
256 }
257
258 // Floating-point version of 1D interpolation
259 static
260 void LinLerp1Dfloat(const cmsFloat32Number Value[],
261 cmsFloat32Number Output[],
262 const cmsInterpParams* p)
263 {
264 cmsFloat32Number y1, y0;
265 cmsFloat32Number val2, rest;
266 int cell0, cell1;
267 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
268
269 val2 = fclamp(Value[0]);
270
271 // if last value...
272 if (val2 == 1.0) {
273 Output[0] = LutTable[p -> Domain[0]];
274 return;
275 }
276
277 val2 *= p -> Domain[0];
278
279 cell0 = (int) floor(val2);
280 cell1 = (int) ceil(val2);
281
282 // Rest is 16 LSB bits
283 rest = val2 - cell0;
284
285 y0 = LutTable[cell0] ;
286 y1 = LutTable[cell1] ;
287
288 Output[0] = y0 + (y1 - y0) * rest;
289 }
290
291
292
293 // Eval gray LUT having only one input channel
294 static
295 void Eval1Input(register const cmsUInt16Number Input[],
296 register cmsUInt16Number Output[],
297 register const cmsInterpParams* p16)
298 {
299 cmsS15Fixed16Number fk;
300 cmsS15Fixed16Number k0, k1, rk, K0, K1;
301 int v;
302 cmsUInt32Number OutChan;
303 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
304
305 v = Input[0] * p16 -> Domain[0];
306 fk = _cmsToFixedDomain(v);
307
308 k0 = FIXED_TO_INT(fk);
309 rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
310
311 k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
312
313 K0 = p16 -> opta[0] * k0;
314 K1 = p16 -> opta[0] * k1;
315
316 for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
317
320 }
321
322
323
324 // Eval gray LUT having only one input channel
325 static
326 void Eval1InputFloat(const cmsFloat32Number Value[],
327 cmsFloat32Number Output[],
328 const cmsInterpParams* p)
329 {
330 cmsFloat32Number y1, y0;
331 cmsFloat32Number val2, rest;
332 int cell0, cell1;
333 cmsUInt32Number OutChan;
334 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
335
336 val2 = fclamp(Value[0]);
337
338 // if last value...
339 if (val2 == 1.0) {
340 Output[0] = LutTable[p -> Domain[0]];
341 return;
342 }
343
344 val2 *= p -> Domain[0];
345
346 cell0 = (int) floor(val2);
347 cell1 = (int) ceil(val2);
348
349 // Rest is 16 LSB bits
350 rest = val2 - cell0;
351
352 cell0 *= p -> opta[0];
353 cell1 *= p -> opta[0];
354
355 for (OutChan=0; OutChan < p->nOutputs; OutChan++) {
356
357 y0 = LutTable[cell0 + OutChan] ;
358 y1 = LutTable[cell1 + OutChan] ;
359
360 Output[OutChan] = y0 + (y1 - y0) * rest;
361 }
362 }
363
364 // Bilinear interpolation (16 bits) - cmsFloat32Number version
365 static
366 void BilinearInterpFloat(const cmsFloat32Number Input[],
367 cmsFloat32Number Output[],
368 const cmsInterpParams* p)
369
370 {
371 # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
372 # define DENS(i,j) (LutTable[(i)+(j)+OutChan])
373
374 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
375 cmsFloat32Number px, py;
376 int x0, y0,
377 X0, Y0, X1, Y1;
378 int TotalOut, OutChan;
379 cmsFloat32Number fx, fy,
380 d00, d01, d10, d11,
381 dx0, dx1,
398
399 d00 = DENS(X0, Y0);
400 d01 = DENS(X0, Y1);
401 d10 = DENS(X1, Y0);
402 d11 = DENS(X1, Y1);
403
404 dx0 = LERP(fx, d00, d10);
405 dx1 = LERP(fx, d01, d11);
406
407 dxy = LERP(fy, dx0, dx1);
408
409 Output[OutChan] = dxy;
410 }
411
412
413 # undef LERP
414 # undef DENS
415 }
416
417 // Bilinear interpolation (16 bits) - optimized version
418 static
419 void BilinearInterp16(register const cmsUInt16Number Input[],
420 register cmsUInt16Number Output[],
421 register const cmsInterpParams* p)
422
423 {
424 #define DENS(i,j) (LutTable[(i)+(j)+OutChan])
425 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
426
427 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
428 int OutChan, TotalOut;
429 cmsS15Fixed16Number fx, fy;
430 register int rx, ry;
431 int x0, y0;
432 register int X0, X1, Y0, Y1;
433 int d00, d01, d10, d11,
434 dx0, dx1,
435 dxy;
436
437 TotalOut = p -> nOutputs;
438
439 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
440 x0 = FIXED_TO_INT(fx);
441 rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain
442
443
444 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
445 y0 = FIXED_TO_INT(fy);
446 ry = FIXED_REST_TO_INT(fy);
447
448
449 X0 = p -> opta[1] * x0;
450 X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]);
451
452 Y0 = p -> opta[0] * y0;
529
530 dx00 = LERP(fx, d000, d100);
531 dx01 = LERP(fx, d001, d101);
532 dx10 = LERP(fx, d010, d110);
533 dx11 = LERP(fx, d011, d111);
534
535 dxy0 = LERP(fy, dx00, dx10);
536 dxy1 = LERP(fy, dx01, dx11);
537
538 dxyz = LERP(fz, dxy0, dxy1);
539
540 Output[OutChan] = dxyz;
541 }
542
543
544 # undef LERP
545 # undef DENS
546 }
547
548 // Trilinear interpolation (16 bits) - optimized version
549 static
550 void TrilinearInterp16(register const cmsUInt16Number Input[],
551 register cmsUInt16Number Output[],
552 register const cmsInterpParams* p)
553
554 {
555 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
556 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
557
558 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
559 int OutChan, TotalOut;
560 cmsS15Fixed16Number fx, fy, fz;
561 register int rx, ry, rz;
562 int x0, y0, z0;
563 register int X0, X1, Y0, Y1, Z0, Z1;
564 int d000, d001, d010, d011,
565 d100, d101, d110, d111,
566 dx00, dx01, dx10, dx11,
567 dxy0, dxy1, dxyz;
568
569 TotalOut = p -> nOutputs;
570
571 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
572 x0 = FIXED_TO_INT(fx);
573 rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain
574
575
576 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
577 y0 = FIXED_TO_INT(fy);
578 ry = FIXED_REST_TO_INT(fy);
579
580 fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
581 z0 = FIXED_TO_INT(fz);
582 rz = FIXED_REST_TO_INT(fz);
583
709
710 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
711 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
712 c3 = DENS(X0, Y0, Z1) - c0;
713
714 }
715 else {
716 c1 = c2 = c3 = 0;
717 }
718
719 Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz;
720 }
721
722 }
723
724 #undef DENS
725
726
727
728
729 static
730 void TetrahedralInterp16(register const cmsUInt16Number Input[],
731 register cmsUInt16Number Output[],
732 register const cmsInterpParams* p)
733 {
734 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;
735 cmsS15Fixed16Number fx, fy, fz;
736 cmsS15Fixed16Number rx, ry, rz;
737 int x0, y0, z0;
738 cmsS15Fixed16Number c0, c1, c2, c3, Rest;
739 cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
740 cmsUInt32Number TotalOut = p -> nOutputs;
741
742 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
743 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
744 fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
745
746 x0 = FIXED_TO_INT(fx);
747 y0 = FIXED_TO_INT(fy);
748 z0 = FIXED_TO_INT(fz);
749
750 rx = FIXED_REST_TO_INT(fx);
751 ry = FIXED_REST_TO_INT(fy);
752 rz = FIXED_REST_TO_INT(fz);
843 } else {
844 Y1 += Z1;
845 X1 += Y1;
846 for (; TotalOut; TotalOut--) {
847 c1 = LutTable[X1];
848 c2 = LutTable[Y1];
849 c3 = LutTable[Z1];
850 c0 = *LutTable++;
851 c1 -= c2;
852 c2 -= c3;
853 c3 -= c0;
854 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
855 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
856 }
857 }
858 }
859 }
860
861
862 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
863 static
864 void Eval4Inputs(register const cmsUInt16Number Input[],
865 register cmsUInt16Number Output[],
866 register const cmsInterpParams* p16)
867 {
868 const cmsUInt16Number* LutTable;
869 cmsS15Fixed16Number fk;
870 cmsS15Fixed16Number k0, rk;
871 int K0, K1;
872 cmsS15Fixed16Number fx, fy, fz;
873 cmsS15Fixed16Number rx, ry, rz;
874 int x0, y0, z0;
875 cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
876 cmsUInt32Number i;
877 cmsS15Fixed16Number c0, c1, c2, c3, Rest;
878 cmsUInt32Number OutChan;
879 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
880
881
882 fk = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]);
883 fx = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]);
884 fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]);
885 fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]);
886
1072
1073 T = LutTable + K0;
1074 p1.Table = T;
1075
1076 TetrahedralInterpFloat(Input + 1, Tmp1, &p1);
1077
1078 T = LutTable + K1;
1079 p1.Table = T;
1080 TetrahedralInterpFloat(Input + 1, Tmp2, &p1);
1081
1082 for (i=0; i < p -> nOutputs; i++)
1083 {
1084 cmsFloat32Number y0 = Tmp1[i];
1085 cmsFloat32Number y1 = Tmp2[i];
1086
1087 Output[i] = y0 + (y1 - y0) * rest;
1088 }
1089 }
1090
1091
1092 static
1093 void Eval5Inputs(register const cmsUInt16Number Input[],
1094 register cmsUInt16Number Output[],
1095
1096 register const cmsInterpParams* p16)
1097 {
1098 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1099 cmsS15Fixed16Number fk;
1100 cmsS15Fixed16Number k0, rk;
1101 int K0, K1;
1102 const cmsUInt16Number* T;
1103 cmsUInt32Number i;
1104 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1105 cmsInterpParams p1;
1106
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[4] * k0;
1113 K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1114
1115 p1 = *p16;
1116 memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number));
1161 p1.Table = T;
1162
1163 Eval4InputsFloat(Input + 1, Tmp1, &p1);
1164
1165 T = LutTable + K1;
1166 p1.Table = T;
1167
1168 Eval4InputsFloat(Input + 1, Tmp2, &p1);
1169
1170 for (i=0; i < p -> nOutputs; i++) {
1171
1172 cmsFloat32Number y0 = Tmp1[i];
1173 cmsFloat32Number y1 = Tmp2[i];
1174
1175 Output[i] = y0 + (y1 - y0) * rest;
1176 }
1177 }
1178
1179
1180
1181 static
1182 void Eval6Inputs(register const cmsUInt16Number Input[],
1183 register cmsUInt16Number Output[],
1184 register const cmsInterpParams* p16)
1185 {
1186 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1187 cmsS15Fixed16Number fk;
1188 cmsS15Fixed16Number k0, rk;
1189 int K0, K1;
1190 const cmsUInt16Number* T;
1191 cmsUInt32Number i;
1192 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1193 cmsInterpParams p1;
1194
1195 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1196 k0 = FIXED_TO_INT(fk);
1197 rk = FIXED_REST_TO_INT(fk);
1198
1199 K0 = p16 -> opta[5] * k0;
1200 K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1201
1202 p1 = *p16;
1203 memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number));
1204
1247 T = LutTable + K0;
1248 p1.Table = T;
1249
1250 Eval5InputsFloat(Input + 1, Tmp1, &p1);
1251
1252 T = LutTable + K1;
1253 p1.Table = T;
1254
1255 Eval5InputsFloat(Input + 1, Tmp2, &p1);
1256
1257 for (i=0; i < p -> nOutputs; i++) {
1258
1259 cmsFloat32Number y0 = Tmp1[i];
1260 cmsFloat32Number y1 = Tmp2[i];
1261
1262 Output[i] = y0 + (y1 - y0) * rest;
1263 }
1264 }
1265
1266
1267 static
1268 void Eval7Inputs(register const cmsUInt16Number Input[],
1269 register cmsUInt16Number Output[],
1270 register const cmsInterpParams* p16)
1271 {
1272 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1273 cmsS15Fixed16Number fk;
1274 cmsS15Fixed16Number k0, rk;
1275 int K0, K1;
1276 const cmsUInt16Number* T;
1277 cmsUInt32Number i;
1278 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1279 cmsInterpParams p1;
1280
1281
1282 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1283 k0 = FIXED_TO_INT(fk);
1284 rk = FIXED_REST_TO_INT(fk);
1285
1286 K0 = p16 -> opta[6] * k0;
1287 K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1288
1289 p1 = *p16;
1290 memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number));
1333 p1.Table = T;
1334
1335 Eval6InputsFloat(Input + 1, Tmp1, &p1);
1336
1337 T = LutTable + K1;
1338 p1.Table = T;
1339
1340 Eval6InputsFloat(Input + 1, Tmp2, &p1);
1341
1342
1343 for (i=0; i < p -> nOutputs; i++) {
1344
1345 cmsFloat32Number y0 = Tmp1[i];
1346 cmsFloat32Number y1 = Tmp2[i];
1347
1348 Output[i] = y0 + (y1 - y0) * rest;
1349
1350 }
1351 }
1352
1353 static
1354 void Eval8Inputs(register const cmsUInt16Number Input[],
1355 register cmsUInt16Number Output[],
1356 register const cmsInterpParams* p16)
1357 {
1358 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1359 cmsS15Fixed16Number fk;
1360 cmsS15Fixed16Number k0, rk;
1361 int K0, K1;
1362 const cmsUInt16Number* T;
1363 cmsUInt32Number i;
1364 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1365 cmsInterpParams p1;
1366
1367 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1368 k0 = FIXED_TO_INT(fk);
1369 rk = FIXED_REST_TO_INT(fk);
1370
1371 K0 = p16 -> opta[7] * k0;
1372 K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1373
1374 p1 = *p16;
1375 memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number));
1376
|
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 // This file is available under and governed by the GNU General Public
26 // License version 2 only, as published by the Free Software Foundation.
27 // However, the following notice accompanied the original version of this
28 // file:
29 //
30 //---------------------------------------------------------------------------------
31 //
32 // Little Color Management System
33 // Copyright (c) 1998-2020 Marti Maria Saguer
34 //
35 // Permission is hereby granted, free of charge, to any person obtaining
36 // a copy of this software and associated documentation files (the "Software"),
37 // to deal in the Software without restriction, including without limitation
38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
39 // and/or sell copies of the Software, and to permit persons to whom the Software
40 // is furnished to do so, subject to the following conditions:
41 //
42 // The above copyright notice and this permission notice shall be included in
43 // all copies or substantial portions of the Software.
44 //
45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 //
53 //---------------------------------------------------------------------------------
193 int i;
194 cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];
195
196 // Fill the auxiliary array
197 for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
198 Samples[i] = nSamples;
199
200 // Call the extended function
201 return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags);
202 }
203
204
205 // Free all associated memory
206 void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p)
207 {
208 if (p != NULL) _cmsFree(p ->ContextID, p);
209 }
210
211
212 // Inline fixed point interpolation
213 cmsINLINE CMS_NO_SANITIZE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h)
214 {
215 cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000;
216 dif = (dif >> 16) + l;
217 return (cmsUInt16Number) (dif);
218 }
219
220
221 // Linear interpolation (Fixed-point optimized)
222 static
223 void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[],
224 CMSREGISTER cmsUInt16Number Output[],
225 CMSREGISTER const cmsInterpParams* p)
226 {
227 cmsUInt16Number y1, y0;
228 int cell0, rest;
229 int val3;
230 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
231
232 // if last value...
233 if (Value[0] == 0xffff) {
234
235 Output[0] = LutTable[p -> Domain[0]];
236 }
237 else
238 {
239 val3 = p->Domain[0] * Value[0];
240 val3 = _cmsToFixedDomain(val3); // To fixed 15.16
241
242 cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits
243 rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits
244
245 y0 = LutTable[cell0];
246 y1 = LutTable[cell0 + 1];
247
248 Output[0] = LinearInterp(rest, y0, y1);
249 }
250 }
251
252 // To prevent out of bounds indexing
253 cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v)
254 {
255 return ((v < 1.0e-9f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v);
256 }
257
258 // Floating-point version of 1D interpolation
259 static
260 void LinLerp1Dfloat(const cmsFloat32Number Value[],
261 cmsFloat32Number Output[],
262 const cmsInterpParams* p)
263 {
264 cmsFloat32Number y1, y0;
265 cmsFloat32Number val2, rest;
266 int cell0, cell1;
267 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
268
269 val2 = fclamp(Value[0]);
270
271 // if last value...
272 if (val2 == 1.0) {
273 Output[0] = LutTable[p -> Domain[0]];
274 }
275 else
276 {
277 val2 *= p->Domain[0];
278
279 cell0 = (int)floor(val2);
280 cell1 = (int)ceil(val2);
281
282 // Rest is 16 LSB bits
283 rest = val2 - cell0;
284
285 y0 = LutTable[cell0];
286 y1 = LutTable[cell1];
287
288 Output[0] = y0 + (y1 - y0) * rest;
289 }
290 }
291
292
293
294 // Eval gray LUT having only one input channel
295 static CMS_NO_SANITIZE
296 void Eval1Input(CMSREGISTER const cmsUInt16Number Input[],
297 CMSREGISTER cmsUInt16Number Output[],
298 CMSREGISTER const cmsInterpParams* p16)
299 {
300 cmsS15Fixed16Number fk;
301 cmsS15Fixed16Number k0, k1, rk, K0, K1;
302 int v;
303 cmsUInt32Number OutChan;
304 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
305
306 v = Input[0] * p16 -> Domain[0];
307 fk = _cmsToFixedDomain(v);
308
309 k0 = FIXED_TO_INT(fk);
310 rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
311
312 k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
313
314 K0 = p16 -> opta[0] * k0;
315 K1 = p16 -> opta[0] * k1;
316
317 for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
318
321 }
322
323
324
325 // Eval gray LUT having only one input channel
326 static
327 void Eval1InputFloat(const cmsFloat32Number Value[],
328 cmsFloat32Number Output[],
329 const cmsInterpParams* p)
330 {
331 cmsFloat32Number y1, y0;
332 cmsFloat32Number val2, rest;
333 int cell0, cell1;
334 cmsUInt32Number OutChan;
335 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
336
337 val2 = fclamp(Value[0]);
338
339 // if last value...
340 if (val2 == 1.0) {
341
342 y0 = LutTable[p->Domain[0]];
343
344 for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {
345 Output[OutChan] = y0;
346 }
347 }
348 else
349 {
350 val2 *= p->Domain[0];
351
352 cell0 = (int)floor(val2);
353 cell1 = (int)ceil(val2);
354
355 // Rest is 16 LSB bits
356 rest = val2 - cell0;
357
358 cell0 *= p->opta[0];
359 cell1 *= p->opta[0];
360
361 for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {
362
363 y0 = LutTable[cell0 + OutChan];
364 y1 = LutTable[cell1 + OutChan];
365
366 Output[OutChan] = y0 + (y1 - y0) * rest;
367 }
368 }
369 }
370
371 // Bilinear interpolation (16 bits) - cmsFloat32Number version
372 static
373 void BilinearInterpFloat(const cmsFloat32Number Input[],
374 cmsFloat32Number Output[],
375 const cmsInterpParams* p)
376
377 {
378 # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
379 # define DENS(i,j) (LutTable[(i)+(j)+OutChan])
380
381 const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
382 cmsFloat32Number px, py;
383 int x0, y0,
384 X0, Y0, X1, Y1;
385 int TotalOut, OutChan;
386 cmsFloat32Number fx, fy,
387 d00, d01, d10, d11,
388 dx0, dx1,
405
406 d00 = DENS(X0, Y0);
407 d01 = DENS(X0, Y1);
408 d10 = DENS(X1, Y0);
409 d11 = DENS(X1, Y1);
410
411 dx0 = LERP(fx, d00, d10);
412 dx1 = LERP(fx, d01, d11);
413
414 dxy = LERP(fy, dx0, dx1);
415
416 Output[OutChan] = dxy;
417 }
418
419
420 # undef LERP
421 # undef DENS
422 }
423
424 // Bilinear interpolation (16 bits) - optimized version
425 static CMS_NO_SANITIZE
426 void BilinearInterp16(CMSREGISTER const cmsUInt16Number Input[],
427 CMSREGISTER cmsUInt16Number Output[],
428 CMSREGISTER const cmsInterpParams* p)
429
430 {
431 #define DENS(i,j) (LutTable[(i)+(j)+OutChan])
432 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
433
434 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
435 int OutChan, TotalOut;
436 cmsS15Fixed16Number fx, fy;
437 CMSREGISTER int rx, ry;
438 int x0, y0;
439 CMSREGISTER int X0, X1, Y0, Y1;
440 int d00, d01, d10, d11,
441 dx0, dx1,
442 dxy;
443
444 TotalOut = p -> nOutputs;
445
446 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
447 x0 = FIXED_TO_INT(fx);
448 rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain
449
450
451 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
452 y0 = FIXED_TO_INT(fy);
453 ry = FIXED_REST_TO_INT(fy);
454
455
456 X0 = p -> opta[1] * x0;
457 X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]);
458
459 Y0 = p -> opta[0] * y0;
536
537 dx00 = LERP(fx, d000, d100);
538 dx01 = LERP(fx, d001, d101);
539 dx10 = LERP(fx, d010, d110);
540 dx11 = LERP(fx, d011, d111);
541
542 dxy0 = LERP(fy, dx00, dx10);
543 dxy1 = LERP(fy, dx01, dx11);
544
545 dxyz = LERP(fz, dxy0, dxy1);
546
547 Output[OutChan] = dxyz;
548 }
549
550
551 # undef LERP
552 # undef DENS
553 }
554
555 // Trilinear interpolation (16 bits) - optimized version
556 static CMS_NO_SANITIZE
557 void TrilinearInterp16(CMSREGISTER const cmsUInt16Number Input[],
558 CMSREGISTER cmsUInt16Number Output[],
559 CMSREGISTER const cmsInterpParams* p)
560
561 {
562 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
563 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
564
565 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
566 int OutChan, TotalOut;
567 cmsS15Fixed16Number fx, fy, fz;
568 CMSREGISTER int rx, ry, rz;
569 int x0, y0, z0;
570 CMSREGISTER int X0, X1, Y0, Y1, Z0, Z1;
571 int d000, d001, d010, d011,
572 d100, d101, d110, d111,
573 dx00, dx01, dx10, dx11,
574 dxy0, dxy1, dxyz;
575
576 TotalOut = p -> nOutputs;
577
578 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
579 x0 = FIXED_TO_INT(fx);
580 rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain
581
582
583 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
584 y0 = FIXED_TO_INT(fy);
585 ry = FIXED_REST_TO_INT(fy);
586
587 fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
588 z0 = FIXED_TO_INT(fz);
589 rz = FIXED_REST_TO_INT(fz);
590
716
717 c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
718 c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
719 c3 = DENS(X0, Y0, Z1) - c0;
720
721 }
722 else {
723 c1 = c2 = c3 = 0;
724 }
725
726 Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz;
727 }
728
729 }
730
731 #undef DENS
732
733
734
735
736 static CMS_NO_SANITIZE
737 void TetrahedralInterp16(CMSREGISTER const cmsUInt16Number Input[],
738 CMSREGISTER cmsUInt16Number Output[],
739 CMSREGISTER const cmsInterpParams* p)
740 {
741 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;
742 cmsS15Fixed16Number fx, fy, fz;
743 cmsS15Fixed16Number rx, ry, rz;
744 int x0, y0, z0;
745 cmsS15Fixed16Number c0, c1, c2, c3, Rest;
746 cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
747 cmsUInt32Number TotalOut = p -> nOutputs;
748
749 fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
750 fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
751 fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
752
753 x0 = FIXED_TO_INT(fx);
754 y0 = FIXED_TO_INT(fy);
755 z0 = FIXED_TO_INT(fz);
756
757 rx = FIXED_REST_TO_INT(fx);
758 ry = FIXED_REST_TO_INT(fy);
759 rz = FIXED_REST_TO_INT(fz);
850 } else {
851 Y1 += Z1;
852 X1 += Y1;
853 for (; TotalOut; TotalOut--) {
854 c1 = LutTable[X1];
855 c2 = LutTable[Y1];
856 c3 = LutTable[Z1];
857 c0 = *LutTable++;
858 c1 -= c2;
859 c2 -= c3;
860 c3 -= c0;
861 Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
862 *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
863 }
864 }
865 }
866 }
867
868
869 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
870 static CMS_NO_SANITIZE
871 void Eval4Inputs(CMSREGISTER const cmsUInt16Number Input[],
872 CMSREGISTER cmsUInt16Number Output[],
873 CMSREGISTER const cmsInterpParams* p16)
874 {
875 const cmsUInt16Number* LutTable;
876 cmsS15Fixed16Number fk;
877 cmsS15Fixed16Number k0, rk;
878 int K0, K1;
879 cmsS15Fixed16Number fx, fy, fz;
880 cmsS15Fixed16Number rx, ry, rz;
881 int x0, y0, z0;
882 cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
883 cmsUInt32Number i;
884 cmsS15Fixed16Number c0, c1, c2, c3, Rest;
885 cmsUInt32Number OutChan;
886 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
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
1079
1080 T = LutTable + K0;
1081 p1.Table = T;
1082
1083 TetrahedralInterpFloat(Input + 1, Tmp1, &p1);
1084
1085 T = LutTable + K1;
1086 p1.Table = T;
1087 TetrahedralInterpFloat(Input + 1, Tmp2, &p1);
1088
1089 for (i=0; i < p -> nOutputs; i++)
1090 {
1091 cmsFloat32Number y0 = Tmp1[i];
1092 cmsFloat32Number y1 = Tmp2[i];
1093
1094 Output[i] = y0 + (y1 - y0) * rest;
1095 }
1096 }
1097
1098
1099 static CMS_NO_SANITIZE
1100 void Eval5Inputs(CMSREGISTER const cmsUInt16Number Input[],
1101 CMSREGISTER cmsUInt16Number Output[],
1102
1103 CMSREGISTER const cmsInterpParams* p16)
1104 {
1105 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1106 cmsS15Fixed16Number fk;
1107 cmsS15Fixed16Number k0, rk;
1108 int K0, K1;
1109 const cmsUInt16Number* T;
1110 cmsUInt32Number i;
1111 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1112 cmsInterpParams p1;
1113
1114
1115 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1116 k0 = FIXED_TO_INT(fk);
1117 rk = FIXED_REST_TO_INT(fk);
1118
1119 K0 = p16 -> opta[4] * k0;
1120 K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1121
1122 p1 = *p16;
1123 memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number));
1168 p1.Table = T;
1169
1170 Eval4InputsFloat(Input + 1, Tmp1, &p1);
1171
1172 T = LutTable + K1;
1173 p1.Table = T;
1174
1175 Eval4InputsFloat(Input + 1, Tmp2, &p1);
1176
1177 for (i=0; i < p -> nOutputs; i++) {
1178
1179 cmsFloat32Number y0 = Tmp1[i];
1180 cmsFloat32Number y1 = Tmp2[i];
1181
1182 Output[i] = y0 + (y1 - y0) * rest;
1183 }
1184 }
1185
1186
1187
1188 static CMS_NO_SANITIZE
1189 void Eval6Inputs(CMSREGISTER const cmsUInt16Number Input[],
1190 CMSREGISTER cmsUInt16Number Output[],
1191 CMSREGISTER const cmsInterpParams* p16)
1192 {
1193 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1194 cmsS15Fixed16Number fk;
1195 cmsS15Fixed16Number k0, rk;
1196 int K0, K1;
1197 const cmsUInt16Number* T;
1198 cmsUInt32Number i;
1199 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1200 cmsInterpParams p1;
1201
1202 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1203 k0 = FIXED_TO_INT(fk);
1204 rk = FIXED_REST_TO_INT(fk);
1205
1206 K0 = p16 -> opta[5] * k0;
1207 K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1208
1209 p1 = *p16;
1210 memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number));
1211
1254 T = LutTable + K0;
1255 p1.Table = T;
1256
1257 Eval5InputsFloat(Input + 1, Tmp1, &p1);
1258
1259 T = LutTable + K1;
1260 p1.Table = T;
1261
1262 Eval5InputsFloat(Input + 1, Tmp2, &p1);
1263
1264 for (i=0; i < p -> nOutputs; i++) {
1265
1266 cmsFloat32Number y0 = Tmp1[i];
1267 cmsFloat32Number y1 = Tmp2[i];
1268
1269 Output[i] = y0 + (y1 - y0) * rest;
1270 }
1271 }
1272
1273
1274 static CMS_NO_SANITIZE
1275 void Eval7Inputs(CMSREGISTER const cmsUInt16Number Input[],
1276 CMSREGISTER cmsUInt16Number Output[],
1277 CMSREGISTER const cmsInterpParams* p16)
1278 {
1279 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1280 cmsS15Fixed16Number fk;
1281 cmsS15Fixed16Number k0, rk;
1282 int K0, K1;
1283 const cmsUInt16Number* T;
1284 cmsUInt32Number i;
1285 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1286 cmsInterpParams p1;
1287
1288
1289 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1290 k0 = FIXED_TO_INT(fk);
1291 rk = FIXED_REST_TO_INT(fk);
1292
1293 K0 = p16 -> opta[6] * k0;
1294 K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1295
1296 p1 = *p16;
1297 memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number));
1340 p1.Table = T;
1341
1342 Eval6InputsFloat(Input + 1, Tmp1, &p1);
1343
1344 T = LutTable + K1;
1345 p1.Table = T;
1346
1347 Eval6InputsFloat(Input + 1, Tmp2, &p1);
1348
1349
1350 for (i=0; i < p -> nOutputs; i++) {
1351
1352 cmsFloat32Number y0 = Tmp1[i];
1353 cmsFloat32Number y1 = Tmp2[i];
1354
1355 Output[i] = y0 + (y1 - y0) * rest;
1356
1357 }
1358 }
1359
1360 static CMS_NO_SANITIZE
1361 void Eval8Inputs(CMSREGISTER const cmsUInt16Number Input[],
1362 CMSREGISTER cmsUInt16Number Output[],
1363 CMSREGISTER const cmsInterpParams* p16)
1364 {
1365 const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
1366 cmsS15Fixed16Number fk;
1367 cmsS15Fixed16Number k0, rk;
1368 int K0, K1;
1369 const cmsUInt16Number* T;
1370 cmsUInt32Number i;
1371 cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1372 cmsInterpParams p1;
1373
1374 fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
1375 k0 = FIXED_TO_INT(fk);
1376 rk = FIXED_REST_TO_INT(fk);
1377
1378 K0 = p16 -> opta[7] * k0;
1379 K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
1380
1381 p1 = *p16;
1382 memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number));
1383
|