// Compute K -> L* relationship. Flags may include black point compensation. In this case, // the relationship is assumed from the profile with BPC to a black point zero. static LPGAMMATABLE ComputeKToLstar(cmsHPROFILE hProfile, int nPoints, int Intent, DWORD dwFlags) { LPGAMMATABLE out; int i; WORD cmyk[4], wLab[3]; cmsHPROFILE hLab = cmsCreateLabProfile(NULL); cmsHTRANSFORM xform = cmsCreateTransform(hProfile, TYPE_CMYK_16, hLab, TYPE_Lab_16, Intent, (dwFlags|cmsFLAGS_NOTPRECALC)); out = cmsAllocGamma(nPoints); for (i=0; i < nPoints; i++) { cmyk[0] = 0; cmyk[1] = 0; cmyk[2] = 0; cmyk[3] = _cmsQuantizeVal(i, nPoints); cmsDoTransform(xform, cmyk, wLab, 1); out->GammaTable[i] = (WORD) (0xFFFF - wLab[0]); } cmsDeleteTransform(xform); cmsCloseProfile(hLab); return out; }
// Does create a linear ramp static LPGAMMATABLE CreateLinear() { LPGAMMATABLE Gamma = cmsAllocGamma(4096); LPWORD Table = Gamma ->GammaTable; int i; for (i=0; i < 4096; i++) { Table[i] = _cmsQuantizeVal(i, 4096); } return Gamma; }
static int MostlyLinear(WORD Table[], int nEntries) { register int i; int diff; for (i=5; i < nEntries; i++) { diff = abs((int) Table[i] - (int) _cmsQuantizeVal(i, nEntries)); if (diff > 0x0300) return 0; } return 1; }
// Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting // in a linear table. This way assures it is linear in 12 bits, which should be enought in most cases. cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve) { cmsUInt32Number i; int diff; _cmsAssert(Curve != NULL); for (i=0; i < Curve ->nEntries; i++) { diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries)); if (diff > 0x0f) return FALSE; } return TRUE; }
void _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransforms, LPLUT Grid) { LPGAMMATABLE Trans[MAXCHANNELS]; unsigned int t, i, v; int j; WORD In[MAXCHANNELS], Out[MAXCHANNELS]; BOOL lIsSuitable; _LPcmsTRANSFORM InputXForm = (_LPcmsTRANSFORM) h[0]; _LPcmsTRANSFORM OutputXForm = (_LPcmsTRANSFORM) h[nTransforms-1]; // First space is *Lab, use our specialized curves for v2 Lab if (InputXForm ->EntryColorSpace == icSigLabData && OutputXForm->ExitColorSpace != icSigLabData) { CreateLabPrelinearization(Trans); cmsAllocLinearTable(Grid, Trans, 1); cmsFreeGammaTriple(Trans); return; } // Do nothing on all but RGB to RGB transforms if ((InputXForm ->EntryColorSpace != icSigRgbData) || (OutputXForm->ExitColorSpace != icSigRgbData)) return; for (t = 0; t < Grid -> InputChan; t++) Trans[t] = cmsAllocGamma(PRELINEARIZATION_POINTS); for (i=0; i < PRELINEARIZATION_POINTS; i++) { v = _cmsQuantizeVal(i, PRELINEARIZATION_POINTS); for (t=0; t < Grid -> InputChan; t++) In[t] = (WORD) v; cmsDoTransform(h[0], In, Out, 1); for (j=1; j < nTransforms; j++) cmsDoTransform(h[j], Out, Out, 1); for (t=0; t < Grid -> InputChan; t++) Trans[t] ->GammaTable[i] = Out[t]; } // Check transfer curves lIsSuitable = TRUE; for (t=0; (lIsSuitable && (t < Grid->InputChan)); t++) { // Exclude if already linear if (MostlyLinear(Trans[t]->GammaTable, PRELINEARIZATION_POINTS)) lIsSuitable = FALSE; // Exclude if non-monotonic if (!IsMonotonic(Trans[t])) lIsSuitable = FALSE; // Exclude if weird endpoints if (!HasProperEndpoints(Trans[t])) lIsSuitable = FALSE; // Exclude if transfer function is not smooth enough // to be modelled as a gamma function, or the gamma is reversed if (cmsEstimateGamma(Trans[t]) < 1.0) lIsSuitable = FALSE; } if (lIsSuitable) { for (t = 0; t < Grid ->InputChan; t++) SlopeLimiting(Trans[t]->GammaTable, Trans[t]->nEntries); } if (lIsSuitable) cmsAllocLinearTable(Grid, Trans, 1); for (t = 0; t < Grid ->InputChan; t++) cmsFreeGamma(Trans[t]); }