static void AllSmeltedBehaviour(LPMATSHAPER MatShaper, WORD In[], WORD Out[]) { WORD tmp[3]; WVEC3 InVect, OutVect; if (MatShaper -> dwFlags & MATSHAPER_HASINPSHAPER) { InVect.n[VX] = cmsLinearInterpFixed(In[0], MatShaper -> L2[0], &MatShaper -> p2_16); InVect.n[VY] = cmsLinearInterpFixed(In[1], MatShaper -> L2[1], &MatShaper -> p2_16); InVect.n[VZ] = cmsLinearInterpFixed(In[2], MatShaper -> L2[2], &MatShaper -> p2_16); } else { InVect.n[VX] = ToFixedDomain(In[0]); InVect.n[VY] = ToFixedDomain(In[1]); InVect.n[VZ] = ToFixedDomain(In[2]); } if (MatShaper -> dwFlags & MATSHAPER_HASMATRIX) { MAT3evalW(&OutVect, &MatShaper -> Matrix, &InVect); } else { OutVect.n[VX] = InVect.n[VX]; OutVect.n[VY] = InVect.n[VY]; OutVect.n[VZ] = InVect.n[VZ]; } tmp[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX])); tmp[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY])); tmp[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ])); if (MatShaper -> dwFlags & MATSHAPER_HASSHAPER) { Out[0] = cmsLinearInterpLUT16(tmp[0], MatShaper -> L[0], &MatShaper -> p16); Out[1] = cmsLinearInterpLUT16(tmp[1], MatShaper -> L[1], &MatShaper -> p16); Out[2] = cmsLinearInterpLUT16(tmp[2], MatShaper -> L[2], &MatShaper -> p16); } else { Out[0] = tmp[0]; Out[1] = tmp[1]; Out[2] = tmp[2]; } }
// 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 OutputBehaviour(LPMATSHAPER MatShaper, WORD In[], WORD Out[]) { WVEC3 InVect, OutVect; int i; // We need to convert from XYZ to RGB, here we must // shift << 1 to pass between 1.15 to 15.16 formats InVect.n[VX] = (Fixed32) In[0] << 1; InVect.n[VY] = (Fixed32) In[1] << 1; InVect.n[VZ] = (Fixed32) In[2] << 1; if (MatShaper -> dwFlags & MATSHAPER_HASMATRIX) { MAT3evalW(&OutVect, &MatShaper -> Matrix, &InVect); } else { OutVect = InVect; } if (MatShaper -> dwFlags & MATSHAPER_HASSHAPER) { for (i=0; i < 3; i++) { Out[i] = cmsLinearInterpLUT16( _cmsClampWord(FromFixedDomain(OutVect.n[i])), MatShaper -> L[i], &MatShaper ->p16); } } else { // Result from fixed domain to RGB Out[0] = _cmsClampWord(FromFixedDomain(OutVect.n[VX])); Out[1] = _cmsClampWord(FromFixedDomain(OutVect.n[VY])); Out[2] = _cmsClampWord(FromFixedDomain(OutVect.n[VZ])); } }
WORD cmsReverseLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p) { register int l = 1; register int r = 0x10000; register int x = 0, res; // 'int' Give spacing for negative values int NumZeroes, NumPoles; int cell0, cell1; double val2; double y0, y1, x0, x1; double a, b, f; // July/27 2001 - Expanded to handle degenerated curves with an arbitrary // number of elements containing 0 at the begining of the table (Zeroes) // and another arbitrary number of poles (FFFFh) at the end. // First the zero and pole extents are computed, then value is compared. NumZeroes = 0; while (LutTable[NumZeroes] == 0 && NumZeroes < p -> Domain) NumZeroes++; // There are no zeros at the beginning and we are trying to find a zero, so // return anything. It seems zero would be the less destructive choice if (NumZeroes == 0 && Value == 0) return 0; NumPoles = 0; while (LutTable[p -> Domain - NumPoles] == 0xFFFF && NumPoles < p -> Domain) NumPoles++; // Does the curve belong to this case? if (NumZeroes > 1 || NumPoles > 1) { int a, b; // Identify if value fall downto 0 or FFFF zone if (Value == 0) return 0; // if (Value == 0xFFFF) return 0xFFFF; // else restrict to valid zone a = ((NumZeroes-1) * 0xFFFF) / p->Domain; b = ((p -> Domain - NumPoles) * 0xFFFF) / p ->Domain; l = a - 1; r = b + 1; } // Seems not a degenerated case... apply binary search while (r > l) { x = (l + r) / 2; res = (int) cmsLinearInterpLUT16((WORD) (x - 1), LutTable, p); if (res == Value) { // Found exact match. return (WORD) (x - 1); } if (res > Value) r = x - 1; else l = x + 1; } // Not found, should we interpolate? // Get surrounding nodes val2 = p -> Domain * ((double) (x - 1) / 65535.0); cell0 = (int) floor(val2); cell1 = (int) ceil(val2); if (cell0 == cell1) return (WORD) x; y0 = LutTable[cell0] ; x0 = (65535.0 * cell0) / p ->Domain; y1 = LutTable[cell1] ; x1 = (65535.0 * cell1) / p ->Domain; a = (y1 - y0) / (x1 - x0); b = y0 - a * x0; if (fabs(a) < 0.01) return (WORD) x; f = ((Value - b) / a); if (f < 0.0) return (WORD) 0; if (f >= 65535.0) return (WORD) 0xFFFF; return (WORD) floor(f + 0.5); }
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]); } }