| /* |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| // This file is available under and governed by the GNU General Public |
| // License version 2 only, as published by the Free Software Foundation. |
| // However, the following notice accompanied the original version of this |
| // file: |
| // |
| // |
| // Little cms |
| // Copyright (C) 1998-2007 Marti Maria |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining |
| // a copy of this software and associated documentation files (the "Software"), |
| // to deal in the Software without restriction, including without limitation |
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| // and/or sell copies of the Software, and to permit persons to whom the Software |
| // is furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO |
| // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| |
| #include "lcms.h" |
| |
| |
| // --------------------------------------------------------------------------------- |
| |
| static volatile int GlobalBlackPreservationStrategy = 0; |
| |
| // Quantize a value 0 <= i < MaxSamples |
| |
| WORD _cmsQuantizeVal(double i, int MaxSamples) |
| { |
| double x; |
| |
| x = ((double) i * 65535.) / (double) (MaxSamples - 1); |
| |
| return (WORD) floor(x + .5); |
| } |
| |
| |
| // Is a table linear? |
| |
| int cmsIsLinear(WORD Table[], int nEntries) |
| { |
| register int i; |
| int diff; |
| |
| for (i=0; i < nEntries; i++) { |
| |
| diff = abs((int) Table[i] - (int) _cmsQuantizeVal(i, nEntries)); |
| if (diff > 3) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| |
| |
| // pow() restricted to integer |
| |
| static |
| int ipow(int base, int exp) |
| { |
| int res = base; |
| |
| while (--exp) |
| res *= base; |
| |
| return res; |
| } |
| |
| |
| // Given n, 0<=n<=clut^dim, returns the colorant. |
| |
| static |
| int ComponentOf(int n, int clut, int nColorant) |
| { |
| if (nColorant <= 0) |
| return (n % clut); |
| |
| n /= ipow(clut, nColorant); |
| |
| return (n % clut); |
| } |
| |
| |
| |
| // This routine does a sweep on whole input space, and calls its callback |
| // function on knots. returns TRUE if all ok, FALSE otherwise. |
| |
| LCMSBOOL LCMSEXPORT cmsSample3DGrid(LPLUT Lut, _cmsSAMPLER Sampler, LPVOID Cargo, DWORD dwFlags) |
| { |
| int i, t, nTotalPoints, Colorant, index; |
| WORD In[MAXCHANNELS], Out[MAXCHANNELS]; |
| |
| nTotalPoints = ipow(Lut->cLutPoints, Lut -> InputChan); |
| |
| index = 0; |
| for (i = 0; i < nTotalPoints; i++) { |
| |
| for (t=0; t < (int) Lut -> InputChan; t++) { |
| |
| Colorant = ComponentOf(i, Lut -> cLutPoints, (Lut -> InputChan - t - 1 )); |
| In[t] = _cmsQuantizeVal(Colorant, Lut -> cLutPoints); |
| } |
| |
| |
| if (dwFlags & SAMPLER_HASTL1) { |
| |
| for (t=0; t < (int) Lut -> InputChan; t++) |
| In[t] = cmsReverseLinearInterpLUT16(In[t], |
| Lut -> L1[t], |
| &Lut -> In16params); |
| } |
| |
| for (t=0; t < (int) Lut -> OutputChan; t++) |
| Out[t] = Lut->T[index + t]; |
| |
| if (dwFlags & SAMPLER_HASTL2) { |
| |
| for (t=0; t < (int) Lut -> OutputChan; t++) |
| Out[t] = cmsLinearInterpLUT16(Out[t], |
| Lut -> L2[t], |
| &Lut -> Out16params); |
| } |
| |
| |
| if (!Sampler(In, Out, Cargo)) |
| return FALSE; |
| |
| if (!(dwFlags & SAMPLER_INSPECT)) { |
| |
| if (dwFlags & SAMPLER_HASTL2) { |
| |
| for (t=0; t < (int) Lut -> OutputChan; t++) |
| Out[t] = cmsReverseLinearInterpLUT16(Out[t], |
| Lut -> L2[t], |
| &Lut -> Out16params); |
| } |
| |
| |
| for (t=0; t < (int) Lut -> OutputChan; t++) |
| Lut->T[index + t] = Out[t]; |
| |
| } |
| |
| index += Lut -> OutputChan; |
| |
| } |
| |
| return TRUE; |
| } |
| |
| |
| |
| |
| |
| |
| // choose reasonable resolution |
| int _cmsReasonableGridpointsByColorspace(icColorSpaceSignature Colorspace, DWORD dwFlags) |
| { |
| int nChannels; |
| |
| // Already specified? |
| if (dwFlags & 0x00FF0000) { |
| // Yes, grab'em |
| return (dwFlags >> 16) & 0xFF; |
| } |
| |
| nChannels = _cmsChannelsOf(Colorspace); |
| |
| // HighResPrecalc is maximum resolution |
| |
| if (dwFlags & cmsFLAGS_HIGHRESPRECALC) { |
| |
| if (nChannels > 4) |
| return 7; // 7 for Hifi |
| |
| if (nChannels == 4) // 23 for CMYK |
| return 23; |
| |
| return 49; // 49 for RGB and others |
| } |
| |
| |
| // LowResPrecal is stripped resolution |
| |
| if (dwFlags & cmsFLAGS_LOWRESPRECALC) { |
| |
| if (nChannels > 4) |
| return 6; // 6 for Hifi |
| |
| if (nChannels == 1) |
| return 33; // For monochrome |
| |
| return 17; // 17 for remaining |
| } |
| |
| // Default values |
| |
| if (nChannels > 4) |
| return 7; // 7 for Hifi |
| |
| if (nChannels == 4) |
| return 17; // 17 for CMYK |
| |
| return 33; // 33 for RGB |
| |
| } |
| |
| // Sampler implemented by another transform. This is a clean way to |
| // precalculate the devicelink 3D CLUT for almost any transform |
| |
| static |
| int XFormSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) |
| { |
| cmsDoTransform((cmsHTRANSFORM) Cargo, In, Out, 1); |
| return TRUE; |
| } |
| |
| // This routine does compute the devicelink CLUT containing whole |
| // transform. Handles any channel number. |
| |
| LPLUT _cmsPrecalculateDeviceLink(cmsHTRANSFORM h, DWORD dwFlags) |
| { |
| _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) h; |
| LPLUT Grid; |
| int nGridPoints; |
| DWORD dwFormatIn, dwFormatOut; |
| DWORD SaveFormatIn, SaveFormatOut; |
| int ChannelsIn, ChannelsOut; |
| LPLUT SaveGamutLUT; |
| |
| |
| // Remove any gamut checking |
| SaveGamutLUT = p ->Gamut; |
| p ->Gamut = NULL; |
| |
| ChannelsIn = _cmsChannelsOf(p -> EntryColorSpace); |
| ChannelsOut = _cmsChannelsOf(p -> ExitColorSpace); |
| |
| nGridPoints = _cmsReasonableGridpointsByColorspace(p -> EntryColorSpace, dwFlags); |
| |
| Grid = cmsAllocLUT(); |
| if (!Grid) return NULL; |
| |
| Grid = cmsAlloc3DGrid(Grid, nGridPoints, ChannelsIn, ChannelsOut); |
| |
| // Compute device link on 16-bit basis |
| dwFormatIn = (CHANNELS_SH(ChannelsIn)|BYTES_SH(2)); |
| dwFormatOut = (CHANNELS_SH(ChannelsOut)|BYTES_SH(2)); |
| |
| SaveFormatIn = p ->InputFormat; |
| SaveFormatOut = p ->OutputFormat; |
| |
| p -> InputFormat = dwFormatIn; |
| p -> OutputFormat = dwFormatOut; |
| p -> FromInput = _cmsIdentifyInputFormat(p, dwFormatIn); |
| p -> ToOutput = _cmsIdentifyOutputFormat(p, dwFormatOut); |
| |
| // Fix gamut & gamma possible mismatches. |
| |
| if (!(dwFlags & cmsFLAGS_NOPRELINEARIZATION)) { |
| |
| cmsHTRANSFORM hOne[1]; |
| hOne[0] = h; |
| |
| _cmsComputePrelinearizationTablesFromXFORM(hOne, 1, Grid); |
| } |
| |
| // Attention to this typecast! we can take the luxury to |
| // do this since cmsHTRANSFORM is only an alias to a pointer |
| // to the transform struct. |
| |
| if (!cmsSample3DGrid(Grid, XFormSampler, (LPVOID) p, Grid -> wFlags)) { |
| |
| cmsFreeLUT(Grid); |
| Grid = NULL; |
| } |
| |
| p ->Gamut = SaveGamutLUT; |
| p ->InputFormat = SaveFormatIn; |
| p ->OutputFormat = SaveFormatOut; |
| |
| return Grid; |
| } |
| |
| |
| |
| // Sampler for Black-preserving CMYK->CMYK transforms |
| |
| typedef struct { |
| cmsHTRANSFORM cmyk2cmyk; |
| cmsHTRANSFORM cmyk2Lab; |
| LPGAMMATABLE KTone; |
| L16PARAMS KToneParams; |
| LPLUT LabK2cmyk; |
| double MaxError; |
| |
| cmsHTRANSFORM hRoundTrip; |
| int MaxTAC; |
| |
| cmsHTRANSFORM hProofOutput; |
| |
| } BPCARGO, *LPBPCARGO; |
| |
| |
| |
| // Preserve black only if that is the only ink used |
| static |
| int BlackPreservingGrayOnlySampler(register WORD In[], register WORD Out[], register LPVOID Cargo) |
| { |
| BPCARGO* bp = (LPBPCARGO) Cargo; |
| |
| // If going across black only, keep black only |
| if (In[0] == 0 && In[1] == 0 && In[2] == 0) { |
| |
| // TAC does not apply because it is black ink! |
| Out[0] = Out[1] = Out[2] = 0; |
| Out[3] = cmsLinearInterpLUT16(In[3], bp->KTone ->GammaTable, &bp->KToneParams); |
| return 1; |
| } |
| |
| // Keep normal transform for other colors |
| cmsDoTransform(bp ->cmyk2cmyk, In, Out, 1); |
| return 1; |
| } |
| |
| |
| |
| // Preserve all K plane. |
| static |
| int BlackPreservingSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) |
| { |
| |
| WORD LabK[4]; |
| double SumCMY, SumCMYK, Error; |
| cmsCIELab ColorimetricLab, BlackPreservingLab; |
| BPCARGO* bp = (LPBPCARGO) Cargo; |
| |
| // Get the K across Tone curve |
| LabK[3] = cmsLinearInterpLUT16(In[3], bp->KTone ->GammaTable, &bp->KToneParams); |
| |
| // If going across black only, keep black only |
| if (In[0] == 0 && In[1] == 0 && In[2] == 0) { |
| |
| Out[0] = Out[1] = Out[2] = 0; |
| Out[3] = LabK[3]; |
| return 1; |
| } |
| |
| // Try the original transform, maybe K is already ok (valid on K=0) |
| cmsDoTransform(bp ->cmyk2cmyk, In, Out, 1); |
| if (Out[3] == LabK[3]) return 1; |
| |
| |
| // No, mesure and keep Lab measurement for further usage |
| cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1); |
| |
| // Is not black only and the transform doesn't keep black. |
| // Obtain the Lab of CMYK. After that we have Lab + K |
| cmsDoTransform(bp ->cmyk2Lab, In, LabK, 1); |
| |
| // Obtain the corresponding CMY using reverse interpolation. |
| // As a seed, we use the colorimetric CMY |
| cmsEvalLUTreverse(bp ->LabK2cmyk, LabK, Out, Out); |
| |
| // Estimate the error |
| cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); |
| Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); |
| |
| |
| // Apply TAC if needed |
| |
| SumCMY = Out[0] + Out[1] + Out[2]; |
| SumCMYK = SumCMY + Out[3]; |
| |
| if (SumCMYK > bp ->MaxTAC) { |
| |
| double Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY); |
| if (Ratio < 0) |
| Ratio = 0; |
| |
| Out[0] = (WORD) floor(Out[0] * Ratio + 0.5); // C |
| Out[1] = (WORD) floor(Out[1] * Ratio + 0.5); // M |
| Out[2] = (WORD) floor(Out[2] * Ratio + 0.5); // Y |
| } |
| |
| return 1; |
| } |
| |
| |
| // Sample whole gamut to estimate maximum TAC |
| |
| #ifdef _MSC_VER |
| #pragma warning(disable : 4100) |
| #endif |
| |
| static |
| int EstimateTAC(register WORD In[], register WORD Out[], register LPVOID Cargo) |
| { |
| BPCARGO* bp = (LPBPCARGO) Cargo; |
| WORD RoundTrip[4]; |
| int Sum; |
| |
| cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1); |
| |
| Sum = RoundTrip[0] + RoundTrip[1] + RoundTrip[2] + RoundTrip[3]; |
| |
| if (Sum > bp ->MaxTAC) |
| bp ->MaxTAC = Sum; |
| |
| return 1; |
| } |
| |
| |
| // Estimate the maximum error |
| static |
| int BlackPreservingEstimateErrorSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) |
| { |
| BPCARGO* bp = (LPBPCARGO) Cargo; |
| WORD ColorimetricOut[4]; |
| cmsCIELab ColorimetricLab, BlackPreservingLab; |
| double Error; |
| |
| if (In[0] == 0 && In[1] == 0 && In[2] == 0) return 1; |
| |
| cmsDoTransform(bp->cmyk2cmyk, In, ColorimetricOut, 1); |
| |
| cmsDoTransform(bp->hProofOutput, ColorimetricOut, &ColorimetricLab, 1); |
| cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); |
| |
| Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); |
| |
| if (Error > bp ->MaxError) |
| bp ->MaxError = Error; |
| |
| return 1; |
| } |
| |
| // Setup the K preservation strategy |
| int LCMSEXPORT cmsSetCMYKPreservationStrategy(int n) |
| { |
| int OldVal = GlobalBlackPreservationStrategy; |
| |
| if (n >= 0) |
| GlobalBlackPreservationStrategy = n; |
| |
| return OldVal; |
| } |
| |
| #pragma warning(disable: 4550) |
| |
| // Get a pointer to callback on depending of strategy |
| static |
| _cmsSAMPLER _cmsGetBlackPreservationSampler(void) |
| { |
| switch (GlobalBlackPreservationStrategy) { |
| |
| case 0: return BlackPreservingGrayOnlySampler; |
| default: return BlackPreservingSampler; |
| } |
| |
| } |
| |
| // This is the black-preserving devicelink generator |
| LPLUT _cmsPrecalculateBlackPreservingDeviceLink(cmsHTRANSFORM hCMYK2CMYK, DWORD dwFlags) |
| { |
| _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) hCMYK2CMYK; |
| BPCARGO Cargo; |
| LPLUT Grid; |
| DWORD LocalFlags; |
| cmsHPROFILE hLab = cmsCreateLabProfile(NULL); |
| int nGridPoints; |
| icTagSignature Device2PCS[] = {icSigAToB0Tag, // Perceptual |
| icSigAToB1Tag, // Relative colorimetric |
| icSigAToB2Tag, // Saturation |
| icSigAToB1Tag }; // Absolute colorimetric |
| // (Relative/WhitePoint) |
| |
| nGridPoints = _cmsReasonableGridpointsByColorspace(p -> EntryColorSpace, dwFlags); |
| |
| // Get a copy of inteserting flags for this kind of xform |
| LocalFlags = cmsFLAGS_NOTPRECALC; |
| if (p -> dwOriginalFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) |
| LocalFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION; |
| |
| // Fill in cargo struct |
| Cargo.cmyk2cmyk = hCMYK2CMYK; |
| |
| // Compute tone curve. |
| Cargo.KTone = _cmsBuildKToneCurve(hCMYK2CMYK, 256); |
| if (Cargo.KTone == NULL) return NULL; |
| cmsCalcL16Params(Cargo.KTone ->nEntries, &Cargo.KToneParams); |
| |
| |
| // Create a CMYK->Lab "normal" transform on input, without K-preservation |
| Cargo.cmyk2Lab = cmsCreateTransform(p ->InputProfile, TYPE_CMYK_16, |
| hLab, TYPE_Lab_16, p->Intent, LocalFlags); |
| |
| // We are going to use the reverse of proof direction |
| Cargo.LabK2cmyk = cmsReadICCLut(p->OutputProfile, Device2PCS[p->Intent]); |
| |
| // Is there any table available? |
| if (Cargo.LabK2cmyk == NULL) { |
| |
| Grid = NULL; |
| goto Cleanup; |
| } |
| |
| // Setup a roundtrip on output profile for TAC estimation |
| Cargo.hRoundTrip = cmsCreateTransform(p ->OutputProfile, TYPE_CMYK_16, |
| p ->OutputProfile, TYPE_CMYK_16, p->Intent, cmsFLAGS_NOTPRECALC); |
| |
| |
| // Setup a proof CMYK->Lab on output |
| Cargo.hProofOutput = cmsCreateTransform(p ->OutputProfile, TYPE_CMYK_16, |
| hLab, TYPE_Lab_DBL, p->Intent, LocalFlags); |
| |
| |
| // Create an empty LUT for holding K-preserving xform |
| Grid = cmsAllocLUT(); |
| if (!Grid) goto Cleanup; |
| |
| Grid = cmsAlloc3DGrid(Grid, nGridPoints, 4, 4); |
| |
| // Setup formatters |
| p -> FromInput = _cmsIdentifyInputFormat(p, TYPE_CMYK_16); |
| p -> ToOutput = _cmsIdentifyOutputFormat(p, TYPE_CMYK_16); |
| |
| |
| |
| // Step #1, estimate TAC |
| Cargo.MaxTAC = 0; |
| if (!cmsSample3DGrid(Grid, EstimateTAC, (LPVOID) &Cargo, 0)) { |
| |
| cmsFreeLUT(Grid); |
| Grid = NULL; |
| goto Cleanup; |
| } |
| |
| |
| // Step #2, compute approximation |
| if (!cmsSample3DGrid(Grid, _cmsGetBlackPreservationSampler(), (LPVOID) &Cargo, 0)) { |
| |
| cmsFreeLUT(Grid); |
| Grid = NULL; |
| goto Cleanup; |
| } |
| |
| // Step #3, estimate error |
| Cargo.MaxError = 0; |
| cmsSample3DGrid(Grid, BlackPreservingEstimateErrorSampler, (LPVOID) &Cargo, SAMPLER_INSPECT); |
| |
| |
| Cleanup: |
| |
| if (Cargo.cmyk2Lab) cmsDeleteTransform(Cargo.cmyk2Lab); |
| if (Cargo.hRoundTrip) cmsDeleteTransform(Cargo.hRoundTrip); |
| if (Cargo.hProofOutput) cmsDeleteTransform(Cargo.hProofOutput); |
| |
| if (hLab) cmsCloseProfile(hLab); |
| if (Cargo.KTone) cmsFreeGamma(Cargo.KTone); |
| if (Cargo.LabK2cmyk) cmsFreeLUT(Cargo.LabK2cmyk); |
| |
| return Grid; |
| } |
| |
| |
| |
| // Fix broken LUT. just to obtain other CMS compatibility |
| |
| static |
| void PatchLUT(LPLUT Grid, WORD At[], WORD Value[], |
| int nChannelsOut, int nChannelsIn) |
| { |
| LPL16PARAMS p16 = &Grid -> CLut16params; |
| double px, py, pz, pw; |
| int x0, y0, z0, w0; |
| int i, index; |
| |
| |
| if (Grid ->wFlags & LUT_HASTL1) return; // There is a prelinearization |
| |
| px = ((double) At[0] * (p16->Domain)) / 65535.0; |
| py = ((double) At[1] * (p16->Domain)) / 65535.0; |
| pz = ((double) At[2] * (p16->Domain)) / 65535.0; |
| pw = ((double) At[3] * (p16->Domain)) / 65535.0; |
| |
| x0 = (int) floor(px); |
| y0 = (int) floor(py); |
| z0 = (int) floor(pz); |
| w0 = (int) floor(pw); |
| |
| if (nChannelsIn == 4) { |
| |
| if (((px - x0) != 0) || |
| ((py - y0) != 0) || |
| ((pz - z0) != 0) || |
| ((pw - w0) != 0)) return; // Not on exact node |
| |
| index = p16 -> opta4 * x0 + |
| p16 -> opta3 * y0 + |
| p16 -> opta2 * z0 + |
| p16 -> opta1 * w0; |
| } |
| else |
| if (nChannelsIn == 3) { |
| |
| if (((px - x0) != 0) || |
| ((py - y0) != 0) || |
| ((pz - z0) != 0)) return; // Not on exact node |
| |
| index = p16 -> opta3 * x0 + |
| p16 -> opta2 * y0 + |
| p16 -> opta1 * z0; |
| } |
| else |
| if (nChannelsIn == 1) { |
| |
| if (((px - x0) != 0)) return; // Not on exact node |
| |
| index = p16 -> opta1 * x0; |
| } |
| else { |
| cmsSignalError(LCMS_ERRC_ABORTED, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn); |
| return; |
| } |
| |
| for (i=0; i < nChannelsOut; i++) |
| Grid -> T[index + i] = Value[i]; |
| |
| } |
| |
| |
| |
| LCMSBOOL _cmsFixWhiteMisalignment(_LPcmsTRANSFORM p) |
| { |
| |
| WORD *WhitePointIn, *WhitePointOut, *BlackPointIn, *BlackPointOut; |
| int nOuts, nIns; |
| |
| |
| if (!p -> DeviceLink) return FALSE; |
| |
| if (p ->Intent == INTENT_ABSOLUTE_COLORIMETRIC) return FALSE; |
| if ((p ->PreviewProfile != NULL) && |
| (p ->ProofIntent == INTENT_ABSOLUTE_COLORIMETRIC)) return FALSE; |
| |
| |
| if (!_cmsEndPointsBySpace(p -> EntryColorSpace, |
| &WhitePointIn, &BlackPointIn, &nIns)) return FALSE; |
| |
| |
| if (!_cmsEndPointsBySpace(p -> ExitColorSpace, |
| &WhitePointOut, &BlackPointOut, &nOuts)) return FALSE; |
| |
| // Fix white only |
| |
| PatchLUT(p -> DeviceLink, WhitePointIn, WhitePointOut, nOuts, nIns); |
| // PatchLUT(p -> DeviceLink, BlackPointIn, BlackPointOut, nOuts, nIns); |
| |
| return TRUE; |
| } |
| |