// Precomputes tables for 8-bit on input devicelink. // LPLUT _cmsBlessLUT8(LPLUT Lut) { int i, j; WORD StageABC[3]; Fixed32 v1, v2, v3; LPL8PARAMS p8; LPL16PARAMS p = &Lut ->CLut16params; p8 = (LPL8PARAMS) malloc(sizeof(L8PARAMS)); if (p8 == NULL) return NULL; // values comes * 257, so we can safely take first byte (x << 8 + x) // if there are prelinearization, is already smelted in tables for (i=0; i < 256; i++) { StageABC[0] = StageABC[1] = StageABC[2] = RGB_8_TO_16(i); if (Lut ->wFlags & LUT_HASTL1) { for (j=0; j < 3; j++) StageABC[i] = cmsLinearInterpLUT16(StageABC[i], Lut -> L1[i], &Lut -> In16params); Lut ->wFlags &= ~LUT_HASTL1; } v1 = ToFixedDomain(StageABC[0] * p -> Domain); v2 = ToFixedDomain(StageABC[1] * p -> Domain); v3 = ToFixedDomain(StageABC[2] * p -> Domain); p8 ->X0[i] = p->opta3 * FIXED_TO_INT(v1); p8 ->Y0[i] = p->opta2 * FIXED_TO_INT(v2); p8 ->Z0[i] = p->opta1 * FIXED_TO_INT(v3); p8 ->rx[i] = (WORD) FIXED_REST_TO_INT(v1); p8 ->ry[i] = (WORD) FIXED_REST_TO_INT(v2); p8 ->rz[i] = (WORD) FIXED_REST_TO_INT(v3); } Lut -> CLut16params.p8 = p8; Lut -> CLut16params.Interp3D = cmsTetrahedralInterp8; return Lut; }
static void Eval8Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16) { Fixed32 fk; Fixed32 k0, rk; int K0, K1; LPWORD T; int i; WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS]; fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain); k0 = FIXED_TO_INT(fk); rk = FIXED_REST_TO_INT(fk); K0 = p16 -> opta8 * k0; K1 = p16 -> opta8 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0)); p16 -> nInputs = 7; T = LutTable + K0; Eval7Inputs(StageABC + 1, Tmp1, T, p16); T = LutTable + K1; Eval7Inputs(StageABC + 1, Tmp2, T, p16); p16 -> nInputs = 8; for (i=0; i < p16 -> nOutputs; i++) { StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]); } }
WORD cmsLinearInterpLUT16(WORD Value1, WORD LutTable[], LPL16PARAMS p) { WORD y1, y0; WORD y; int dif, a1; int cell0, rest; int val3, Value; // if last value... Value = Value1; if (Value == 0xffff) return LutTable[p -> Domain]; val3 = p -> Domain * Value; val3 = ToFixedDomain(val3); // To fixed 15.16 cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits y0 = LutTable[cell0] ; y1 = LutTable[cell0+1] ; dif = (int) y1 - y0; // dif is in domain -ffff ... ffff if (dif >= 0) { a1 = ToFixedDomain(dif * rest); a1 += 0x8000; } else { a1 = ToFixedDomain((- dif) * rest); a1 -= 0x8000; a1 = -a1; } y = (WORD) (y0 + FIXED_TO_INT(a1)); return y; }
static void Eval1Input(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16) { Fixed32 fk; Fixed32 k0, k1, rk, K0, K1; int OutChan; fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain); k0 = FIXED_TO_INT(fk); rk = (WORD) FIXED_REST_TO_INT(fk); k1 = k0 + (StageABC[0] != 0xFFFFU ? 1 : 0); K0 = p16 -> opta1 * k0; K1 = p16 -> opta1 * k1; for (OutChan=0; OutChan < p16->nOutputs; OutChan++) { StageLMN[OutChan] = (WORD) FixedLERP(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]); } }
Fixed32 cmsLinearInterpFixed(WORD Value1, WORD LutTable[], LPL16PARAMS p) { Fixed32 y1, y0; int cell0; int val3, Value; // if last value... Value = Value1; if (Value == 0xffffU) return LutTable[p -> Domain]; val3 = p -> Domain * Value; val3 = ToFixedDomain(val3); // To fixed 15.16 cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits y0 = LutTable[cell0] ; y1 = LutTable[cell0+1] ; return y0 + FixedMul((y1 - y0), (val3 & 0xFFFFL)); }
void cmsTetrahedralInterp16(WORD Input[], WORD Output[], WORD LutTable1[], LPL16PARAMS p) { Fixed32 fx, fy, fz; Fixed32 rx, ry, rz; int x0, y0, z0; Fixed32 c0, c1, c2, c3, Rest; int OutChan; Fixed32 X0, X1, Y0, Y1, Z0, Z1; int TotalOut = p -> nOutputs; register LPWORD LutTable = LutTable1; fx = ToFixedDomain((int) Input[0] * p -> Domain); fy = ToFixedDomain((int) Input[1] * p -> Domain); fz = ToFixedDomain((int) Input[2] * p -> Domain); x0 = FIXED_TO_INT(fx); y0 = FIXED_TO_INT(fy); z0 = FIXED_TO_INT(fz); rx = FIXED_REST_TO_INT(fx); ry = FIXED_REST_TO_INT(fy); rz = FIXED_REST_TO_INT(fz); X0 = p -> opta3 * x0; X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta3); Y0 = p -> opta2 * y0; Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta2); Z0 = p -> opta1 * z0; Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta1); // These are the 6 Tetrahedral for (OutChan=0; OutChan < TotalOut; OutChan++) { c0 = DENS(X0, Y0, Z0); if (rx >= ry && ry >= rz) { c1 = DENS(X1, Y0, Z0) - c0; c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); } else if (rx >= rz && rz >= ry) { c1 = DENS(X1, Y0, Z0) - c0; c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); } else if (rz >= rx && rx >= ry) { c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); c3 = DENS(X0, Y0, Z1) - c0; } else if (ry >= rx && rx >= rz) { c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); c2 = DENS(X0, Y1, Z0) - c0; c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); } else if (ry >= rz && rz >= rx) { c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); c2 = DENS(X0, Y1, Z0) - c0; c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); } else if (rz >= ry && ry >= rx) { c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); c3 = DENS(X0, Y0, Z1) - c0; } else { c1 = c2 = c3 = 0; // assert(FALSE); } Rest = c1 * rx + c2 * ry + c3 * rz; // There is a lot of math hidden in this expression. The rest is in fixed domain // and the result in 0..ffff domain. So the complete expression should be // ROUND_FIXED_TO_INT(ToFixedDomain(Rest)) But that can be optimized as (Rest + 0x7FFF) / 0xFFFF Output[OutChan] = (WORD) (c0 + ((Rest + 0x7FFF) / 0xFFFF)); } }
void cmsTrilinearInterp16(WORD Input[], WORD Output[], WORD LutTable[], LPL16PARAMS p) { #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) #define LERP(a,l,h) (WORD) (l+ ROUND_FIXED_TO_INT(((h-l)*a))) int OutChan, TotalOut; Fixed32 fx, fy, fz; register int rx, ry, rz; int x0, y0, z0; register int X0, X1, Y0, Y1, Z0, Z1; int d000, d001, d010, d011, d100, d101, d110, d111, dx00, dx01, dx10, dx11, dxy0, dxy1, dxyz; TotalOut = p -> nOutputs; fx = ToFixedDomain((int) Input[0] * p -> Domain); x0 = FIXED_TO_INT(fx); rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain fy = ToFixedDomain((int) Input[1] * p -> Domain); y0 = FIXED_TO_INT(fy); ry = FIXED_REST_TO_INT(fy); fz = ToFixedDomain((int) Input[2] * p -> Domain); z0 = FIXED_TO_INT(fz); rz = FIXED_REST_TO_INT(fz); X0 = p -> opta3 * x0; X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta3); Y0 = p -> opta2 * y0; Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta2); Z0 = p -> opta1 * z0; Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta1); for (OutChan = 0; OutChan < TotalOut; OutChan++) { d000 = DENS(X0, Y0, Z0); d001 = DENS(X0, Y0, Z1); d010 = DENS(X0, Y1, Z0); d011 = DENS(X0, Y1, Z1); d100 = DENS(X1, Y0, Z0); d101 = DENS(X1, Y0, Z1); d110 = DENS(X1, Y1, Z0); d111 = DENS(X1, Y1, Z1); dx00 = LERP(rx, d000, d100); dx01 = LERP(rx, d001, d101); dx10 = LERP(rx, d010, d110); dx11 = LERP(rx, d011, d111); dxy0 = LERP(ry, dx00, dx10); dxy1 = LERP(ry, dx01, dx11); dxyz = LERP(rz, dxy0, dxy1); Output[OutChan] = (WORD) dxyz; } # undef LERP # undef DENS }
void LCMSEXPORT cmsEvalLUT(LPLUT Lut, WORD In[], WORD Out[]) { register unsigned int i; WORD StageABC[MAXCHANNELS], StageLMN[MAXCHANNELS]; // Try to speedup things on plain devicelinks if (Lut ->wFlags == LUT_HAS3DGRID) { Lut ->CLut16params.Interp3D(In, Out, Lut -> T, &Lut -> CLut16params); return; } // Nope, evaluate whole LUT for (i=0; i < Lut -> InputChan; i++) StageABC[i] = In[i]; if (Lut ->wFlags & LUT_V4_OUTPUT_EMULATE_V2) { // Clamp Lab to avoid overflow if (StageABC[0] > 0xFF00) StageABC[0] = 0xFF00; StageABC[0] = (WORD) FROM_V2_TO_V4(StageABC[0]); StageABC[1] = (WORD) FROM_V2_TO_V4(StageABC[1]); StageABC[2] = (WORD) FROM_V2_TO_V4(StageABC[2]); } if (Lut ->wFlags & LUT_V2_OUTPUT_EMULATE_V4) { StageABC[0] = (WORD) FROM_V4_TO_V2(StageABC[0]); StageABC[1] = (WORD) FROM_V4_TO_V2(StageABC[1]); StageABC[2] = (WORD) FROM_V4_TO_V2(StageABC[2]); } // Matrix handling. if (Lut -> wFlags & LUT_HASMATRIX) { WVEC3 InVect, OutVect; // In LUT8 here comes the special gray axis fixup if (Lut ->FixGrayAxes) { StageABC[1] = _cmsClampWord(StageABC[1] - 128); StageABC[2] = _cmsClampWord(StageABC[2] - 128); } // Matrix InVect.n[VX] = ToFixedDomain(StageABC[0]); InVect.n[VY] = ToFixedDomain(StageABC[1]); InVect.n[VZ] = ToFixedDomain(StageABC[2]); MAT3evalW(&OutVect, &Lut -> Matrix, &InVect); // PCS in 1Fixed15 format, adjusting StageABC[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX])); StageABC[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY])); StageABC[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ])); } // First linearization if (Lut -> wFlags & LUT_HASTL1) { for (i=0; i < Lut -> InputChan; i++) StageABC[i] = cmsLinearInterpLUT16(StageABC[i], Lut -> L1[i], &Lut -> In16params); } // Mat3, Ofs3, L3 processing if (Lut ->wFlags & LUT_HASMATRIX3) { WVEC3 InVect, OutVect; InVect.n[VX] = ToFixedDomain(StageABC[0]); InVect.n[VY] = ToFixedDomain(StageABC[1]); InVect.n[VZ] = ToFixedDomain(StageABC[2]); MAT3evalW(&OutVect, &Lut -> Mat3, &InVect); OutVect.n[VX] += Lut ->Ofs3.n[VX]; OutVect.n[VY] += Lut ->Ofs3.n[VY]; OutVect.n[VZ] += Lut ->Ofs3.n[VZ]; StageABC[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX])); StageABC[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY])); StageABC[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ])); } if (Lut ->wFlags & LUT_HASTL3) { for (i=0; i < Lut -> InputChan; i++) StageABC[i] = cmsLinearInterpLUT16(StageABC[i], Lut -> L3[i], &Lut -> L3params); } if (Lut -> wFlags & LUT_HAS3DGRID) { Lut ->CLut16params.Interp3D(StageABC, StageLMN, Lut -> T, &Lut -> CLut16params); } else { for (i=0; i < Lut -> InputChan; i++) StageLMN[i] = StageABC[i]; } // Mat4, Ofs4, L4 processing if (Lut ->wFlags & LUT_HASTL4) { for (i=0; i < Lut -> OutputChan; i++) StageLMN[i] = cmsLinearInterpLUT16(StageLMN[i], Lut -> L4[i], &Lut -> L4params); } if (Lut ->wFlags & LUT_HASMATRIX4) { WVEC3 InVect, OutVect; InVect.n[VX] = ToFixedDomain(StageLMN[0]); InVect.n[VY] = ToFixedDomain(StageLMN[1]); InVect.n[VZ] = ToFixedDomain(StageLMN[2]); MAT3evalW(&OutVect, &Lut -> Mat4, &InVect); OutVect.n[VX] += Lut ->Ofs4.n[VX]; OutVect.n[VY] += Lut ->Ofs4.n[VY]; OutVect.n[VZ] += Lut ->Ofs4.n[VZ]; StageLMN[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX])); StageLMN[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY])); StageLMN[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ])); } // Last linearitzation if (Lut -> wFlags & LUT_HASTL2) { for (i=0; i < Lut -> OutputChan; i++) Out[i] = cmsLinearInterpLUT16(StageLMN[i], Lut -> L2[i], &Lut -> Out16params); } else { for (i=0; i < Lut -> OutputChan; i++) Out[i] = StageLMN[i]; } if (Lut ->wFlags & LUT_V4_INPUT_EMULATE_V2) { Out[0] = (WORD) FROM_V4_TO_V2(Out[0]); Out[1] = (WORD) FROM_V4_TO_V2(Out[1]); Out[2] = (WORD) FROM_V4_TO_V2(Out[2]); } if (Lut ->wFlags & LUT_V2_INPUT_EMULATE_V4) { Out[0] = (WORD) FROM_V2_TO_V4(Out[0]); Out[1] = (WORD) FROM_V2_TO_V4(Out[1]); Out[2] = (WORD) FROM_V2_TO_V4(Out[2]); } }