diff options
| author | Michele Calgaro <michele.calgaro@yahoo.it> | 2020-09-11 14:38:47 +0900 |
|---|---|---|
| committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2020-09-11 14:38:47 +0900 |
| commit | 884c8093d63402a1ad0b502244b791e3c6782be3 (patch) | |
| tree | a600d4ab0d431a2bdfe4c15b70df43c14fbd8dd0 /debian/lcms/lcms-1.19.dfsg2/src/cmsgamma.c | |
| parent | 14e1aa2006796f147f3f4811fb908a6b01e79253 (diff) | |
| download | extra-dependencies-884c8093d63402a1ad0b502244b791e3c6782be3.tar.gz extra-dependencies-884c8093d63402a1ad0b502244b791e3c6782be3.zip | |
Added debian extra dependency packages.
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'debian/lcms/lcms-1.19.dfsg2/src/cmsgamma.c')
| -rwxr-xr-x | debian/lcms/lcms-1.19.dfsg2/src/cmsgamma.c | 954 |
1 files changed, 954 insertions, 0 deletions
diff --git a/debian/lcms/lcms-1.19.dfsg2/src/cmsgamma.c b/debian/lcms/lcms-1.19.dfsg2/src/cmsgamma.c new file mode 100755 index 00000000..857d82fc --- /dev/null +++ b/debian/lcms/lcms-1.19.dfsg2/src/cmsgamma.c @@ -0,0 +1,954 @@ +// +// 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" + +// Gamma handling. + +LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries); +void LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma); +void LCMSEXPORT cmsFreeGammaTriple(LPGAMMATABLE Gamma[3]); +LPGAMMATABLE LCMSEXPORT cmsBuildGamma(int nEntries, double Gamma); +LPGAMMATABLE LCMSEXPORT cmsDupGamma(LPGAMMATABLE Src); +LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma); +LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[]); +LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma); +LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma, int nPoints); +LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda); + +LCMSBOOL cdecl _cmsSmoothEndpoints(LPWORD Table, int nPoints); + + +// Sampled curves + +LPSAMPLEDCURVE cdecl cmsAllocSampledCurve(int nItems); +void cdecl cmsFreeSampledCurve(LPSAMPLEDCURVE p); +void cdecl cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max); +void cdecl cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max); +LCMSBOOL cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda); +void cdecl cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints); + +LPSAMPLEDCURVE cdecl cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints); + +double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t); +double LCMSEXPORT cmsEstimateGammaEx(LPWORD GammaTable, int nEntries, double Thereshold); + +// ---------------------------------------------------------------------------------------- + + +#define MAX_KNOTS 4096 +typedef float vec[MAX_KNOTS+1]; + + +// Ciclic-redundant-check for assuring table is a true representation of parametric curve + +// The usual polynomial, which is used for AAL5, FDDI, and probably Ethernet +#define QUOTIENT 0x04c11db7 + +static +unsigned int Crc32(unsigned int result, LPVOID ptr, int len) +{ + int i,j; + BYTE octet; + LPBYTE data = (LPBYTE) ptr; + + for (i=0; i < len; i++) { + + octet = *data++; + + for (j=0; j < 8; j++) { + + if (result & 0x80000000) { + + result = (result << 1) ^ QUOTIENT ^ (octet >> 7); + } + else + { + result = (result << 1) ^ (octet >> 7); + } + octet <<= 1; + } + } + + return result; +} + +// Get CRC of gamma table + +unsigned int _cmsCrc32OfGammaTable(LPGAMMATABLE Table) +{ + unsigned int crc = ~0U; + + crc = Crc32(crc, &Table -> Seed.Type, sizeof(int)); + crc = Crc32(crc, Table ->Seed.Params, sizeof(double)*10); + crc = Crc32(crc, &Table ->nEntries, sizeof(int)); + crc = Crc32(crc, Table ->GammaTable, sizeof(WORD) * Table -> nEntries); + + return ~crc; + +} + + +LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries) +{ + LPGAMMATABLE p; + size_t size; + + if (nEntries > 65530 || nEntries <= 0) { + cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't create gammatable of more than 65530 entries"); + return NULL; + } + + size = sizeof(GAMMATABLE) + (sizeof(WORD) * (nEntries-1)); + + p = (LPGAMMATABLE) _cmsMalloc(size); + if (!p) return NULL; + + ZeroMemory(p, size); + + p -> Seed.Type = 0; + p -> nEntries = nEntries; + + return p; +} + +void LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma) +{ + if (Gamma) _cmsFree(Gamma); +} + + + +void LCMSEXPORT cmsFreeGammaTriple(LPGAMMATABLE Gamma[3]) +{ + cmsFreeGamma(Gamma[0]); + cmsFreeGamma(Gamma[1]); + cmsFreeGamma(Gamma[2]); + Gamma[0] = Gamma[1] = Gamma[2] = NULL; +} + + + +// Duplicate a gamma table + +LPGAMMATABLE LCMSEXPORT cmsDupGamma(LPGAMMATABLE In) +{ + LPGAMMATABLE Ptr; + size_t size; + + Ptr = cmsAllocGamma(In -> nEntries); + if (Ptr == NULL) return NULL; + + size = sizeof(GAMMATABLE) + (sizeof(WORD) * (In -> nEntries-1)); + + CopyMemory(Ptr, In, size); + return Ptr; +} + + +// Handle gamma using interpolation tables. The resulting curves can become +// very stange, but are pleasent to eye. + +LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, + LPGAMMATABLE OutGamma) +{ + register int i; + L16PARAMS L16In, L16Out; + LPWORD InPtr, OutPtr; + LPGAMMATABLE p; + + p = cmsAllocGamma(256); + if (!p) return NULL; + + cmsCalcL16Params(InGamma -> nEntries, &L16In); + InPtr = InGamma -> GammaTable; + + cmsCalcL16Params(OutGamma -> nEntries, &L16Out); + OutPtr = OutGamma-> GammaTable; + + for (i=0; i < 256; i++) + { + WORD wValIn, wValOut; + + wValIn = cmsLinearInterpLUT16(RGB_8_TO_16(i), InPtr, &L16In); + wValOut = cmsReverseLinearInterpLUT16(wValIn, OutPtr, &L16Out); + + p -> GammaTable[i] = wValOut; + } + + return p; +} + + + +// New method, using smoothed parametric curves. This works FAR better. +// We want to get +// +// y = f(g^-1(x)) ; f = ingamma, g = outgamma +// +// And this can be parametrized as +// +// y = f(t) +// x = g(t) + + +LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, + LPGAMMATABLE OutGamma, int nPoints) +{ + + LPSAMPLEDCURVE x, y, r; + LPGAMMATABLE res; + + x = cmsConvertGammaToSampledCurve(InGamma, nPoints); + y = cmsConvertGammaToSampledCurve(OutGamma, nPoints); + r = cmsJoinSampledCurves(y, x, nPoints); + + // Does clean "hair" + cmsSmoothSampledCurve(r, 0.001); + + cmsClampSampledCurve(r, 0.0, 65535.0); + + cmsFreeSampledCurve(x); + cmsFreeSampledCurve(y); + + res = cmsConvertSampledCurveToGamma(r, 65535.0); + cmsFreeSampledCurve(r); + + return res; +} + + + +// Reverse a gamma table + +LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma) +{ + register int i; + L16PARAMS L16In; + LPWORD InPtr; + LPGAMMATABLE p; + + // Try to reverse it analytically whatever possible + if (InGamma -> Seed.Type > 0 && InGamma -> Seed.Type <= 5 && + _cmsCrc32OfGammaTable(InGamma) == InGamma -> Seed.Crc32) { + + return cmsBuildParametricGamma(nResultSamples, -(InGamma -> Seed.Type), InGamma ->Seed.Params); + } + + + // Nope, reverse the table + p = cmsAllocGamma(nResultSamples); + if (!p) return NULL; + + cmsCalcL16Params(InGamma -> nEntries, &L16In); + InPtr = InGamma -> GammaTable; + + for (i=0; i < nResultSamples; i++) + { + WORD wValIn, wValOut; + + wValIn = _cmsQuantizeVal(i, nResultSamples); + wValOut = cmsReverseLinearInterpLUT16(wValIn, InPtr, &L16In); + p -> GammaTable[i] = wValOut; + } + + + return p; +} + + + +// Parametric curves +// +// Parameters goes as: Gamma, a, b, c, d, e, f +// Type is the ICC type +1 +// if type is negative, then the curve is analyticaly inverted + +LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[]) +{ + LPGAMMATABLE Table; + double R, Val, dval, e; + int i; + int ParamsByType[] = { 0, 1, 3, 4, 5, 7 }; + + Table = cmsAllocGamma(nEntries); + if (NULL == Table) return NULL; + + Table -> Seed.Type = Type; + + CopyMemory(Table ->Seed.Params, Params, ParamsByType[abs(Type)] * sizeof(double)); + + + for (i=0; i < nEntries; i++) { + + R = (double) i / (nEntries-1); + + switch (Type) { + + // X = Y ^ Gamma + case 1: + Val = pow(R, Params[0]); + break; + + // Type 1 Reversed: X = Y ^1/gamma + case -1: + Val = pow(R, 1/Params[0]); + break; + + // CIE 122-1966 + // Y = (aX + b)^Gamma | X >= -b/a + // Y = 0 | else + case 2: + if (R >= -Params[2] / Params[1]) { + + e = Params[1]*R + Params[2]; + + if (e > 0) + Val = pow(e, Params[0]); + else + Val = 0; + } + else + Val = 0; + break; + + // Type 2 Reversed + // X = (Y ^1/g - b) / a + case -2: + + Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1]; + if (Val < 0) + Val = 0; + break; + + + // IEC 61966-3 + // Y = (aX + b)^Gamma | X <= -b/a + // Y = c | else + case 3: + if (R >= -Params[2] / Params[1]) { + + e = Params[1]*R + Params[2]; + Val = pow(e, Params[0]) + Params[3]; + } + else + Val = Params[3]; + break; + + + // Type 3 reversed + // X=((Y-c)^1/g - b)/a | (Y>=c) + // X=-b/a | (Y<c) + + case -3: + if (R >= Params[3]) { + e = R - Params[3]; + Val = (pow(e, 1/Params[0]) - Params[2]) / Params[1]; + if (Val < 0) Val = 0; + } + else { + Val = -Params[2] / Params[1]; + } + break; + + + // IEC 61966-2.1 (sRGB) + // Y = (aX + b)^Gamma | X >= d + // Y = cX | X < d + case 4: + if (R >= Params[4]) { + + e = Params[1]*R + Params[2]; + if (e > 0) + Val = pow(e, Params[0]); + else + Val = 0; + } + else + Val = R * Params[3]; + break; + + // Type 4 reversed + // X=((Y^1/g-b)/a) | Y >= (ad+b)^g + // X=Y/c | Y< (ad+b)^g + + case -4: + if (R >= pow(Params[1] * Params[4] + Params[2], Params[0])) { + + Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1]; + } + else { + Val = R / Params[3]; + } + break; + + + + // Y = (aX + b)^Gamma + e | X <= d + // Y = cX + f | else + case 5: + if (R >= Params[4]) { + + e = Params[1]*R + Params[2]; + Val = pow(e, Params[0]) + Params[5]; + } + else + Val = R*Params[3] + Params[6]; + break; + + + // Reversed type 5 + // X=((Y-e)1/g-b)/a | Y >=(ad+b)^g+e) + // X=(Y-f)/c | else + case -5: + + if (R >= pow(Params[1] * Params[4], Params[0]) + Params[5]) { + + Val = pow(R - Params[5], 1/Params[0]) - Params[2] / Params[1]; + } + else { + Val = (R - Params[6]) / Params[3]; + } + break; + + default: + cmsSignalError(LCMS_ERRC_ABORTED, "Unsupported parametric curve type=%d", abs(Type)-1); + cmsFreeGamma(Table); + return NULL; + } + + + // Saturate + + dval = Val * 65535.0 + .5; + if (dval > 65535.) dval = 65535.0; + if (dval < 0) dval = 0; + + Table->GammaTable[i] = (WORD) floor(dval); + } + + Table -> Seed.Crc32 = _cmsCrc32OfGammaTable(Table); + + return Table; +} + +// Build a gamma table based on gamma constant + +LPGAMMATABLE LCMSEXPORT cmsBuildGamma(int nEntries, double Gamma) +{ + return cmsBuildParametricGamma(nEntries, 1, &Gamma); +} + + + +// From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite +// differences. in: Graphic Gems IV, Heckbert, P.S. (ed.), Academic press. +// +// Smoothing and interpolation with second differences. +// +// Input: weights (w), data (y): vector from 1 to m. +// Input: smoothing parameter (lambda), length (m). +// Output: smoothed vector (z): vector from 1 to m. + + +static +void smooth2(vec w, vec y, vec z, float lambda, int m) +{ + int i, i1, i2; + vec c, d, e; + d[1] = w[1] + lambda; + c[1] = -2 * lambda / d[1]; + e[1] = lambda /d[1]; + z[1] = w[1] * y[1]; + d[2] = w[2] + 5 * lambda - d[1] * c[1] * c[1]; + c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2]; + e[2] = lambda / d[2]; + z[2] = w[2] * y[2] - c[1] * z[1]; + for (i = 3; i < m - 1; i++) { + i1 = i - 1; i2 = i - 2; + d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; + c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i]; + e[i] = lambda / d[i]; + z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2]; + } + i1 = m - 2; i2 = m - 3; + d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; + c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1]; + z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2]; + i1 = m - 1; i2 = m - 2; + d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2]; + z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m]; + z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m]; + for (i = m - 2; 1<= i; i--) + z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2]; +} + + + +// Smooths a curve sampled at regular intervals + +LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda) + +{ + vec w, y, z; + int i, nItems, Zeros, Poles; + + + if (cmsIsLinear(Tab->GammaTable, Tab->nEntries)) return FALSE; // Nothing to do + + nItems = Tab -> nEntries; + + if (nItems > MAX_KNOTS) { + cmsSignalError(LCMS_ERRC_ABORTED, "cmsSmoothGamma: too many points."); + return FALSE; + } + + ZeroMemory(w, nItems * sizeof(float)); + ZeroMemory(y, nItems * sizeof(float)); + ZeroMemory(z, nItems * sizeof(float)); + + for (i=0; i < nItems; i++) + { + y[i+1] = (float) Tab -> GammaTable[i]; + w[i+1] = 1.0; + } + + smooth2(w, y, z, (float) lambda, nItems); + + // Do some reality - checking... + Zeros = Poles = 0; + for (i=nItems; i > 1; --i) { + + if (z[i] == 0.) Zeros++; + if (z[i] >= 65535.) Poles++; + if (z[i] < z[i-1]) return FALSE; // Non-Monotonic + } + + if (Zeros > (nItems / 3)) return FALSE; // Degenerated, mostly zeros + if (Poles > (nItems / 3)) return FALSE; // Degenerated, mostly poles + + // Seems ok + + for (i=0; i < nItems; i++) { + + // Clamp to WORD + + float v = z[i+1]; + + if (v < 0) v = 0; + if (v > 65535.) v = 65535.; + + Tab -> GammaTable[i] = (WORD) floor(v + .5); + } + + return TRUE; +} + + +// Check if curve is exponential, return gamma if so. + +double LCMSEXPORT cmsEstimateGammaEx(LPWORD GammaTable, int nEntries, double Thereshold) +{ + double gamma, sum, sum2; + double n, x, y, Std; + int i; + + sum = sum2 = n = 0; + + // Does exclude endpoints + for (i=1; i < nEntries - 1; i++) { + + x = (double) i / (nEntries - 1); + y = (double) GammaTable[i] / 65535.; + + // Avoid 7% on lower part to prevent + // artifacts due to linear ramps + + if (y > 0. && y < 1. && x > 0.07) { + + gamma = log(y) / log(x); + sum += gamma; + sum2 += gamma * gamma; + n++; + } + + } + + // Take a look on SD to see if gamma isn't exponential at all + Std = sqrt((n * sum2 - sum * sum) / (n*(n-1))); + + + if (Std > Thereshold) + return -1.0; + + return (sum / n); // The mean +} + + +double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t) +{ + return cmsEstimateGammaEx(t->GammaTable, t->nEntries, 0.7); +} + + +// -----------------------------------------------------------------Sampled curves + +// Allocate a empty curve + +LPSAMPLEDCURVE cmsAllocSampledCurve(int nItems) +{ + LPSAMPLEDCURVE pOut; + + pOut = (LPSAMPLEDCURVE) _cmsMalloc(sizeof(SAMPLEDCURVE)); + if (pOut == NULL) + return NULL; + + if((pOut->Values = (double *) _cmsMalloc(nItems * sizeof(double))) == NULL) + { + _cmsFree(pOut); + return NULL; + } + + pOut->nItems = nItems; + ZeroMemory(pOut->Values, nItems * sizeof(double)); + + return pOut; +} + + +void cmsFreeSampledCurve(LPSAMPLEDCURVE p) +{ + _cmsFree((LPVOID) p -> Values); + _cmsFree((LPVOID) p); +} + + + +// Does duplicate a sampled curve + +LPSAMPLEDCURVE cmsDupSampledCurve(LPSAMPLEDCURVE p) +{ + LPSAMPLEDCURVE out; + + out = cmsAllocSampledCurve(p -> nItems); + if (!out) return NULL; + + CopyMemory(out ->Values, p ->Values, p->nItems * sizeof(double)); + + return out; +} + + +// Take min, max of curve + +void cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max) +{ + int i; + + *Min = 65536.; + *Max = 0.; + + for (i=0; i < p -> nItems; i++) { + + double v = p -> Values[i]; + + if (v < *Min) + *Min = v; + + if (v > *Max) + *Max = v; + } + + if (*Min < 0) *Min = 0; + if (*Max > 65535.0) *Max = 65535.0; +} + +// Clamps to Min, Max + +void cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max) +{ + + int i; + + for (i=0; i < p -> nItems; i++) { + + double v = p -> Values[i]; + + if (v < Min) + v = Min; + + if (v > Max) + v = Max; + + p -> Values[i] = v; + + } + +} + + + +// Smooths a curve sampled at regular intervals + +LCMSBOOL cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double lambda) +{ + vec w, y, z; + int i, nItems; + + nItems = Tab -> nItems; + + if (nItems > MAX_KNOTS) { + cmsSignalError(LCMS_ERRC_ABORTED, "cmsSmoothSampledCurve: too many points."); + return FALSE; + } + + ZeroMemory(w, nItems * sizeof(float)); + ZeroMemory(y, nItems * sizeof(float)); + ZeroMemory(z, nItems * sizeof(float)); + + for (i=0; i < nItems; i++) + { + float value = (float) Tab -> Values[i]; + + y[i+1] = value; + w[i+1] = (float) ((value < 0.0) ? 0 : 1); + } + + + smooth2(w, y, z, (float) lambda, nItems); + + for (i=0; i < nItems; i++) { + + Tab -> Values[i] = z[i+1];; + } + + return TRUE; + +} + + +// Scale a value v, within domain Min .. Max +// to a domain 0..(nPoints-1) + +static +double ScaleVal(double v, double Min, double Max, int nPoints) +{ + + double a, b; + + if (v <= Min) return 0; + if (v >= Max) return (nPoints-1); + + a = (double) (nPoints - 1) / (Max - Min); + b = a * Min; + + return (a * v) - b; + +} + + +// Does rescale a sampled curve to fit in a 0..(nPoints-1) domain + +void cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints) +{ + + int i; + + for (i=0; i < p -> nItems; i++) { + + double v = p -> Values[i]; + + p -> Values[i] = ScaleVal(v, Min, Max, nPoints); + } + +} + + +// Joins two sampled curves for X and Y. Curves should be sorted. + +LPSAMPLEDCURVE cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints) +{ + int i, j; + LPSAMPLEDCURVE out; + double MinX, MinY, MaxX, MaxY; + double x, y, x1, y1, x2, y2, a, b; + + out = cmsAllocSampledCurve(nResultingPoints); + if (out == NULL) + return NULL; + + if (X -> nItems != Y -> nItems) { + + cmsSignalError(LCMS_ERRC_ABORTED, "cmsJoinSampledCurves: invalid curve."); + cmsFreeSampledCurve(out); + return NULL; + } + + // Get endpoints of sampled curves + cmsEndpointsOfSampledCurve(X, &MinX, &MaxX); + cmsEndpointsOfSampledCurve(Y, &MinY, &MaxY); + + + // Set our points + out ->Values[0] = MinY; + for (i=1; i < nResultingPoints; i++) { + + // Scale t to x domain + x = (i * (MaxX - MinX) / (nResultingPoints-1)) + MinX; + + // Find interval in which j is within (always up, + // since fn should be monotonic at all) + + j = 1; + while ((j < X ->nItems - 1) && X ->Values[j] < x) + j++; + + // Now x is within X[j-1], X[j] + x1 = X ->Values[j-1]; x2 = X ->Values[j]; + y1 = Y ->Values[j-1]; y2 = Y ->Values[j]; + + // Interpolate the value + a = (y1 - y2) / (x1 - x2); + b = y1 - a * x1; + y = a* x + b; + + out ->Values[i] = y; + } + + + cmsClampSampledCurve(out, MinY, MaxY); + return out; +} + + + +// Convert between curve types + +LPGAMMATABLE cmsConvertSampledCurveToGamma(LPSAMPLEDCURVE Sampled, double Max) +{ + LPGAMMATABLE Gamma; + int i, nPoints; + + + nPoints = Sampled ->nItems; + + Gamma = cmsAllocGamma(nPoints); + for (i=0; i < nPoints; i++) { + + Gamma->GammaTable[i] = (WORD) floor(ScaleVal(Sampled ->Values[i], 0, Max, 65536) + .5); + } + + return Gamma; + +} + +// Inverse of anterior + +LPSAMPLEDCURVE cmsConvertGammaToSampledCurve(LPGAMMATABLE Gamma, int nPoints) +{ + LPSAMPLEDCURVE Sampled; + L16PARAMS L16; + int i; + WORD wQuant, wValIn; + + if (nPoints > 4096) { + + cmsSignalError(LCMS_ERRC_ABORTED, "cmsConvertGammaToSampledCurve: too many points (max=4096)"); + return NULL; + } + + cmsCalcL16Params(Gamma -> nEntries, &L16); + + Sampled = cmsAllocSampledCurve(nPoints); + for (i=0; i < nPoints; i++) { + wQuant = _cmsQuantizeVal(i, nPoints); + wValIn = cmsLinearInterpLUT16(wQuant, Gamma ->GammaTable, &L16); + Sampled ->Values[i] = (float) wValIn; + } + + return Sampled; +} + + + + +// Smooth endpoints (used in Black/White compensation) + +LCMSBOOL _cmsSmoothEndpoints(LPWORD Table, int nEntries) +{ + vec w, y, z; + int i, Zeros, Poles; + + + + if (cmsIsLinear(Table, nEntries)) return FALSE; // Nothing to do + + + if (nEntries > MAX_KNOTS) { + cmsSignalError(LCMS_ERRC_ABORTED, "_cmsSmoothEndpoints: too many points."); + return FALSE; + } + + ZeroMemory(w, nEntries * sizeof(float)); + ZeroMemory(y, nEntries * sizeof(float)); + ZeroMemory(z, nEntries * sizeof(float)); + + for (i=0; i < nEntries; i++) + { + y[i+1] = (float) Table[i]; + w[i+1] = 1.0; + } + + w[1] = 65535.0; + w[nEntries] = 65535.0; + + smooth2(w, y, z, (float) nEntries, nEntries); + + // Do some reality - checking... + Zeros = Poles = 0; + for (i=nEntries; i > 1; --i) { + + if (z[i] == 0.) Zeros++; + if (z[i] >= 65535.) Poles++; + if (z[i] < z[i-1]) return FALSE; // Non-Monotonic + } + + if (Zeros > (nEntries / 3)) return FALSE; // Degenerated, mostly zeros + if (Poles > (nEntries / 3)) return FALSE; // Degenerated, mostly poles + + // Seems ok + + for (i=0; i < nEntries; i++) { + + // Clamp to WORD + + float v = z[i+1]; + + if (v < 0) v = 0; + if (v > 65535.) v = 65535.; + + Table[i] = (WORD) floor(v + .5); + } + + return TRUE; +} |
