3 * @author Pascal Getreuer 2005-2010 <getreuer@gmail.com>
6 * This file implements routines for color transformations between the spaces
7 * sRGB, Y'UV, Y'CbCr, Y'PbPr, Y'DbDr, Y'IQ, HSV, HSL, HSI, CIEXYZ, CIELAB,
8 * CIELUV, CIELCH, and CIECAT02 LMS.
11 * First call GetColorTransform, specifying the source and destination color
12 * spaces as "dest<-src" or "src->dest". Then call ApplyColorTransform to
13 * perform the transform:
15 double S[3] = {173, 0.8, 0.5};
19 if(!(GetColorTransform(&Trans, "HSI -> Lab")))
21 printf("Invalid syntax or unknown color space\n");
25 ApplyColorTransform(Trans, &D[0], &D[1], &D[2], S[0], S[1], S[2]);
27 * "num" is a typedef defined at the beginning of colorspace.h that may be set
28 * to either double or float, depending on the application.
30 * Specific transformation routines can also be called directly. The following
31 * converts an sRGB color to CIELAB and then back to sRGB:
33 double R = 0.85, G = 0.32, B = 0.5;
35 Rgb2Lab(&L, &a, &b, R, G, B);
36 Lab2Rgb(&R, &G, &B, L, a, b);
38 * Generally, the calling syntax is
40 Foo2Bar(&B0, &B1, &B2, F0, F1, F2);
42 * where (F0,F1,F2) are the coordinates of a color in space "Foo" and
43 * (B0,B1,B2) are the transformed coordinates in space "Bar." For any
44 * transformation routine, its inverse has the sytax
46 Bar2Foo(&F0, &F1, &F2, B0, B1, B2);
49 * The conversion routines are consistently named with the first letter of a
50 * color space capitalized with following letters in lower case and omitting
51 * prime symbols. For example, "Rgb2Ydbdr" converts sRGB to Y'DbDr. For
52 * any transformation routine Foo2Bar, its inverse is Bar2Foo.
54 * All transformations assume a two degree observer angle and a D65 illuminant.
55 * The white point can be changed by modifying the WHITEPOINT_X, WHITEPOINT_Y,
56 * WHITEPOINT_Z definitions at the beginning of colorspace.h.
58 * == List of transformation routines ==
59 * - Rgb2Yuv(double *Y, double *U, double *V, double R, double G, double B)
60 * - Rgb2Ycbcr(double *Y, double *Cb, double *Cr, double R, double G, double B)
61 * - Rgb2Jpegycbcr(double *Y, double *Cb, double *Cr, double R, double G, double B)
62 * - Rgb2Ypbpr(double *Y, double *Pb, double *Pr, double R, double G, double B)
63 * - Rgb2Ydbdr(double *Y, double *Db, double *Dr, double R, double G, double B)
64 * - Rgb2Yiq(double *Y, double *I, double *Q, double R, double G, double B)
65 * - Rgb2Hsv(double *H, double *S, double *V, double R, double G, double B)
66 * - Rgb2Hsl(double *H, double *S, double *L, double R, double G, double B)
67 * - Rgb2Hsi(double *H, double *S, double *I, double R, double G, double B)
68 * - Rgb2Xyz(double *X, double *Y, double *Z, double R, double G, double B)
69 * - Xyz2Lab(double *L, double *a, double *b, double X, double Y, double Z)
70 * - Xyz2Luv(double *L, double *u, double *v, double X, double Y, double Z)
71 * - Xyz2Lch(double *L, double *C, double *h, double X, double Y, double Z)
72 * - Xyz2Cat02lms(double *L, double *M, double *S, double X, double Y, double Z)
73 * - Rgb2Lab(double *L, double *a, double *b, double R, double G, double B)
74 * - Rgb2Luv(double *L, double *u, double *v, double R, double G, double B)
75 * - Rgb2Lch(double *L, double *C, double *h, double R, double G, double B)
76 * - Rgb2Cat02lms(double *L, double *M, double *S, double R, double G, double B)
77 * (Similarly for the inverse transformations.)
79 * It is possible to transform between two arbitrary color spaces by first
80 * transforming from the source space to sRGB and then transforming from
81 * sRGB to the desired destination space. For transformations between CIE
82 * color spaces, it is convenient to use XYZ as the intermediate space. This
83 * is the strategy used by GetColorTransform and ApplyColorTransform.
86 * The definitions of these spaces and the many of the transformation formulas
89 * Poynton, "Frequently Asked Questions About Gamma"
90 * http://www.poynton.com/notes/colour_and_gamma/GammaFAQ.html
92 * Poynton, "Frequently Asked Questions About Color"
93 * http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html
95 * and Wikipedia articles
96 * http://en.wikipedia.org/wiki/SRGB
97 * http://en.wikipedia.org/wiki/YUV
98 * http://en.wikipedia.org/wiki/YCbCr
99 * http://en.wikipedia.org/wiki/YPbPr
100 * http://en.wikipedia.org/wiki/YDbDr
101 * http://en.wikipedia.org/wiki/YIQ
102 * http://en.wikipedia.org/wiki/HSL_and_HSV
103 * http://en.wikipedia.org/wiki/CIE_1931_color_space
104 * http://en.wikipedia.org/wiki/Lab_color_space
105 * http://en.wikipedia.org/wiki/CIELUV_color_space
106 * http://en.wikipedia.org/wiki/LMS_color_space
108 * == License (BSD) ==
109 * Copyright (c) 2005-2010, Pascal Getreuer
110 * All rights reserved.
112 * Redistribution and use in source and binary forms, with or without
113 * modification, are permitted provided that the following conditions are met:
115 * - Redistributions of source code must retain the above copyright
116 * notice, this list of conditions and the following disclaimer.
117 * - Redistributions in binary form must reproduce the above copyright
118 * notice, this list of conditions and the following disclaimer in
119 * the documentation and/or other materials provided with the distribution.
121 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
122 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
123 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
124 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
125 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
126 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
127 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
128 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
129 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
130 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
131 * POSSIBILITY OF SUCH DAMAGE.
138 #include "gtkmm2ext/colorspace.h"
140 namespace Gtkmm2ext {
142 /** @brief Min of A and B */
143 #define MIN(A,B) (((A) <= (B)) ? (A) : (B))
145 /** @brief Max of A and B */
146 #define MAX(A,B) (((A) >= (B)) ? (A) : (B))
148 /** @brief Min of A, B, and C */
149 #define MIN3(A,B,C) (((A) <= (B)) ? MIN(A,C) : MIN(B,C))
151 /** @brief Max of A, B, and C */
152 #define MAX3(A,B,C) (((A) >= (B)) ? MAX(A,C) : MAX(B,C))
155 /** @brief The constant pi */
156 #define M_PI 3.14159265358979323846264338327950288
160 * @brief sRGB gamma correction, transforms R to R'
161 * http://en.wikipedia.org/wiki/SRGB
163 #define GAMMACORRECTION(t) \
164 (((t) <= 0.0031306684425005883) ? \
165 (12.92*(t)) : (1.055*pow((t), 0.416666666666666667) - 0.055))
168 * @brief Inverse sRGB gamma correction, transforms R' to R
170 #define INVGAMMACORRECTION(t) \
171 (((t) <= 0.0404482362771076) ? \
172 ((t)/12.92) : pow(((t) + 0.055)/1.055, 2.4))
175 * @brief CIE L*a*b* f function (used to convert XYZ to L*a*b*)
176 * http://en.wikipedia.org/wiki/Lab_color_space
179 ((t >= 8.85645167903563082e-3) ? \
180 pow(t,0.333333333333333) : (841.0/108.0)*(t) + (4.0/29.0))
183 * @brief CIE L*a*b* inverse f function
184 * http://en.wikipedia.org/wiki/Lab_color_space
187 ((t >= 0.206896551724137931) ? \
188 ((t)*(t)*(t)) : (108.0/841.0)*((t) - (4.0/29.0)))
190 /** @brief u'v' coordinates of the white point for CIE Lu*v* */
191 #define WHITEPOINT_U ((4*WHITEPOINT_X) \
192 /(WHITEPOINT_X + 15*WHITEPOINT_Y + 3*WHITEPOINT_Z))
193 #define WHITEPOINT_V ((9*WHITEPOINT_Y) \
194 /(WHITEPOINT_X + 15*WHITEPOINT_Y + 3*WHITEPOINT_Z))
196 /** @brief Enumeration of the supported color spaces */
197 #define UNKNOWN_SPACE 0
200 #define YCBCR_SPACE 3
201 #define JPEGYCBCR_SPACE 4
202 #define YPBPR_SPACE 5
203 #define YDBDR_SPACE 6
212 #define CAT02LMS_SPACE 15
214 #define NUM_TRANSFORM_PAIRS 18
219 * == Linear color transformations ==
221 * The following routines implement transformations between sRGB and
222 * the linearly-related color spaces Y'UV, Y'PbPr, Y'DbDr, and Y'IQ.
227 * @brief Convert sRGB to NTSC/PAL Y'UV Luma + Chroma
229 * @param Y, U, V pointers to hold the result
230 * @param R, G, B the input sRGB values
232 * Wikipedia: http://en.wikipedia.org/wiki/YUV
234 void Rgb2Yuv(double *Y, double *U, double *V, double R, double G, double B)
236 *Y = (double)( 0.299*R + 0.587*G + 0.114*B);
237 *U = (double)(-0.147*R - 0.289*G + 0.436*B);
238 *V = (double)( 0.615*R - 0.515*G - 0.100*B);
243 * @brief Convert NTSC/PAL Y'UV to sRGB
245 * @param R, G, B pointers to hold the result
246 * @param Y, U, V the input YUV values
248 void Yuv2Rgb(double *R, double *G, double *B, double Y, double U, double V)
250 *R = (double)(Y - 3.945707070708279e-05*U + 1.1398279671717170825*V);
251 *G = (double)(Y - 0.3946101641414141437*U - 0.5805003156565656797*V);
252 *B = (double)(Y + 2.0319996843434342537*U - 4.813762626262513e-04*V);
256 /** @brief sRGB to Y'CbCr Luma + Chroma */
257 void Rgb2Ycbcr(double *Y, double *Cb, double *Cr, double R, double G, double B)
259 *Y = (double)( 65.481*R + 128.553*G + 24.966*B + 16);
260 *Cb = (double)(-37.797*R - 74.203*G + 112.0 *B + 128);
261 *Cr = (double)(112.0 *R - 93.786*G - 18.214*B + 128);
265 /** @brief Y'CbCr to sRGB */
266 void Ycbcr2Rgb(double *R, double *G, double *B, double Y, double Cr, double Cb)
271 *R = (double)(0.00456621004566210107*Y + 1.1808799897946415e-09*Cr + 0.00625892896994393634*Cb);
272 *G = (double)(0.00456621004566210107*Y - 0.00153632368604490212*Cr - 0.00318811094965570701*Cb);
273 *B = (double)(0.00456621004566210107*Y + 0.00791071623355474145*Cr + 1.1977497040190077e-08*Cb);
277 /** @brief sRGB to JPEG-Y'CbCr Luma + Chroma */
278 void Rgb2Jpegycbcr(double *Y, double *Cb, double *Cr, double R, double G, double B)
280 Rgb2Ypbpr(Y, Cb, Cr, R, G, B);
285 /** @brief JPEG-Y'CbCr to sRGB */
286 void Jpegycbcr2Rgb(double *R, double *G, double *B, double Y, double Cb, double Cr)
290 Ypbpr2Rgb(R, G, B, Y, Cb, Cr);
294 /** @brief sRGB to Y'PbPr Luma (ITU-R BT.601) + Chroma */
295 void Rgb2Ypbpr(double *Y, double *Pb, double *Pr, double R, double G, double B)
297 *Y = (double)( 0.299 *R + 0.587 *G + 0.114 *B);
298 *Pb = (double)(-0.1687367*R - 0.331264*G + 0.5 *B);
299 *Pr = (double)( 0.5 *R - 0.418688*G - 0.081312*B);
303 /** @brief Y'PbPr to sRGB */
304 void Ypbpr2Rgb(double *R, double *G, double *B, double Y, double Pb, double Pr)
306 *R = (double)(0.99999999999914679361*Y - 1.2188941887145875e-06*Pb + 1.4019995886561440468*Pr);
307 *G = (double)(0.99999975910502514331*Y - 0.34413567816504303521*Pb - 0.71413649331646789076*Pr);
308 *B = (double)(1.00000124040004623180*Y + 1.77200006607230409200*Pb + 2.1453384174593273e-06*Pr);
312 /** @brief sRGB to SECAM Y'DbDr Luma + Chroma */
313 void Rgb2Ydbdr(double *Y, double *Db, double *Dr, double R, double G, double B)
315 *Y = (double)( 0.299*R + 0.587*G + 0.114*B);
316 *Db = (double)(-0.450*R - 0.883*G + 1.333*B);
317 *Dr = (double)(-1.333*R + 1.116*G + 0.217*B);
321 /** @brief SECAM Y'DbDr to sRGB */
322 void Ydbdr2Rgb(double *R, double *G, double *B, double Y, double Db, double Dr)
324 *R = (double)(Y + 9.2303716147657e-05*Db - 0.52591263066186533*Dr);
325 *G = (double)(Y - 0.12913289889050927*Db + 0.26789932820759876*Dr);
326 *B = (double)(Y + 0.66467905997895482*Db - 7.9202543533108e-05*Dr);
330 /** @brief sRGB to NTSC YIQ */
331 void Rgb2Yiq(double *Y, double *I, double *Q, double R, double G, double B)
333 *Y = (double)(0.299 *R + 0.587 *G + 0.114 *B);
334 *I = (double)(0.595716*R - 0.274453*G - 0.321263*B);
335 *Q = (double)(0.211456*R - 0.522591*G + 0.311135*B);
339 /** @brief Convert NTSC YIQ to sRGB */
340 void Yiq2Rgb(double *R, double *G, double *B, double Y, double I, double Q)
342 *R = (double)(Y + 0.9562957197589482261*I + 0.6210244164652610754*Q);
343 *G = (double)(Y - 0.2721220993185104464*I - 0.6473805968256950427*Q);
344 *B = (double)(Y - 1.1069890167364901945*I + 1.7046149983646481374*Q);
350 * == Hue Saturation Value/Lightness/Intensity color transformations ==
352 * The following routines implement transformations between sRGB and
353 * color spaces HSV, HSL, and HSI.
358 * @brief Convert an sRGB color to Hue-Saturation-Value (HSV)
360 * @param H, S, V pointers to hold the result
361 * @param R, G, B the input sRGB values scaled in [0,1]
363 * This routine transforms from sRGB to the hexcone HSV color space. The
364 * sRGB values are assumed to be between 0 and 1. The output values are
365 * H = hexagonal hue angle (0 <= H < 360),
366 * S = C/V (0 <= S <= 1),
367 * V = max(R',G',B') (0 <= V <= 1),
368 * where C = max(R',G',B') - min(R',G',B'). The inverse color transformation
369 * is given by Hsv2Rgb.
371 * Wikipedia: http://en.wikipedia.org/wiki/HSL_and_HSV
373 void Rgb2Hsv(double *H, double *S, double *V, double R, double G, double B)
375 double Max = MAX3(R, G, B);
376 double Min = MIN3(R, G, B);
377 double C = Max - Min;
392 *H = 2 + (B - R) / C;
394 *H = 4 + (R - G) / C;
405 * @brief Convert a Hue-Saturation-Value (HSV) color to sRGB
407 * @param R, G, B pointers to hold the result
408 * @param H, S, V the input HSV values
410 * The input values are assumed to be scaled as
414 * The output sRGB values are scaled between 0 and 1. This is the inverse
415 * transformation of Rgb2Hsv.
417 * Wikipedia: http://en.wikipedia.org/wiki/HSL_and_HSV
419 void Hsv2Rgb(double *R, double *G, double *B, double H, double S, double V)
426 H -= 360*floor(H/360);
428 X = C*(1 - fabs(H - 2*floor(H/2) - 1));
469 * @brief Convert an sRGB color to Hue-Saturation-Lightness (HSL)
471 * @param H, S, L pointers to hold the result
472 * @param R, G, B the input sRGB values scaled in [0,1]
474 * This routine transforms from sRGB to the double hexcone HSL color space
475 * The sRGB values are assumed to be between 0 and 1. The outputs are
476 * H = hexagonal hue angle (0 <= H < 360),
477 * S = { C/(2L) if L <= 1/2 (0 <= S <= 1),
478 * { C/(2 - 2L) if L > 1/2
479 * L = (max(R',G',B') + min(R',G',B'))/2 (0 <= L <= 1),
480 * where C = max(R',G',B') - min(R',G',B'). The inverse color transformation
481 * is given by Hsl2Rgb.
483 * Wikipedia: http://en.wikipedia.org/wiki/HSL_and_HSV
485 void Rgb2Hsl(double *H, double *S, double *L, double R, double G, double B)
487 double Max = MAX3(R, G, B);
488 double Min = MIN3(R, G, B);
489 double C = Max - Min;
504 *H = 2 + (B - R) / C;
506 *H = 4 + (R - G) / C;
509 *S = (*L <= 0.5) ? (C/(2*(*L))) : (C/(2 - 2*(*L)));
517 * @brief Convert a Hue-Saturation-Lightness (HSL) color to sRGB
519 * @param R, G, B pointers to hold the result
520 * @param H, S, L the input HSL values
522 * The input values are assumed to be scaled as
526 * The output sRGB values are scaled between 0 and 1. This is the inverse
527 * transformation of Rgb2Hsl.
529 * Wikipedia: http://en.wikipedia.org/wiki/HSL_and_HSV
531 void Hsl2Rgb(double *R, double *G, double *B, double H, double S, double L)
533 double C = (L <= 0.5) ? (2*L*S) : ((2 - 2*L)*S);
534 double Min = L - 0.5*C;
538 H -= 360*floor(H/360);
540 X = C*(1 - fabs(H - 2*floor(H/2) - 1));
581 * @brief Convert an sRGB color to Hue-Saturation-Intensity (HSI)
583 * @param H, S, I pointers to hold the result
584 * @param R, G, B the input sRGB values scaled in [0,1]
586 * This routine transforms from sRGB to the cylindrical HSI color space. The
587 * sRGB values are assumed to be between 0 and 1. The output values are
588 * H = polar hue angle (0 <= H < 360),
589 * S = 1 - min(R',G',B')/I (0 <= S <= 1),
590 * I = (R'+G'+B')/3 (0 <= I <= 1).
591 * The inverse color transformation is given by Hsi2Rgb.
593 * Wikipedia: http://en.wikipedia.org/wiki/HSL_and_HSV
595 void Rgb2Hsi(double *H, double *S, double *I, double R, double G, double B)
597 double alpha = 0.5*(2*R - G - B);
598 double beta = 0.866025403784439*(G - B);
605 *S = 1 - MIN3(R,G,B) / *I;
606 *H = atan2(beta, alpha)*(180/M_PI);
617 * @brief Convert a Hue-Saturation-Intesity (HSI) color to sRGB
619 * @param R, G, B pointers to hold the result
620 * @param H, S, I the input HSI values
622 * The input values are assumed to be scaled as
626 * The output sRGB values are scaled between 0 and 1. This is the inverse
627 * transformation of Rgb2Hsi.
629 * Wikipedia: http://en.wikipedia.org/wiki/HSL_and_HSV
631 void Hsi2Rgb(double *R, double *G, double *B, double H, double S, double I)
633 H -= 360*floor(H/360);
638 *R = I*(1 + S*cos(H*(M_PI/180))/cos((60 - H)*(M_PI/180)));
645 *G = I*(1 + S*cos(H*(M_PI/180))/cos((60 - H)*(M_PI/180)));
652 *B = I*(1 + S*cos(H*(M_PI/180))/cos((60 - H)*(M_PI/180)));
659 * == CIE color transformations ==
661 * The following routines implement transformations between sRGB and
662 * the CIE color spaces XYZ, L*a*b, L*u*v*, and L*C*H*. These
663 * transforms assume a 2 degree observer angle and a D65 illuminant.
668 * @brief Transform sRGB to CIE XYZ with the D65 white point
670 * @param X, Y, Z pointers to hold the result
671 * @param R, G, B the input sRGB values
673 * Poynton, "Frequently Asked Questions About Color," page 10
674 * Wikipedia: http://en.wikipedia.org/wiki/SRGB
675 * Wikipedia: http://en.wikipedia.org/wiki/CIE_1931_color_space
677 void Rgb2Xyz(double *X, double *Y, double *Z, double R, double G, double B)
679 R = INVGAMMACORRECTION(R);
680 G = INVGAMMACORRECTION(G);
681 B = INVGAMMACORRECTION(B);
682 *X = (double)(0.4123955889674142161*R + 0.3575834307637148171*G + 0.1804926473817015735*B);
683 *Y = (double)(0.2125862307855955516*R + 0.7151703037034108499*G + 0.07220049864333622685*B);
684 *Z = (double)(0.01929721549174694484*R + 0.1191838645808485318*G + 0.9504971251315797660*B);
689 * @brief Transform CIE XYZ to sRGB with the D65 white point
691 * @param R, G, B pointers to hold the result
692 * @param X, Y, Z the input XYZ values
694 * Official sRGB specification (IEC 61966-2-1:1999)
695 * Poynton, "Frequently Asked Questions About Color," page 10
696 * Wikipedia: http://en.wikipedia.org/wiki/SRGB
697 * Wikipedia: http://en.wikipedia.org/wiki/CIE_1931_color_space
699 void Xyz2Rgb(double *R, double *G, double *B, double X, double Y, double Z)
701 double R1, B1, G1, Min;
704 R1 = (double)( 3.2406*X - 1.5372*Y - 0.4986*Z);
705 G1 = (double)(-0.9689*X + 1.8758*Y + 0.0415*Z);
706 B1 = (double)( 0.0557*X - 0.2040*Y + 1.0570*Z);
708 Min = MIN3(R1, G1, B1);
710 /* Force nonnegative values so that gamma correction is well-defined. */
718 /* Transform from RGB to R'G'B' */
719 *R = GAMMACORRECTION(R1);
720 *G = GAMMACORRECTION(G1);
721 *B = GAMMACORRECTION(B1);
726 * Convert CIE XYZ to CIE L*a*b* (CIELAB) with the D65 white point
728 * @param L, a, b pointers to hold the result
729 * @param X, Y, Z the input XYZ values
731 * Wikipedia: http://en.wikipedia.org/wiki/Lab_color_space
733 void Xyz2Lab(double *L, double *a, double *b, double X, double Y, double Z)
748 * Convert CIE L*a*b* (CIELAB) to CIE XYZ with the D65 white point
750 * @param X, Y, Z pointers to hold the result
751 * @param L, a, b the input L*a*b* values
753 * Wikipedia: http://en.wikipedia.org/wiki/Lab_color_space
755 void Lab2Xyz(double *X, double *Y, double *Z, double L, double a, double b)
760 *X = WHITEPOINT_X*LABINVF(a);
761 *Y = WHITEPOINT_Y*LABINVF(L);
762 *Z = WHITEPOINT_Z*LABINVF(b);
767 * Convert CIE XYZ to CIE L*u*v* (CIELUV) with the D65 white point
769 * @param L, u, v pointers to hold the result
770 * @param X, Y, Z the input XYZ values
772 * Wikipedia: http://en.wikipedia.org/wiki/CIELUV_color_space
774 void Xyz2Luv(double *L, double *u, double *v, double X, double Y, double Z)
776 double u1, v1, Denom;
779 if((Denom = X + 15*Y + 3*Z) > 0)
790 *u = 13*(*L)*(u1 - WHITEPOINT_U);
791 *v = 13*(*L)*(v1 - WHITEPOINT_V);
796 * Convert CIE L*u*v* (CIELUV) to CIE XYZ with the D65 white point
798 * @param X, Y, Z pointers to hold the result
799 * @param L, u, v the input L*u*v* values
801 * Wikipedia: http://en.wikipedia.org/wiki/CIELUV_color_space
803 void Luv2Xyz(double *X, double *Y, double *Z, double L, double u, double v)
806 *Y = WHITEPOINT_Y*LABINVF(*Y);
814 u = u/13 + WHITEPOINT_U;
815 v = v/13 + WHITEPOINT_V;
816 *X = (*Y) * ((9*u)/(4*v));
817 *Z = (*Y) * ((3 - 0.75*u)/v - 5);
822 * Convert CIE XYZ to CIE L*C*H* with the D65 white point
824 * @param L, C, H pointers to hold the result
825 * @param X, Y, Z the input XYZ values
827 * CIE L*C*H* is related to CIE L*a*b* by
828 * a* = C* cos(H* pi/180),
829 * b* = C* sin(H* pi/180).
831 void Xyz2Lch(double *L, double *C, double *H, double X, double Y, double Z)
836 Xyz2Lab(L, &a, &b, X, Y, Z);
837 *C = sqrt(a*a + b*b);
838 *H = atan2(b, a)*180.0/M_PI;
845 * Convert CIE L*C*H* to CIE XYZ with the D65 white point
847 * @param X, Y, Z pointers to hold the result
848 * @param L, C, H the input L*C*H* values
850 void Lch2Xyz(double *X, double *Y, double *Z, double L, double C, double H)
852 double a = C * cos(H*(M_PI/180.0));
853 double b = C * sin(H*(M_PI/180.0));
856 Lab2Xyz(X, Y, Z, L, a, b);
860 /** @brief XYZ to CAT02 LMS */
861 void Xyz2Cat02lms(double *L, double *M, double *S, double X, double Y, double Z)
863 *L = (double)( 0.7328*X + 0.4296*Y - 0.1624*Z);
864 *M = (double)(-0.7036*X + 1.6975*Y + 0.0061*Z);
865 *S = (double)( 0.0030*X + 0.0136*Y + 0.9834*Z);
869 /** @brief CAT02 LMS to XYZ */
870 void Cat02lms2Xyz(double *X, double *Y, double *Z, double L, double M, double S)
872 *X = (double)( 1.096123820835514*L - 0.278869000218287*M + 0.182745179382773*S);
873 *Y = (double)( 0.454369041975359*L + 0.473533154307412*M + 0.072097803717229*S);
874 *Z = (double)(-0.009627608738429*L - 0.005698031216113*M + 1.015325639954543*S);
879 * == Glue functions for multi-stage transforms ==
882 void Rgb2Lab(double *L, double *a, double *b, double R, double G, double B)
885 Rgb2Xyz(&X, &Y, &Z, R, G, B);
886 Xyz2Lab(L, a, b, X, Y, Z);
890 void Lab2Rgb(double *R, double *G, double *B, double L, double a, double b)
893 Lab2Xyz(&X, &Y, &Z, L, a, b);
894 Xyz2Rgb(R, G, B, X, Y, Z);
898 void Rgb2Luv(double *L, double *u, double *v, double R, double G, double B)
901 Rgb2Xyz(&X, &Y, &Z, R, G, B);
902 Xyz2Luv(L, u, v, X, Y, Z);
906 void Luv2Rgb(double *R, double *G, double *B, double L, double u, double v)
909 Luv2Xyz(&X, &Y, &Z, L, u, v);
910 Xyz2Rgb(R, G, B, X, Y, Z);
913 void Rgb2Lch(double *L, double *C, double *H, double R, double G, double B)
916 Rgb2Xyz(&X, &Y, &Z, R, G, B);
917 Xyz2Lch(L, C, H, X, Y, Z);
921 void Lch2Rgb(double *R, double *G, double *B, double L, double C, double H)
924 Lch2Xyz(&X, &Y, &Z, L, C, H);
925 Xyz2Rgb(R, G, B, X, Y, Z);
929 void Rgb2Cat02lms(double *L, double *M, double *S, double R, double G, double B)
932 Rgb2Xyz(&X, &Y, &Z, R, G, B);
933 Xyz2Cat02lms(L, M, S, X, Y, Z);
937 void Cat02lms2Rgb(double *R, double *G, double *B, double L, double M, double S)
940 Cat02lms2Xyz(&X, &Y, &Z, L, M, S);
941 Xyz2Rgb(R, G, B, X, Y, Z);