📄 cmspcs.c
字号:
//// Little cms// Copyright (C) 1998-2005 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.// inter PCS conversions XYZ <-> CIE L* a* b*#include "lcms.h"/* CIE Lab is defined as: L* = 116*f(Y/Yn) - 16 0 <= L* <= 100 a* = 500*[f(X/Xn) - f(Y/Yn)] b* = 200*[f(Y/Yn) - f(Z/Zn)] and f(t) = t^(1/3) 1 >= t > 0.008856 7.787*t + (16/116) 0 <= t <= 0.008856 Reverse transform is: X = Xn*[a* / 500 + (L* + 16) / 116] ^ 3 if (X/Xn) > 0.206893 = Xn*(a* / 500 + L* / 116) / 7.787 if (X/Xn) <= 0.206893 Following ICC. PCS in Lab is coded as: 8 bit Lab PCS: L* 0..100 into a 0..ff byte. a* t + 128 range is -128.0 +127.0 b* 16 bit Lab PCS: L* 0..100 into a 0..ff00 word. a* t + 128 range is -128.0 +127.9961 b* We are always playing with 16 bits-data, so I will ignore the 8-bits encoding scheme.Interchange Space Component Actual Range Encoded RangeCIE XYZ X 0 -> 1.99997 0x0000 -> 0xffffCIE XYZ Y 0 -> 1.99997 0x0000 -> 0xffffCIE XYZ Z 0 -> 1.99997 0x0000 -> 0xffffVersion 2,3-----------CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xff00CIELAB (16 bit) a* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffffCIELAB (16 bit) b* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffffVersion 4---------CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffffCIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffffCIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff*/// On most modern computers, D > 4 M (i.e. a division takes more than 4// multiplications worth of time), so it is probably preferable to compute// a 24 bit result directly.// #define ITERATE 1staticfloat CubeRoot(float x){ float fr, r; int ex, shx; /* Argument reduction */ fr = (float) frexp(x, &ex); /* separate into mantissa and exponent */ shx = ex % 3; if (shx > 0) shx -= 3; /* compute shx such that (ex - shx) is divisible by 3 */ ex = (ex - shx) / 3; /* exponent of cube root */ fr = (float) ldexp(fr, shx); /* 0.125 <= fr < 1.0 */#ifdef ITERATE /* Compute seed with a quadratic approximation */ fr = (-0.46946116F * fr + 1.072302F) * fr + 0.3812513F;/* 0.5<=fr<1 */ r = ldexp(fr, ex); /* 6 bits of precision */ /* Newton-Raphson iterations */ r = (float)(2.0/3.0) * r + (float)(1.0/3.0) * x / (r * r); /* 12 bits */ r = (float)(2.0/3.0) * r + (float)(1.0/3.0) * x / (r * r); /* 24 bits */#else /* ITERATE */ /* Use quartic rational polynomial with error < 2^(-24) */ fr = (float) (((((45.2548339756803022511987494 * fr + 192.2798368355061050458134625) * fr + 119.1654824285581628956914143) * fr + 13.43250139086239872172837314) * fr + 0.1636161226585754240958355063) / ((((14.80884093219134573786480845 * fr + 151.9714051044435648658557668) * fr + 168.5254414101568283957668343) * fr + 33.9905941350215598754191872) * fr + 1.0)); r = (float) ldexp(fr, ex); /* 24 bits of precision */#endif return r;}staticdouble f(double t){ if (t <= 0.008856) return 7.787037037037037037037037037037*t + (16./116.); else return CubeRoot((float) t); // more precisse than return pow(t, 1.0/3.0);}void LCMSEXPORT cmsXYZ2Lab(LPcmsCIEXYZ WhitePoint, LPcmsCIELab Lab, const cmsCIEXYZ* xyz){ double fx, fy, fz; if (xyz -> X == 0 && xyz -> Y == 0 && xyz -> Z == 0) { Lab -> L = 0; Lab -> a = 0; Lab -> b = 0; return; } if (WhitePoint == NULL) WhitePoint = cmsD50_XYZ(); fx = f(xyz->X / WhitePoint->X); fy = f(xyz->Y / WhitePoint->Y); fz = f(xyz->Z / WhitePoint->Z); Lab->L = 116.* fy - 16.; Lab->a = 500.*(fx - fy); Lab->b = 200.*(fy - fz);}void cmsXYZ2LabEncoded(WORD XYZ[3], WORD Lab[3]){ Fixed32 X, Y, Z; double x, y, z, L, a, b; double fx, fy, fz; Fixed32 wL, wa, wb; X = (Fixed32) XYZ[0] << 1; Y = (Fixed32) XYZ[1] << 1; Z = (Fixed32) XYZ[2] << 1; if (X==0 && Y==0 && Z==0) { Lab[0] = 0; Lab[1] = Lab[2] = 0x8000; return; } // PCS is in D50 x = FIXED_TO_DOUBLE(X) / D50X; y = FIXED_TO_DOUBLE(Y) / D50Y; z = FIXED_TO_DOUBLE(Z) / D50Z; fx = f(x); fy = f(y); fz = f(z); L = 116.* fy - 16.; a = 500.*(fx - fy); b = 200.*(fy - fz); a += 128.; b += 128.; wL = (int) (L * 652.800 + .5); wa = (int) (a * 256.0 + .5); wb = (int) (b * 256.0 + .5); Lab[0] = Clamp_L(wL); Lab[1] = Clamp_ab(wa); Lab[2] = Clamp_ab(wb);}staticdouble f_1(double t){ if (t <= ((7.787*0.008856) + (16./116.))) { double tmp; tmp = ((t - (16./116.)) / 7.787037037037037037037037037037); if (tmp <= 0.0) return 0.0; else return tmp; } return t * t * t;}void LCMSEXPORT cmsLab2XYZ(LPcmsCIEXYZ WhitePoint, LPcmsCIEXYZ xyz, const cmsCIELab* Lab){ double x, y, z; if (Lab -> L <= 0) { xyz -> X = 0; xyz -> Y = 0; xyz -> Z = 0; return; } if (WhitePoint == NULL) WhitePoint = cmsD50_XYZ(); y = (Lab-> L + 16.) / 116.0; x = y + 0.002 * Lab -> a; z = y - 0.005 * Lab -> b; xyz -> X = f_1(x) * WhitePoint -> X; xyz -> Y = f_1(y) * WhitePoint -> Y; xyz -> Z = f_1(z) * WhitePoint -> Z;}void cmsLab2XYZEncoded(WORD Lab[3], WORD XYZ[3]){ double L, a, b; double X, Y, Z, x, y, z; L = ((double) Lab[0] * 100.0) / 65280.0; if (L==0.0) { XYZ[0] = 0; XYZ[1] = 0; XYZ[2] = 0; return; } a = ((double) Lab[1] / 256.0) - 128.0; b = ((double) Lab[2] / 256.0) - 128.0; y = (L + 16.) / 116.0; x = y + 0.002 * a; z = y - 0.005 * b; X = f_1(x) * D50X; Y = f_1(y) * D50Y; Z = f_1(z) * D50Z; // Convert to 1.15 fixed format PCS XYZ[0] = _cmsClampWord((int) floor(X * 32768.0 + 0.5)); XYZ[1] = _cmsClampWord((int) floor(Y * 32768.0 + 0.5)); XYZ[2] = _cmsClampWord((int) floor(Z * 32768.0 + 0.5)); }staticdouble L2float3(WORD v){ Fixed32 fix32; fix32 = (Fixed32) v; return (double) fix32 / 652.800;}// the a/b partstaticdouble ab2float3(WORD v){ Fixed32 fix32; fix32 = (Fixed32) v; return ((double) fix32/256.0)-128.0;}staticWORD L2Fix3(double L){ return (WORD) (L * 652.800 + 0.5);}staticWORD ab2Fix3(double ab){ return (WORD) ((ab + 128.0) * 256.0 + 0.5);}// ICC 4.0 -- ICC has changed PCS Lab encoding.static WORD L2Fix4(double L){ return (WORD) (L * 655.35 + 0.5);}staticWORD ab2Fix4(double ab){ return (WORD) ((ab + 128.0) * 257.0 + 0.5);}staticdouble L2float4(WORD v){ Fixed32 fix32; fix32 = (Fixed32) v; return (double) fix32 / 655.35;}// the a/b partstaticdouble ab2float4(WORD v){ Fixed32 fix32; fix32 = (Fixed32) v; return ((double) fix32/257.0)-128.0;}void LCMSEXPORT cmsLabEncoded2Float(LPcmsCIELab Lab, const WORD wLab[3]){ Lab->L = L2float3(wLab[0]); Lab->a = ab2float3(wLab[1]); Lab->b = ab2float3(wLab[2]);}void LCMSEXPORT cmsLabEncoded2Float4(LPcmsCIELab Lab, const WORD wLab[3]){ Lab->L = L2float4(wLab[0]); Lab->a = ab2float4(wLab[1]); Lab->b = ab2float4(wLab[2]);}staticdouble Clamp_L_double(double L){ if (L < 0) L = 0; if (L > 100) L = 100; return L;}staticdouble Clamp_ab_double(double ab){ if (ab < -128) ab = -128.0; if (ab > +127.9961) ab = +127.9961; return ab;}void LCMSEXPORT cmsFloat2LabEncoded(WORD wLab[3], const cmsCIELab* fLab){ cmsCIELab Lab; Lab.L = Clamp_L_double(fLab ->L); Lab.a = Clamp_ab_double(fLab ->a); Lab.b = Clamp_ab_double(fLab ->b); wLab[0] = L2Fix3(Lab.L); wLab[1] = ab2Fix3(Lab.a); wLab[2] = ab2Fix3(Lab.b);}void LCMSEXPORT cmsFloat2LabEncoded4(WORD wLab[3], const cmsCIELab* fLab){ cmsCIELab Lab; Lab.L = fLab ->L; Lab.a = fLab ->a; Lab.b = fLab ->b; if (Lab.L < 0) Lab.L = 0; if (Lab.L > 100.) Lab.L = 100.; if (Lab.a < -128.) Lab.a = -128.; if (Lab.a > 127.) Lab.a = 127.; if (Lab.b < -128.) Lab.b = -128.; if (Lab.b > 127.) Lab.b = 127.; wLab[0] = L2Fix4(Lab.L); wLab[1] = ab2Fix4(Lab.a); wLab[2] = ab2Fix4(Lab.b);}void LCMSEXPORT cmsLab2LCh(LPcmsCIELCh LCh, const cmsCIELab* Lab){ double a, b; LCh -> L = Clamp_L_double(Lab -> L); a = Clamp_ab_double(Lab -> a); b = Clamp_ab_double(Lab -> b); LCh -> C = pow(a * a + b * b, 0.5); if (a == 0 && b == 0) LCh -> h = 0; else LCh -> h = atan2(b, a); LCh -> h *= (180. / M_PI); while (LCh -> h >= 360.) // Not necessary, but included as a check. LCh -> h -= 360.; while (LCh -> h < 0) LCh -> h += 360.; }void LCMSEXPORT cmsLCh2Lab(LPcmsCIELab Lab, const cmsCIELCh* LCh){ double h = (LCh -> h * M_PI) / 180.0; Lab -> L = Clamp_L_double(LCh -> L); Lab -> a = Clamp_ab_double(LCh -> C * cos(h)); Lab -> b = Clamp_ab_double(LCh -> C * sin(h)); }// In XYZ All 3 components are encoded using 1.15 fixed pointstaticWORD XYZ2Fix(double d){ return (WORD) floor(d * 32768.0 + 0.5);}void LCMSEXPORT cmsFloat2XYZEncoded(WORD XYZ[3], const cmsCIEXYZ* fXYZ){ cmsCIEXYZ xyz; xyz.X = fXYZ -> X; xyz.Y = fXYZ -> Y; xyz.Z = fXYZ -> Z; // Clamp to encodeable values. // 1.99997 is reserved as out-of-gamut marker if (xyz.Y <= 0) { xyz.X = 0; xyz.Y = 0; xyz.Z = 0; } if (xyz.X > 1.99996) xyz.X = 1.99996; if (xyz.X < 0) xyz.X = 0; if (xyz.Y > 1.99996) xyz.Y = 1.99996; if (xyz.Y < 0) xyz.Y = 0; if (xyz.Z > 1.99996) xyz.Z = 1.99996; if (xyz.Z < 0) xyz.Z = 0; XYZ[0] = XYZ2Fix(xyz.X); XYZ[1] = XYZ2Fix(xyz.Y); XYZ[2] = XYZ2Fix(xyz.Z); }// To convert from Fixed 1.15 point to doublestaticdouble XYZ2float(WORD v){ Fixed32 fix32; // From 1.15 to 15.16 fix32 = v << 1; // From fixed 15.16 to double return FIXED_TO_DOUBLE(fix32);}void LCMSEXPORT cmsXYZEncoded2Float(LPcmsCIEXYZ fXYZ, const WORD XYZ[3]){ fXYZ -> X = XYZ2float(XYZ[0]); fXYZ -> Y = XYZ2float(XYZ[1]); fXYZ -> Z = XYZ2float(XYZ[2]);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -