static int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) { GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo; cmsCIELab LabIn1, LabOut1; cmsCIELab LabIn2, LabOut2; cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; cmsFloat64Number dE1, dE2, ErrorRatio; // Assume in-gamut by default. ErrorRatio = 1.0; // Convert input to Lab cmsDoTransform(t -> hInput, In, &LabIn1, 1); // converts from PCS to colorant. This always // does return in-gamut values, cmsDoTransform(t -> hForward, &LabIn1, Proof, 1); // Now, do the inverse, from colorant to PCS. cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1); memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab)); // Try again, but this time taking Check as input cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1); // Take difference of direct value dE1 = cmsDeltaE(&LabIn1, &LabOut1); // Take difference of converted value dE2 = cmsDeltaE(&LabIn2, &LabOut2); // if dE1 is small and dE2 is small, value is likely to be in gamut if (dE1 < t->Thereshold && dE2 < t->Thereshold) Out[0] = 0; else { // if dE1 is small and dE2 is big, undefined. Assume in gamut if (dE1 < t->Thereshold && dE2 > t->Thereshold) Out[0] = 0; else // dE1 is big and dE2 is small, clearly out of gamut if (dE1 > t->Thereshold && dE2 < t->Thereshold) Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5); else { // dE1 is big and dE2 is also big, could be due to perceptual mapping // so take error ratio if (dE2 == 0.0) ErrorRatio = dE1; else ErrorRatio = dE1 / dE2; if (ErrorRatio > t->Thereshold) Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); else Out[0] = 0; } } return TRUE; }
void cmsTrilinearInterp16(WORD Input[], WORD Output[], WORD LutTable[], LPL16PARAMS p) { # define LERP(a,l,h) (double) ((l)+(((h)-(l))*(a))) # define DENS(X, Y, Z) (double) (LutTable[TotalOut*((Z)+clutPoints*((Y)+clutPoints*(X)))+OutChan]) double px, py, pz; int x0, y0, z0, x1, y1, z1; int clutPoints, TotalOut, OutChan; double fx, fy, fz, d000, d001, d010, d011, d100, d101, d110, d111, dx00, dx01, dx10, dx11, dxy0, dxy1, dxyz; clutPoints = p -> Domain + 1; TotalOut = p -> nOutputs; px = ((double) Input[0] * (p->Domain)) / 65535.0; py = ((double) Input[1] * (p->Domain)) / 65535.0; pz = ((double) Input[2] * (p->Domain)) / 65535.0; x0 = (int) _cmsQuickFloor(px); fx = px - (double) x0; y0 = (int) _cmsQuickFloor(py); fy = py - (double) y0; z0 = (int) _cmsQuickFloor(pz); fz = pz - (double) z0; x1 = x0 + (Input[0] != 0xFFFFU ? 1 : 0); y1 = y0 + (Input[1] != 0xFFFFU ? 1 : 0); z1 = z0 + (Input[2] != 0xFFFFU ? 1 : 0); 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(fx, d000, d100); dx01 = LERP(fx, d001, d101); dx10 = LERP(fx, d010, d110); dx11 = LERP(fx, d011, d111); dxy0 = LERP(fy, dx00, dx10); dxy1 = LERP(fy, dx01, dx11); dxyz = LERP(fz, dxy0, dxy1); Output[OutChan] = (WORD) floor(dxyz + .5); } # undef LERP # undef DENS }
void cmsTetrahedralInterp16(WORD Input[], WORD Output[], WORD LutTable[], LPL16PARAMS p) { double px, py, pz; int x0, y0, z0, x1, y1, z1; double fx, fy, fz; double c1=0, c2=0, c3=0; int clutPoints, OutChan, TotalOut; clutPoints = p -> Domain + 1; TotalOut = p -> nOutputs; px = ((double) Input[0] * p->Domain) / 65535.0; py = ((double) Input[1] * p->Domain) / 65535.0; pz = ((double) Input[2] * p->Domain) / 65535.0; x0 = (int) _cmsQuickFloor(px); fx = (px - (double) x0); y0 = (int) _cmsQuickFloor(py); fy = (py - (double) y0); z0 = (int) _cmsQuickFloor(pz); fz = (pz - (double) z0); x1 = x0 + (Input[0] != 0xFFFFU ? 1 : 0); y1 = y0 + (Input[1] != 0xFFFFU ? 1 : 0); z1 = z0 + (Input[2] != 0xFFFFU ? 1 : 0); for (OutChan=0; OutChan < TotalOut; OutChan++) { // These are the 6 Tetrahedral if (fx >= fy && fy >= fz) { c1 = DENS(x1, y0, z0) - DENS(x0, y0, z0); c2 = DENS(x1, y1, z0) - DENS(x1, y0, z0); c3 = DENS(x1, y1, z1) - DENS(x1, y1, z0); } else if (fx >= fz && fz >= fy) { c1 = DENS(x1, y0, z0) - DENS(x0, y0, z0); c2 = DENS(x1, y1, z1) - DENS(x1, y0, z1); c3 = DENS(x1, y0, z1) - DENS(x1, y0, z0); } else if (fz >= fx && fx >= fy) { c1 = DENS(x1, y0, z1) - DENS(x0, y0, z1); c2 = DENS(x1, y1, z1) - DENS(x1, y0, z1); c3 = DENS(x0, y0, z1) - DENS(x0, y0, z0); } else if (fy >= fx && fx >= fz) { c1 = DENS(x1, y1, z0) - DENS(x0, y1, z0); c2 = DENS(x0, y1, z0) - DENS(x0, y0, z0); c3 = DENS(x1, y1, z1) - DENS(x1, y1, z0); } else if (fy >= fz && fz >= fx) { c1 = DENS(x1, y1, z1) - DENS(x0, y1, z1); c2 = DENS(x0, y1, z0) - DENS(x0, y0, z0); c3 = DENS(x0, y1, z1) - DENS(x0, y1, z0); } else if (fz >= fy && fy >= fx) { c1 = DENS(x1, y1, z1) - DENS(x0, y1, z1); c2 = DENS(x0, y1, z1) - DENS(x0, y0, z1); c3 = DENS(x0, y0, z1) - DENS(x0, y0, z0); } else { c1 = c2 = c3 = 0; // assert(FALSE); } Output[OutChan] = (WORD) floor((double) DENS(x0,y0,z0) + c1 * fx + c2 * fy + c3 * fz + .5); } }
static int GamutSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) { LPGAMUTCHAIN t = (LPGAMUTCHAIN) Cargo; WORD Proof[MAXCHANNELS], Check[MAXCHANNELS]; WORD Proof2[MAXCHANNELS], Check2[MAXCHANNELS]; cmsCIELab LabIn1, LabOut1; cmsCIELab LabIn2, LabOut2; double dE1, dE2, ErrorRatio; // Assume in-gamut by default. dE1 = 0.; dE2 = 0; ErrorRatio = 1.0; // Any input space? I can use In[] no matter channels // because is just one pixel if (t -> hInput != NULL) cmsDoTransform(t -> hInput, In, In, 1); // converts from PCS to colorant. This always // does return in-gamut values, cmsDoTransform(t -> hForward, In, Proof, 1); // Now, do the inverse, from colorant to PCS. cmsDoTransform(t -> hReverse, Proof, Check, 1); // Try again, but this time taking Check as input cmsDoTransform(t -> hForward, Check, Proof2, 1); cmsDoTransform(t -> hReverse, Proof2, Check2, 1); // Does the transform returns out-of-gamut? if (Check[0] == 0xFFFF && Check[1] == 0xFFFF && Check[2] == 0xFFFF) Out[0] = 0xFF00; // Out of gamut! else { // Transport encoded values cmsLabEncoded2Float(&LabIn1, In); cmsLabEncoded2Float(&LabOut1, Check); // Take difference of direct value dE1 = cmsDeltaE(&LabIn1, &LabOut1); cmsLabEncoded2Float(&LabIn2, Check); cmsLabEncoded2Float(&LabOut2, Check2); // Take difference of converted value dE2 = cmsDeltaE(&LabIn2, &LabOut2); // if dE1 is small and dE2 is small, value is likely to be in gamut if (dE1 < t->Thereshold && dE2 < t->Thereshold) Out[0] = 0; else // if dE1 is small and dE2 is big, undefined. Assume in gamut if (dE1 < t->Thereshold && dE2 > t->Thereshold) Out[0] = 0; else // dE1 is big and dE2 is small, clearly out of gamut if (dE1 > t->Thereshold && dE2 < t->Thereshold) Out[0] = (WORD) _cmsQuickFloor((dE1 - t->Thereshold) + .5); else { // dE1 is big and dE2 is also big, could be due to perceptual mapping // so take error ratio if (dE2 == 0.0) ErrorRatio = dE1; else ErrorRatio = dE1 / dE2; if (ErrorRatio > t->Thereshold) Out[0] = (WORD) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); else Out[0] = 0; } } return TRUE; }