summaryrefslogtreecommitdiffstats
path: root/debian/lcms/lcms-1.19.dfsg2/src/cmssamp.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/lcms/lcms-1.19.dfsg2/src/cmssamp.c')
-rwxr-xr-xdebian/lcms/lcms-1.19.dfsg2/src/cmssamp.c668
1 files changed, 668 insertions, 0 deletions
diff --git a/debian/lcms/lcms-1.19.dfsg2/src/cmssamp.c b/debian/lcms/lcms-1.19.dfsg2/src/cmssamp.c
new file mode 100755
index 00000000..b6bfd855
--- /dev/null
+++ b/debian/lcms/lcms-1.19.dfsg2/src/cmssamp.c
@@ -0,0 +1,668 @@
+//
+// 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;
+}
+