Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c
38918 views
/*1* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation. Oracle designates this6* particular file as subject to the "Classpath" exception as provided7* by Oracle in the LICENSE file that accompanied this code.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324// This file is available under and governed by the GNU General Public25// License version 2 only, as published by the Free Software Foundation.26// However, the following notice accompanied the original version of this27// file:28//29//---------------------------------------------------------------------------------30//31// Little Color Management System32// Copyright (c) 1998-2020 Marti Maria Saguer33//34// Permission is hereby granted, free of charge, to any person obtaining35// a copy of this software and associated documentation files (the "Software"),36// to deal in the Software without restriction, including without limitation37// the rights to use, copy, modify, merge, publish, distribute, sublicense,38// and/or sell copies of the Software, and to permit persons to whom the Software39// is furnished to do so, subject to the following conditions:40//41// The above copyright notice and this permission notice shall be included in42// all copies or substantial portions of the Software.43//44// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,45// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO46// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND47// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE48// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION49// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION50// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.51//52//---------------------------------------------------------------------------------53//5455#include "lcms2_internal.h"5657// This module incorporates several interpolation routines, for 1 to 8 channels on input and58// up to 65535 channels on output. The user may change those by using the interpolation plug-in5960// Some people may want to compile as C++ with all warnings on, in this case make compiler silent61#ifdef _MSC_VER62# if (_MSC_VER >= 1400)63# pragma warning( disable : 4365 )64# endif65#endif6667// Interpolation routines by default68static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);6970// This is the default factory71_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL };7273// The interpolation plug-in memory chunk allocator/dup74void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src)75{76void* from;7778_cmsAssert(ctx != NULL);7980if (src != NULL) {81from = src ->chunks[InterpPlugin];82}83else {84static _cmsInterpPluginChunkType InterpPluginChunk = { NULL };8586from = &InterpPluginChunk;87}8889_cmsAssert(from != NULL);90ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType));91}929394// Main plug-in entry95cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data)96{97cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data;98_cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);99100if (Data == NULL) {101102ptr ->Interpolators = NULL;103return TRUE;104}105106// Set replacement functions107ptr ->Interpolators = Plugin ->InterpolatorsFactory;108return TRUE;109}110111112// Set the interpolation method113cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p)114{115_cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);116117p ->Interpolation.Lerp16 = NULL;118119// Invoke factory, possibly in the Plug-in120if (ptr ->Interpolators != NULL)121p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);122123// If unsupported by the plug-in, go for the LittleCMS default.124// If happens only if an extern plug-in is being used125if (p ->Interpolation.Lerp16 == NULL)126p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags);127128// Check for valid interpolator (we just check one member of the union)129if (p ->Interpolation.Lerp16 == NULL) {130return FALSE;131}132133return TRUE;134}135136137// This function precalculates as many parameters as possible to speed up the interpolation.138cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,139const cmsUInt32Number nSamples[],140cmsUInt32Number InputChan, cmsUInt32Number OutputChan,141const void *Table,142cmsUInt32Number dwFlags)143{144cmsInterpParams* p;145cmsUInt32Number i;146147// Check for maximum inputs148if (InputChan > MAX_INPUT_DIMENSIONS) {149cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS);150return NULL;151}152153// Creates an empty object154p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams));155if (p == NULL) return NULL;156157// Keep original parameters158p -> dwFlags = dwFlags;159p -> nInputs = InputChan;160p -> nOutputs = OutputChan;161p ->Table = Table;162p ->ContextID = ContextID;163164// Fill samples per input direction and domain (which is number of nodes minus one)165for (i=0; i < InputChan; i++) {166167p -> nSamples[i] = nSamples[i];168p -> Domain[i] = nSamples[i] - 1;169}170171// Compute factors to apply to each component to index the grid array172p -> opta[0] = p -> nOutputs;173for (i=1; i < InputChan; i++)174p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];175176177if (!_cmsSetInterpolationRoutine(ContextID, p)) {178cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan);179_cmsFree(ContextID, p);180return NULL;181}182183// All seems ok184return p;185}186187188// This one is a wrapper on the anterior, but assuming all directions have same number of nodes189cmsInterpParams* CMSEXPORT _cmsComputeInterpParams(cmsContext ContextID, cmsUInt32Number nSamples,190cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags)191{192int i;193cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];194195// Fill the auxiliary array196for (i=0; i < MAX_INPUT_DIMENSIONS; i++)197Samples[i] = nSamples;198199// Call the extended function200return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags);201}202203204// Free all associated memory205void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p)206{207if (p != NULL) _cmsFree(p ->ContextID, p);208}209210211// Inline fixed point interpolation212cmsINLINE CMS_NO_SANITIZE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h)213{214cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000;215dif = (dif >> 16) + l;216return (cmsUInt16Number) (dif);217}218219220// Linear interpolation (Fixed-point optimized)221static222void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[],223CMSREGISTER cmsUInt16Number Output[],224CMSREGISTER const cmsInterpParams* p)225{226cmsUInt16Number y1, y0;227int cell0, rest;228int val3;229const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;230231// if last value...232if (Value[0] == 0xffff) {233234Output[0] = LutTable[p -> Domain[0]];235}236else237{238val3 = p->Domain[0] * Value[0];239val3 = _cmsToFixedDomain(val3); // To fixed 15.16240241cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits242rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits243244y0 = LutTable[cell0];245y1 = LutTable[cell0 + 1];246247Output[0] = LinearInterp(rest, y0, y1);248}249}250251// To prevent out of bounds indexing252cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v)253{254return ((v < 1.0e-9f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v);255}256257// Floating-point version of 1D interpolation258static259void LinLerp1Dfloat(const cmsFloat32Number Value[],260cmsFloat32Number Output[],261const cmsInterpParams* p)262{263cmsFloat32Number y1, y0;264cmsFloat32Number val2, rest;265int cell0, cell1;266const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;267268val2 = fclamp(Value[0]);269270// if last value...271if (val2 == 1.0) {272Output[0] = LutTable[p -> Domain[0]];273}274else275{276val2 *= p->Domain[0];277278cell0 = (int)floor(val2);279cell1 = (int)ceil(val2);280281// Rest is 16 LSB bits282rest = val2 - cell0;283284y0 = LutTable[cell0];285y1 = LutTable[cell1];286287Output[0] = y0 + (y1 - y0) * rest;288}289}290291292293// Eval gray LUT having only one input channel294static CMS_NO_SANITIZE295void Eval1Input(CMSREGISTER const cmsUInt16Number Input[],296CMSREGISTER cmsUInt16Number Output[],297CMSREGISTER const cmsInterpParams* p16)298{299cmsS15Fixed16Number fk;300cmsS15Fixed16Number k0, k1, rk, K0, K1;301int v;302cmsUInt32Number OutChan;303const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;304305v = Input[0] * p16 -> Domain[0];306fk = _cmsToFixedDomain(v);307308k0 = FIXED_TO_INT(fk);309rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);310311k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);312313K0 = p16 -> opta[0] * k0;314K1 = p16 -> opta[0] * k1;315316for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {317318Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]);319}320}321322323324// Eval gray LUT having only one input channel325static326void Eval1InputFloat(const cmsFloat32Number Value[],327cmsFloat32Number Output[],328const cmsInterpParams* p)329{330cmsFloat32Number y1, y0;331cmsFloat32Number val2, rest;332int cell0, cell1;333cmsUInt32Number OutChan;334const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;335336val2 = fclamp(Value[0]);337338// if last value...339if (val2 == 1.0) {340341y0 = LutTable[p->Domain[0]];342343for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {344Output[OutChan] = y0;345}346}347else348{349val2 *= p->Domain[0];350351cell0 = (int)floor(val2);352cell1 = (int)ceil(val2);353354// Rest is 16 LSB bits355rest = val2 - cell0;356357cell0 *= p->opta[0];358cell1 *= p->opta[0];359360for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {361362y0 = LutTable[cell0 + OutChan];363y1 = LutTable[cell1 + OutChan];364365Output[OutChan] = y0 + (y1 - y0) * rest;366}367}368}369370// Bilinear interpolation (16 bits) - cmsFloat32Number version371static372void BilinearInterpFloat(const cmsFloat32Number Input[],373cmsFloat32Number Output[],374const cmsInterpParams* p)375376{377# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))378# define DENS(i,j) (LutTable[(i)+(j)+OutChan])379380const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;381cmsFloat32Number px, py;382int x0, y0,383X0, Y0, X1, Y1;384int TotalOut, OutChan;385cmsFloat32Number fx, fy,386d00, d01, d10, d11,387dx0, dx1,388dxy;389390TotalOut = p -> nOutputs;391px = fclamp(Input[0]) * p->Domain[0];392py = fclamp(Input[1]) * p->Domain[1];393394x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;395y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;396397X0 = p -> opta[1] * x0;398X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[1]);399400Y0 = p -> opta[0] * y0;401Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[0]);402403for (OutChan = 0; OutChan < TotalOut; OutChan++) {404405d00 = DENS(X0, Y0);406d01 = DENS(X0, Y1);407d10 = DENS(X1, Y0);408d11 = DENS(X1, Y1);409410dx0 = LERP(fx, d00, d10);411dx1 = LERP(fx, d01, d11);412413dxy = LERP(fy, dx0, dx1);414415Output[OutChan] = dxy;416}417418419# undef LERP420# undef DENS421}422423// Bilinear interpolation (16 bits) - optimized version424static CMS_NO_SANITIZE425void BilinearInterp16(CMSREGISTER const cmsUInt16Number Input[],426CMSREGISTER cmsUInt16Number Output[],427CMSREGISTER const cmsInterpParams* p)428429{430#define DENS(i,j) (LutTable[(i)+(j)+OutChan])431#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))432433const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;434int OutChan, TotalOut;435cmsS15Fixed16Number fx, fy;436CMSREGISTER int rx, ry;437int x0, y0;438CMSREGISTER int X0, X1, Y0, Y1;439int d00, d01, d10, d11,440dx0, dx1,441dxy;442443TotalOut = p -> nOutputs;444445fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);446x0 = FIXED_TO_INT(fx);447rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain448449450fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);451y0 = FIXED_TO_INT(fy);452ry = FIXED_REST_TO_INT(fy);453454455X0 = p -> opta[1] * x0;456X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]);457458Y0 = p -> opta[0] * y0;459Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]);460461for (OutChan = 0; OutChan < TotalOut; OutChan++) {462463d00 = DENS(X0, Y0);464d01 = DENS(X0, Y1);465d10 = DENS(X1, Y0);466d11 = DENS(X1, Y1);467468dx0 = LERP(rx, d00, d10);469dx1 = LERP(rx, d01, d11);470471dxy = LERP(ry, dx0, dx1);472473Output[OutChan] = (cmsUInt16Number) dxy;474}475476477# undef LERP478# undef DENS479}480481482// Trilinear interpolation (16 bits) - cmsFloat32Number version483static484void TrilinearInterpFloat(const cmsFloat32Number Input[],485cmsFloat32Number Output[],486const cmsInterpParams* p)487488{489# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))490# define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])491492const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;493cmsFloat32Number px, py, pz;494int x0, y0, z0,495X0, Y0, Z0, X1, Y1, Z1;496int TotalOut, OutChan;497cmsFloat32Number fx, fy, fz,498d000, d001, d010, d011,499d100, d101, d110, d111,500dx00, dx01, dx10, dx11,501dxy0, dxy1, dxyz;502503TotalOut = p -> nOutputs;504505// We need some clipping here506px = fclamp(Input[0]) * p->Domain[0];507py = fclamp(Input[1]) * p->Domain[1];508pz = fclamp(Input[2]) * p->Domain[2];509510x0 = (int) floor(px); fx = px - (cmsFloat32Number) x0; // We need full floor funcionality here511y0 = (int) floor(py); fy = py - (cmsFloat32Number) y0;512z0 = (int) floor(pz); fz = pz - (cmsFloat32Number) z0;513514X0 = p -> opta[2] * x0;515X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);516517Y0 = p -> opta[1] * y0;518Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);519520Z0 = p -> opta[0] * z0;521Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);522523for (OutChan = 0; OutChan < TotalOut; OutChan++) {524525d000 = DENS(X0, Y0, Z0);526d001 = DENS(X0, Y0, Z1);527d010 = DENS(X0, Y1, Z0);528d011 = DENS(X0, Y1, Z1);529530d100 = DENS(X1, Y0, Z0);531d101 = DENS(X1, Y0, Z1);532d110 = DENS(X1, Y1, Z0);533d111 = DENS(X1, Y1, Z1);534535536dx00 = LERP(fx, d000, d100);537dx01 = LERP(fx, d001, d101);538dx10 = LERP(fx, d010, d110);539dx11 = LERP(fx, d011, d111);540541dxy0 = LERP(fy, dx00, dx10);542dxy1 = LERP(fy, dx01, dx11);543544dxyz = LERP(fz, dxy0, dxy1);545546Output[OutChan] = dxyz;547}548549550# undef LERP551# undef DENS552}553554// Trilinear interpolation (16 bits) - optimized version555static CMS_NO_SANITIZE556void TrilinearInterp16(CMSREGISTER const cmsUInt16Number Input[],557CMSREGISTER cmsUInt16Number Output[],558CMSREGISTER const cmsInterpParams* p)559560{561#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])562#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))563564const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;565int OutChan, TotalOut;566cmsS15Fixed16Number fx, fy, fz;567CMSREGISTER int rx, ry, rz;568int x0, y0, z0;569CMSREGISTER int X0, X1, Y0, Y1, Z0, Z1;570int d000, d001, d010, d011,571d100, d101, d110, d111,572dx00, dx01, dx10, dx11,573dxy0, dxy1, dxyz;574575TotalOut = p -> nOutputs;576577fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);578x0 = FIXED_TO_INT(fx);579rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain580581582fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);583y0 = FIXED_TO_INT(fy);584ry = FIXED_REST_TO_INT(fy);585586fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);587z0 = FIXED_TO_INT(fz);588rz = FIXED_REST_TO_INT(fz);589590591X0 = p -> opta[2] * x0;592X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);593594Y0 = p -> opta[1] * y0;595Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);596597Z0 = p -> opta[0] * z0;598Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);599600for (OutChan = 0; OutChan < TotalOut; OutChan++) {601602d000 = DENS(X0, Y0, Z0);603d001 = DENS(X0, Y0, Z1);604d010 = DENS(X0, Y1, Z0);605d011 = DENS(X0, Y1, Z1);606607d100 = DENS(X1, Y0, Z0);608d101 = DENS(X1, Y0, Z1);609d110 = DENS(X1, Y1, Z0);610d111 = DENS(X1, Y1, Z1);611612613dx00 = LERP(rx, d000, d100);614dx01 = LERP(rx, d001, d101);615dx10 = LERP(rx, d010, d110);616dx11 = LERP(rx, d011, d111);617618dxy0 = LERP(ry, dx00, dx10);619dxy1 = LERP(ry, dx01, dx11);620621dxyz = LERP(rz, dxy0, dxy1);622623Output[OutChan] = (cmsUInt16Number) dxyz;624}625626627# undef LERP628# undef DENS629}630631632// Tetrahedral interpolation, using Sakamoto algorithm.633#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])634static635void TetrahedralInterpFloat(const cmsFloat32Number Input[],636cmsFloat32Number Output[],637const cmsInterpParams* p)638{639const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;640cmsFloat32Number px, py, pz;641int x0, y0, z0,642X0, Y0, Z0, X1, Y1, Z1;643cmsFloat32Number rx, ry, rz;644cmsFloat32Number c0, c1=0, c2=0, c3=0;645int OutChan, TotalOut;646647TotalOut = p -> nOutputs;648649// We need some clipping here650px = fclamp(Input[0]) * p->Domain[0];651py = fclamp(Input[1]) * p->Domain[1];652pz = fclamp(Input[2]) * p->Domain[2];653654x0 = (int) floor(px); rx = (px - (cmsFloat32Number) x0); // We need full floor functionality here655y0 = (int) floor(py); ry = (py - (cmsFloat32Number) y0);656z0 = (int) floor(pz); rz = (pz - (cmsFloat32Number) z0);657658659X0 = p -> opta[2] * x0;660X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);661662Y0 = p -> opta[1] * y0;663Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);664665Z0 = p -> opta[0] * z0;666Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);667668for (OutChan=0; OutChan < TotalOut; OutChan++) {669670// These are the 6 Tetrahedral671672c0 = DENS(X0, Y0, Z0);673674if (rx >= ry && ry >= rz) {675676c1 = DENS(X1, Y0, Z0) - c0;677c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);678c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);679680}681else682if (rx >= rz && rz >= ry) {683684c1 = DENS(X1, Y0, Z0) - c0;685c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);686c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);687688}689else690if (rz >= rx && rx >= ry) {691692c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);693c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);694c3 = DENS(X0, Y0, Z1) - c0;695696}697else698if (ry >= rx && rx >= rz) {699700c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);701c2 = DENS(X0, Y1, Z0) - c0;702c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);703704}705else706if (ry >= rz && rz >= rx) {707708c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);709c2 = DENS(X0, Y1, Z0) - c0;710c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);711712}713else714if (rz >= ry && ry >= rx) {715716c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);717c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);718c3 = DENS(X0, Y0, Z1) - c0;719720}721else {722c1 = c2 = c3 = 0;723}724725Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz;726}727728}729730#undef DENS731732733734735static CMS_NO_SANITIZE736void TetrahedralInterp16(CMSREGISTER const cmsUInt16Number Input[],737CMSREGISTER cmsUInt16Number Output[],738CMSREGISTER const cmsInterpParams* p)739{740const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;741cmsS15Fixed16Number fx, fy, fz;742cmsS15Fixed16Number rx, ry, rz;743int x0, y0, z0;744cmsS15Fixed16Number c0, c1, c2, c3, Rest;745cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;746cmsUInt32Number TotalOut = p -> nOutputs;747748fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);749fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);750fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);751752x0 = FIXED_TO_INT(fx);753y0 = FIXED_TO_INT(fy);754z0 = FIXED_TO_INT(fz);755756rx = FIXED_REST_TO_INT(fx);757ry = FIXED_REST_TO_INT(fy);758rz = FIXED_REST_TO_INT(fz);759760X0 = p -> opta[2] * x0;761X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]);762763Y0 = p -> opta[1] * y0;764Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]);765766Z0 = p -> opta[0] * z0;767Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]);768769LutTable = &LutTable[X0+Y0+Z0];770771// Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))772// which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16773// This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16774// at the cost of being off by one at 7fff and 17ffe.775776if (rx >= ry) {777if (ry >= rz) {778Y1 += X1;779Z1 += Y1;780for (; TotalOut; TotalOut--) {781c1 = LutTable[X1];782c2 = LutTable[Y1];783c3 = LutTable[Z1];784c0 = *LutTable++;785c3 -= c2;786c2 -= c1;787c1 -= c0;788Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;789*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);790}791} else if (rz >= rx) {792X1 += Z1;793Y1 += X1;794for (; TotalOut; TotalOut--) {795c1 = LutTable[X1];796c2 = LutTable[Y1];797c3 = LutTable[Z1];798c0 = *LutTable++;799c2 -= c1;800c1 -= c3;801c3 -= c0;802Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;803*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);804}805} else {806Z1 += X1;807Y1 += Z1;808for (; TotalOut; TotalOut--) {809c1 = LutTable[X1];810c2 = LutTable[Y1];811c3 = LutTable[Z1];812c0 = *LutTable++;813c2 -= c3;814c3 -= c1;815c1 -= c0;816Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;817*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);818}819}820} else {821if (rx >= rz) {822X1 += Y1;823Z1 += X1;824for (; TotalOut; TotalOut--) {825c1 = LutTable[X1];826c2 = LutTable[Y1];827c3 = LutTable[Z1];828c0 = *LutTable++;829c3 -= c1;830c1 -= c2;831c2 -= c0;832Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;833*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);834}835} else if (ry >= rz) {836Z1 += Y1;837X1 += Z1;838for (; TotalOut; TotalOut--) {839c1 = LutTable[X1];840c2 = LutTable[Y1];841c3 = LutTable[Z1];842c0 = *LutTable++;843c1 -= c3;844c3 -= c2;845c2 -= c0;846Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;847*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);848}849} else {850Y1 += Z1;851X1 += Y1;852for (; TotalOut; TotalOut--) {853c1 = LutTable[X1];854c2 = LutTable[Y1];855c3 = LutTable[Z1];856c0 = *LutTable++;857c1 -= c2;858c2 -= c3;859c3 -= c0;860Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;861*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);862}863}864}865}866867868#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])869static CMS_NO_SANITIZE870void Eval4Inputs(CMSREGISTER const cmsUInt16Number Input[],871CMSREGISTER cmsUInt16Number Output[],872CMSREGISTER const cmsInterpParams* p16)873{874const cmsUInt16Number* LutTable;875cmsS15Fixed16Number fk;876cmsS15Fixed16Number k0, rk;877int K0, K1;878cmsS15Fixed16Number fx, fy, fz;879cmsS15Fixed16Number rx, ry, rz;880int x0, y0, z0;881cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;882cmsUInt32Number i;883cmsS15Fixed16Number c0, c1, c2, c3, Rest;884cmsUInt32Number OutChan;885cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];886887888fk = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]);889fx = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]);890fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]);891fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]);892893k0 = FIXED_TO_INT(fk);894x0 = FIXED_TO_INT(fx);895y0 = FIXED_TO_INT(fy);896z0 = FIXED_TO_INT(fz);897898rk = FIXED_REST_TO_INT(fk);899rx = FIXED_REST_TO_INT(fx);900ry = FIXED_REST_TO_INT(fy);901rz = FIXED_REST_TO_INT(fz);902903K0 = p16 -> opta[3] * k0;904K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]);905906X0 = p16 -> opta[2] * x0;907X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]);908909Y0 = p16 -> opta[1] * y0;910Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]);911912Z0 = p16 -> opta[0] * z0;913Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]);914915LutTable = (cmsUInt16Number*) p16 -> Table;916LutTable += K0;917918for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {919920c0 = DENS(X0, Y0, Z0);921922if (rx >= ry && ry >= rz) {923924c1 = DENS(X1, Y0, Z0) - c0;925c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);926c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);927928}929else930if (rx >= rz && rz >= ry) {931932c1 = DENS(X1, Y0, Z0) - c0;933c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);934c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);935936}937else938if (rz >= rx && rx >= ry) {939940c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);941c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);942c3 = DENS(X0, Y0, Z1) - c0;943944}945else946if (ry >= rx && rx >= rz) {947948c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);949c2 = DENS(X0, Y1, Z0) - c0;950c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);951952}953else954if (ry >= rz && rz >= rx) {955956c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);957c2 = DENS(X0, Y1, Z0) - c0;958c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);959960}961else962if (rz >= ry && ry >= rx) {963964c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);965c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);966c3 = DENS(X0, Y0, Z1) - c0;967968}969else {970c1 = c2 = c3 = 0;971}972973Rest = c1 * rx + c2 * ry + c3 * rz;974975Tmp1[OutChan] = (cmsUInt16Number)(c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));976}977978979LutTable = (cmsUInt16Number*) p16 -> Table;980LutTable += K1;981982for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {983984c0 = DENS(X0, Y0, Z0);985986if (rx >= ry && ry >= rz) {987988c1 = DENS(X1, Y0, Z0) - c0;989c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);990c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);991992}993else994if (rx >= rz && rz >= ry) {995996c1 = DENS(X1, Y0, Z0) - c0;997c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);998c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);9991000}1001else1002if (rz >= rx && rx >= ry) {10031004c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);1005c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);1006c3 = DENS(X0, Y0, Z1) - c0;10071008}1009else1010if (ry >= rx && rx >= rz) {10111012c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);1013c2 = DENS(X0, Y1, Z0) - c0;1014c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);10151016}1017else1018if (ry >= rz && rz >= rx) {10191020c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);1021c2 = DENS(X0, Y1, Z0) - c0;1022c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);10231024}1025else1026if (rz >= ry && ry >= rx) {10271028c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);1029c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);1030c3 = DENS(X0, Y0, Z1) - c0;10311032}1033else {1034c1 = c2 = c3 = 0;1035}10361037Rest = c1 * rx + c2 * ry + c3 * rz;10381039Tmp2[OutChan] = (cmsUInt16Number) (c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));1040}1041104210431044for (i=0; i < p16 -> nOutputs; i++) {1045Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);1046}1047}1048#undef DENS104910501051// For more that 3 inputs (i.e., CMYK)1052// evaluate two 3-dimensional interpolations and then linearly interpolate between them.105310541055static1056void Eval4InputsFloat(const cmsFloat32Number Input[],1057cmsFloat32Number Output[],1058const cmsInterpParams* p)1059{1060const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;1061cmsFloat32Number rest;1062cmsFloat32Number pk;1063int k0, K0, K1;1064const cmsFloat32Number* T;1065cmsUInt32Number i;1066cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];1067cmsInterpParams p1;10681069pk = fclamp(Input[0]) * p->Domain[0];1070k0 = _cmsQuickFloor(pk);1071rest = pk - (cmsFloat32Number) k0;10721073K0 = p -> opta[3] * k0;1074K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[3]);10751076p1 = *p;1077memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number));10781079T = LutTable + K0;1080p1.Table = T;10811082TetrahedralInterpFloat(Input + 1, Tmp1, &p1);10831084T = LutTable + K1;1085p1.Table = T;1086TetrahedralInterpFloat(Input + 1, Tmp2, &p1);10871088for (i=0; i < p -> nOutputs; i++)1089{1090cmsFloat32Number y0 = Tmp1[i];1091cmsFloat32Number y1 = Tmp2[i];10921093Output[i] = y0 + (y1 - y0) * rest;1094}1095}109610971098static CMS_NO_SANITIZE1099void Eval5Inputs(CMSREGISTER const cmsUInt16Number Input[],1100CMSREGISTER cmsUInt16Number Output[],11011102CMSREGISTER const cmsInterpParams* p16)1103{1104const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;1105cmsS15Fixed16Number fk;1106cmsS15Fixed16Number k0, rk;1107int K0, K1;1108const cmsUInt16Number* T;1109cmsUInt32Number i;1110cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];1111cmsInterpParams p1;111211131114fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);1115k0 = FIXED_TO_INT(fk);1116rk = FIXED_REST_TO_INT(fk);11171118K0 = p16 -> opta[4] * k0;1119K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));11201121p1 = *p16;1122memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number));11231124T = LutTable + K0;1125p1.Table = T;11261127Eval4Inputs(Input + 1, Tmp1, &p1);11281129T = LutTable + K1;1130p1.Table = T;11311132Eval4Inputs(Input + 1, Tmp2, &p1);11331134for (i=0; i < p16 -> nOutputs; i++) {11351136Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);1137}11381139}114011411142static1143void Eval5InputsFloat(const cmsFloat32Number Input[],1144cmsFloat32Number Output[],1145const cmsInterpParams* p)1146{1147const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;1148cmsFloat32Number rest;1149cmsFloat32Number pk;1150int k0, K0, K1;1151const cmsFloat32Number* T;1152cmsUInt32Number i;1153cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];1154cmsInterpParams p1;11551156pk = fclamp(Input[0]) * p->Domain[0];1157k0 = _cmsQuickFloor(pk);1158rest = pk - (cmsFloat32Number) k0;11591160K0 = p -> opta[4] * k0;1161K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[4]);11621163p1 = *p;1164memmove(&p1.Domain[0], &p ->Domain[1], 4*sizeof(cmsUInt32Number));11651166T = LutTable + K0;1167p1.Table = T;11681169Eval4InputsFloat(Input + 1, Tmp1, &p1);11701171T = LutTable + K1;1172p1.Table = T;11731174Eval4InputsFloat(Input + 1, Tmp2, &p1);11751176for (i=0; i < p -> nOutputs; i++) {11771178cmsFloat32Number y0 = Tmp1[i];1179cmsFloat32Number y1 = Tmp2[i];11801181Output[i] = y0 + (y1 - y0) * rest;1182}1183}1184118511861187static CMS_NO_SANITIZE1188void Eval6Inputs(CMSREGISTER const cmsUInt16Number Input[],1189CMSREGISTER cmsUInt16Number Output[],1190CMSREGISTER const cmsInterpParams* p16)1191{1192const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;1193cmsS15Fixed16Number fk;1194cmsS15Fixed16Number k0, rk;1195int K0, K1;1196const cmsUInt16Number* T;1197cmsUInt32Number i;1198cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];1199cmsInterpParams p1;12001201fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);1202k0 = FIXED_TO_INT(fk);1203rk = FIXED_REST_TO_INT(fk);12041205K0 = p16 -> opta[5] * k0;1206K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));12071208p1 = *p16;1209memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number));12101211T = LutTable + K0;1212p1.Table = T;12131214Eval5Inputs(Input + 1, Tmp1, &p1);12151216T = LutTable + K1;1217p1.Table = T;12181219Eval5Inputs(Input + 1, Tmp2, &p1);12201221for (i=0; i < p16 -> nOutputs; i++) {12221223Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);1224}12251226}122712281229static1230void Eval6InputsFloat(const cmsFloat32Number Input[],1231cmsFloat32Number Output[],1232const cmsInterpParams* p)1233{1234const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;1235cmsFloat32Number rest;1236cmsFloat32Number pk;1237int k0, K0, K1;1238const cmsFloat32Number* T;1239cmsUInt32Number i;1240cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];1241cmsInterpParams p1;12421243pk = fclamp(Input[0]) * p->Domain[0];1244k0 = _cmsQuickFloor(pk);1245rest = pk - (cmsFloat32Number) k0;12461247K0 = p -> opta[5] * k0;1248K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[5]);12491250p1 = *p;1251memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number));12521253T = LutTable + K0;1254p1.Table = T;12551256Eval5InputsFloat(Input + 1, Tmp1, &p1);12571258T = LutTable + K1;1259p1.Table = T;12601261Eval5InputsFloat(Input + 1, Tmp2, &p1);12621263for (i=0; i < p -> nOutputs; i++) {12641265cmsFloat32Number y0 = Tmp1[i];1266cmsFloat32Number y1 = Tmp2[i];12671268Output[i] = y0 + (y1 - y0) * rest;1269}1270}127112721273static CMS_NO_SANITIZE1274void Eval7Inputs(CMSREGISTER const cmsUInt16Number Input[],1275CMSREGISTER cmsUInt16Number Output[],1276CMSREGISTER const cmsInterpParams* p16)1277{1278const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;1279cmsS15Fixed16Number fk;1280cmsS15Fixed16Number k0, rk;1281int K0, K1;1282const cmsUInt16Number* T;1283cmsUInt32Number i;1284cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];1285cmsInterpParams p1;128612871288fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);1289k0 = FIXED_TO_INT(fk);1290rk = FIXED_REST_TO_INT(fk);12911292K0 = p16 -> opta[6] * k0;1293K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));12941295p1 = *p16;1296memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number));12971298T = LutTable + K0;1299p1.Table = T;13001301Eval6Inputs(Input + 1, Tmp1, &p1);13021303T = LutTable + K1;1304p1.Table = T;13051306Eval6Inputs(Input + 1, Tmp2, &p1);13071308for (i=0; i < p16 -> nOutputs; i++) {1309Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);1310}1311}131213131314static1315void Eval7InputsFloat(const cmsFloat32Number Input[],1316cmsFloat32Number Output[],1317const cmsInterpParams* p)1318{1319const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;1320cmsFloat32Number rest;1321cmsFloat32Number pk;1322int k0, K0, K1;1323const cmsFloat32Number* T;1324cmsUInt32Number i;1325cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];1326cmsInterpParams p1;13271328pk = fclamp(Input[0]) * p->Domain[0];1329k0 = _cmsQuickFloor(pk);1330rest = pk - (cmsFloat32Number) k0;13311332K0 = p -> opta[6] * k0;1333K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[6]);13341335p1 = *p;1336memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number));13371338T = LutTable + K0;1339p1.Table = T;13401341Eval6InputsFloat(Input + 1, Tmp1, &p1);13421343T = LutTable + K1;1344p1.Table = T;13451346Eval6InputsFloat(Input + 1, Tmp2, &p1);134713481349for (i=0; i < p -> nOutputs; i++) {13501351cmsFloat32Number y0 = Tmp1[i];1352cmsFloat32Number y1 = Tmp2[i];13531354Output[i] = y0 + (y1 - y0) * rest;13551356}1357}13581359static CMS_NO_SANITIZE1360void Eval8Inputs(CMSREGISTER const cmsUInt16Number Input[],1361CMSREGISTER cmsUInt16Number Output[],1362CMSREGISTER const cmsInterpParams* p16)1363{1364const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;1365cmsS15Fixed16Number fk;1366cmsS15Fixed16Number k0, rk;1367int K0, K1;1368const cmsUInt16Number* T;1369cmsUInt32Number i;1370cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];1371cmsInterpParams p1;13721373fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);1374k0 = FIXED_TO_INT(fk);1375rk = FIXED_REST_TO_INT(fk);13761377K0 = p16 -> opta[7] * k0;1378K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));13791380p1 = *p16;1381memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number));13821383T = LutTable + K0;1384p1.Table = T;13851386Eval7Inputs(Input + 1, Tmp1, &p1);13871388T = LutTable + K1;1389p1.Table = T;1390Eval7Inputs(Input + 1, Tmp2, &p1);13911392for (i=0; i < p16 -> nOutputs; i++) {1393Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);1394}1395}1396139713981399static1400void Eval8InputsFloat(const cmsFloat32Number Input[],1401cmsFloat32Number Output[],1402const cmsInterpParams* p)1403{1404const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;1405cmsFloat32Number rest;1406cmsFloat32Number pk;1407int k0, K0, K1;1408const cmsFloat32Number* T;1409cmsUInt32Number i;1410cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];1411cmsInterpParams p1;14121413pk = fclamp(Input[0]) * p->Domain[0];1414k0 = _cmsQuickFloor(pk);1415rest = pk - (cmsFloat32Number) k0;14161417K0 = p -> opta[7] * k0;1418K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[7]);14191420p1 = *p;1421memmove(&p1.Domain[0], &p ->Domain[1], 7*sizeof(cmsUInt32Number));14221423T = LutTable + K0;1424p1.Table = T;14251426Eval7InputsFloat(Input + 1, Tmp1, &p1);14271428T = LutTable + K1;1429p1.Table = T;14301431Eval7InputsFloat(Input + 1, Tmp2, &p1);143214331434for (i=0; i < p -> nOutputs; i++) {14351436cmsFloat32Number y0 = Tmp1[i];1437cmsFloat32Number y1 = Tmp2[i];14381439Output[i] = y0 + (y1 - y0) * rest;1440}1441}14421443// The default factory1444static1445cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags)1446{14471448cmsInterpFunction Interpolation;1449cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT);1450cmsBool IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR);14511452memset(&Interpolation, 0, sizeof(Interpolation));14531454// Safety check1455if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS)1456return Interpolation;14571458switch (nInputChannels) {14591460case 1: // Gray LUT / linear14611462if (nOutputChannels == 1) {14631464if (IsFloat)1465Interpolation.LerpFloat = LinLerp1Dfloat;1466else1467Interpolation.Lerp16 = LinLerp1D;14681469}1470else {14711472if (IsFloat)1473Interpolation.LerpFloat = Eval1InputFloat;1474else1475Interpolation.Lerp16 = Eval1Input;1476}1477break;14781479case 2: // Duotone1480if (IsFloat)1481Interpolation.LerpFloat = BilinearInterpFloat;1482else1483Interpolation.Lerp16 = BilinearInterp16;1484break;14851486case 3: // RGB et al14871488if (IsTrilinear) {14891490if (IsFloat)1491Interpolation.LerpFloat = TrilinearInterpFloat;1492else1493Interpolation.Lerp16 = TrilinearInterp16;1494}1495else {14961497if (IsFloat)1498Interpolation.LerpFloat = TetrahedralInterpFloat;1499else {15001501Interpolation.Lerp16 = TetrahedralInterp16;1502}1503}1504break;15051506case 4: // CMYK lut15071508if (IsFloat)1509Interpolation.LerpFloat = Eval4InputsFloat;1510else1511Interpolation.Lerp16 = Eval4Inputs;1512break;15131514case 5: // 5 Inks1515if (IsFloat)1516Interpolation.LerpFloat = Eval5InputsFloat;1517else1518Interpolation.Lerp16 = Eval5Inputs;1519break;15201521case 6: // 6 Inks1522if (IsFloat)1523Interpolation.LerpFloat = Eval6InputsFloat;1524else1525Interpolation.Lerp16 = Eval6Inputs;1526break;15271528case 7: // 7 inks1529if (IsFloat)1530Interpolation.LerpFloat = Eval7InputsFloat;1531else1532Interpolation.Lerp16 = Eval7Inputs;1533break;15341535case 8: // 8 inks1536if (IsFloat)1537Interpolation.LerpFloat = Eval8InputsFloat;1538else1539Interpolation.Lerp16 = Eval8Inputs;1540break;15411542break;15431544default:1545Interpolation.Lerp16 = NULL;1546}15471548return Interpolation;1549}155015511552