4 * Colorspace conversions for the Common UNIX Printing System (CUPS).
6 * Copyright 1993-2006 by Easy Software Products.
8 * The color saturation/hue matrix stuff is provided thanks to Mr. Paul
9 * Haeberli at "http://www.sgi.com/grafica/matrix/index.html".
11 * These coded instructions, statements, and computer programs are the
12 * property of Easy Software Products and are protected by Federal
13 * copyright law. Distribution and use rights are outlined in the file
14 * "LICENSE.txt" which should have been included with this file. If this
15 * file is missing or damaged please contact Easy Software Products
18 * Attn: CUPS Licensing Information
19 * Easy Software Products
20 * 44141 Airport View Drive, Suite 204
21 * Hollywood, Maryland 20636 USA
23 * Voice: (301) 373-9600
24 * EMail: cups-info@cups.org
25 * WWW: http://www.cups.org
27 * This file is subject to the Apple OS-Developed Software exception.
31 * cupsImageCMYKToBlack() - Convert CMYK data to black.
32 * cupsImageCMYKToCMY() - Convert CMYK colors to CMY.
33 * cupsImageCMYKToCMYK() - Convert CMYK colors to CMYK.
34 * cupsImageCMYKToRGB() - Convert CMYK colors to device-dependent
36 * cupsImageCMYKToWhite() - Convert CMYK colors to luminance.
37 * cupsImageLut() - Adjust all pixel values with the given
39 * cupsImageRGBAdjust() - Adjust the hue and saturation of the
41 * cupsImageRGBToBlack() - Convert RGB data to black.
42 * cupsImageRGBToCMY() - Convert RGB colors to CMY.
43 * cupsImageRGBToCMYK() - Convert RGB colors to CMYK.
44 * cupsImageRGBToRGB() - Convert RGB colors to device-dependent
46 * cupsImageRGBToWhite() - Convert RGB colors to luminance.
47 * cupsImageSetProfile() - Set the device color profile.
48 * cupsImageSetRasterColorSpace() - Set the destination colorspace.
49 * cupsImageWhiteToBlack() - Convert luminance colors to black.
50 * cupsImageWhiteToCMY() - Convert luminance colors to CMY.
51 * cupsImageWhiteToCMYK() - Convert luminance colors to CMYK.
52 * cupsImageWhiteToRGB() - Convert luminance data to RGB.
53 * cupsImageWhiteToWhite() - Convert luminance colors to device-
54 * dependent luminance.
55 * cielab() - Map CIE Lab transformation...
56 * huerotate() - Rotate the hue, maintaining luminance.
57 * ident() - Make an identity matrix.
58 * mult() - Multiply two matrices.
59 * rgb_to_lab() - Convert an RGB color to CIE Lab.
60 * rgb_to_xyz() - Convert an RGB color to CIE XYZ.
61 * saturate() - Make a saturation matrix.
62 * xform() - Transform a 3D point using a matrix...
63 * xrotate() - Rotate about the x (red) axis...
64 * yrotate() - Rotate about the y (green) axis...
65 * zrotate() - Rotate about the z (blue) axis...
66 * zshear() - Shear z using x and y...
70 * Include necessary headers...
73 #include "image-private.h"
77 * Define some math constants that are required...
81 # define M_PI 3.14159265358979323846
85 # define M_SQRT2 1.41421356237309504880
89 # define M_SQRT1_2 0.70710678118654752440
90 #endif /* !M_SQRT1_2 */
93 * CIE XYZ whitepoint...
96 #define D65_X (0.412453 + 0.357580 + 0.180423)
97 #define D65_Y (0.212671 + 0.715160 + 0.072169)
98 #define D65_Z (0.019334 + 0.119193 + 0.950227)
102 * Lookup table structure...
105 typedef int cups_clut_t
[3][256];
112 static int cupsImageHaveProfile
= 0;
113 /* Do we have a color profile? */
114 static int *cupsImageDensity
;
115 /* Ink/marker density LUT */
116 static cups_clut_t
*cupsImageMatrix
;
117 /* Color transform matrix LUT */
118 static cups_cspace_t cupsImageColorSpace
= CUPS_CSPACE_RGB
;
119 /* Destination colorspace */
126 static float cielab(float x
, float xn
);
127 static void huerotate(float [3][3], float);
128 static void ident(float [3][3]);
129 static void mult(float [3][3], float [3][3], float [3][3]);
130 static void rgb_to_lab(cups_ib_t
*val
);
131 static void rgb_to_xyz(cups_ib_t
*val
);
132 static void saturate(float [3][3], float);
133 static void xform(float [3][3], float, float, float, float *, float *, float *);
134 static void xrotate(float [3][3], float, float);
135 static void yrotate(float [3][3], float, float);
136 static void zrotate(float [3][3], float, float);
137 static void zshear(float [3][3], float, float);
141 * 'cupsImageCMYKToBlack()' - Convert CMYK data to black.
145 cupsImageCMYKToBlack(
146 const cups_ib_t
*in
, /* I - Input pixels */
147 cups_ib_t
*out
, /* I - Output pixels */
148 int count
) /* I - Number of pixels */
150 int k
; /* Black value */
153 if (cupsImageHaveProfile
)
156 k
= (31 * in
[0] + 61 * in
[1] + 8 * in
[2]) / 100 + in
[3];
159 *out
++ = cupsImageDensity
[k
];
161 *out
++ = cupsImageDensity
[255];
169 k
= (31 * in
[0] + 61 * in
[1] + 8 * in
[2]) / 100 + in
[3];
183 * 'cupsImageCMYKToCMY()' - Convert CMYK colors to CMY.
188 const cups_ib_t
*in
, /* I - Input pixels */
189 cups_ib_t
*out
, /* I - Output pixels */
190 int count
) /* I - Number of pixels */
192 int c
, m
, y
, k
; /* CMYK values */
193 int cc
, cm
, cy
; /* Calibrated CMY values */
196 if (cupsImageHaveProfile
)
204 cc
= cupsImageMatrix
[0][0][c
] +
205 cupsImageMatrix
[0][1][m
] +
206 cupsImageMatrix
[0][2][y
] + k
;
207 cm
= cupsImageMatrix
[1][0][c
] +
208 cupsImageMatrix
[1][1][m
] +
209 cupsImageMatrix
[1][2][y
] + k
;
210 cy
= cupsImageMatrix
[2][0][c
] +
211 cupsImageMatrix
[2][1][m
] +
212 cupsImageMatrix
[2][2][y
] + k
;
217 *out
++ = cupsImageDensity
[255];
219 *out
++ = cupsImageDensity
[cc
];
224 *out
++ = cupsImageDensity
[255];
226 *out
++ = cupsImageDensity
[cm
];
231 *out
++ = cupsImageDensity
[255];
233 *out
++ = cupsImageDensity
[cy
];
270 * 'cupsImageCMYKToCMYK()' - Convert CMYK colors to CMYK.
275 const cups_ib_t
*in
, /* I - Input pixels */
276 cups_ib_t
*out
, /* I - Output pixels */
277 int count
) /* I - Number of pixels */
279 int c
, m
, y
, k
; /* CMYK values */
280 int cc
, cm
, cy
; /* Calibrated CMY values */
283 if (cupsImageHaveProfile
)
291 cc
= (cupsImageMatrix
[0][0][c
] +
292 cupsImageMatrix
[0][1][m
] +
293 cupsImageMatrix
[0][2][y
]);
294 cm
= (cupsImageMatrix
[1][0][c
] +
295 cupsImageMatrix
[1][1][m
] +
296 cupsImageMatrix
[1][2][y
]);
297 cy
= (cupsImageMatrix
[2][0][c
] +
298 cupsImageMatrix
[2][1][m
] +
299 cupsImageMatrix
[2][2][y
]);
304 *out
++ = cupsImageDensity
[255];
306 *out
++ = cupsImageDensity
[cc
];
311 *out
++ = cupsImageDensity
[255];
313 *out
++ = cupsImageDensity
[cm
];
318 *out
++ = cupsImageDensity
[255];
320 *out
++ = cupsImageDensity
[cy
];
322 *out
++ = cupsImageDensity
[k
];
342 * 'cupsImageCMYKToRGB()' - Convert CMYK colors to device-dependent RGB.
347 const cups_ib_t
*in
, /* I - Input pixels */
348 cups_ib_t
*out
, /* I - Output pixels */
349 int count
) /* I - Number of pixels */
351 int c
, m
, y
, k
; /* CMYK values */
352 int cr
, cg
, cb
; /* Calibrated RGB values */
355 if (cupsImageHaveProfile
)
364 cr
= cupsImageMatrix
[0][0][c
] +
365 cupsImageMatrix
[0][1][m
] +
366 cupsImageMatrix
[0][2][y
] + k
;
367 cg
= cupsImageMatrix
[1][0][c
] +
368 cupsImageMatrix
[1][1][m
] +
369 cupsImageMatrix
[1][2][y
] + k
;
370 cb
= cupsImageMatrix
[2][0][c
] +
371 cupsImageMatrix
[2][1][m
] +
372 cupsImageMatrix
[2][2][y
] + k
;
377 *out
++ = 255 - cupsImageDensity
[255];
379 *out
++ = 255 - cupsImageDensity
[cr
];
384 *out
++ = 255 - cupsImageDensity
[255];
386 *out
++ = 255 - cupsImageDensity
[cg
];
391 *out
++ = 255 - cupsImageDensity
[255];
393 *out
++ = 255 - cupsImageDensity
[cb
];
426 if (cupsImageColorSpace
== CUPS_CSPACE_CIELab
||
427 cupsImageColorSpace
>= CUPS_CSPACE_ICC1
)
429 else if (cupsImageColorSpace
== CUPS_CSPACE_CIEXYZ
)
439 * 'cupsImageCMYKToWhite()' - Convert CMYK colors to luminance.
443 cupsImageCMYKToWhite(
444 const cups_ib_t
*in
, /* I - Input pixels */
445 cups_ib_t
*out
, /* I - Output pixels */
446 int count
) /* I - Number of pixels */
448 int w
; /* White value */
451 if (cupsImageHaveProfile
)
455 w
= 255 - (31 * in
[0] + 61 * in
[1] + 8 * in
[2]) / 100 - in
[3];
458 *out
++ = cupsImageDensity
[w
];
460 *out
++ = cupsImageDensity
[0];
470 w
= 255 - (31 * in
[0] + 61 * in
[1] + 8 * in
[2]) / 100 - in
[3];
485 * 'cupsImageLut()' - Adjust all pixel values with the given LUT.
489 cupsImageLut(cups_ib_t
*pixels
, /* IO - Input/output pixels */
490 int count
, /* I - Number of pixels/bytes to adjust */
491 const cups_ib_t
*lut
) /* I - Lookup table */
495 *pixels
= lut
[*pixels
];
503 * 'cupsImageRGBAdjust()' - Adjust the hue and saturation of the given RGB colors.
507 cupsImageRGBAdjust(cups_ib_t
*pixels
, /* IO - Input/output pixels */
508 int count
, /* I - Number of pixels to adjust */
509 int saturation
,/* I - Color saturation (%) */
510 int hue
) /* I - Color hue (degrees) */
512 int i
, j
, k
; /* Looping vars */
513 float mat
[3][3]; /* Color adjustment matrix */
514 static int last_sat
= 100, /* Last saturation used */
515 last_hue
= 0; /* Last hue used */
516 static cups_clut_t
*lut
= NULL
; /* Lookup table for matrix */
519 if (saturation
!= last_sat
||
523 * Build the color adjustment matrix...
527 saturate(mat
, saturation
* 0.01);
528 huerotate(mat
, (float)hue
);
531 * Allocate memory for the lookup table...
535 lut
= calloc(3, sizeof(cups_clut_t
));
541 * Convert the matrix into a 3x3 array of lookup tables...
544 for (i
= 0; i
< 3; i
++)
545 for (j
= 0; j
< 3; j
++)
546 for (k
= 0; k
< 256; k
++)
547 lut
[i
][j
][k
] = mat
[i
][j
] * k
+ 0.5;
550 * Save the saturation and hue to compare later...
553 last_sat
= saturation
;
558 * Adjust each pixel in the given buffer.
563 i
= lut
[0][0][pixels
[0]] +
564 lut
[1][0][pixels
[1]] +
565 lut
[2][0][pixels
[2]];
573 i
= lut
[0][1][pixels
[0]] +
574 lut
[1][1][pixels
[1]] +
575 lut
[2][1][pixels
[2]];
583 i
= lut
[0][2][pixels
[0]] +
584 lut
[1][2][pixels
[1]] +
585 lut
[2][2][pixels
[2]];
600 * 'cupsImageRGBToBlack()' - Convert RGB data to black.
605 const cups_ib_t
*in
, /* I - Input pixels */
606 cups_ib_t
*out
, /* I - Output pixels */
607 int count
) /* I - Number of pixels */
609 if (cupsImageHaveProfile
)
612 *out
++ = cupsImageDensity
[255 - (31 * in
[0] + 61 * in
[1] + 8 * in
[2]) / 100];
619 *out
++ = 255 - (31 * in
[0] + 61 * in
[1] + 8 * in
[2]) / 100;
627 * 'cupsImageRGBToCMY()' - Convert RGB colors to CMY.
632 const cups_ib_t
*in
, /* I - Input pixels */
633 cups_ib_t
*out
, /* I - Output pixels */
634 int count
) /* I - Number of pixels */
636 int c
, m
, y
, k
; /* CMYK values */
637 int cc
, cm
, cy
; /* Calibrated CMY values */
640 if (cupsImageHaveProfile
)
646 k
= min(c
, min(m
, y
));
651 cc
= cupsImageMatrix
[0][0][c
] +
652 cupsImageMatrix
[0][1][m
] +
653 cupsImageMatrix
[0][2][y
] + k
;
654 cm
= cupsImageMatrix
[1][0][c
] +
655 cupsImageMatrix
[1][1][m
] +
656 cupsImageMatrix
[1][2][y
] + k
;
657 cy
= cupsImageMatrix
[2][0][c
] +
658 cupsImageMatrix
[2][1][m
] +
659 cupsImageMatrix
[2][2][y
] + k
;
664 *out
++ = cupsImageDensity
[255];
666 *out
++ = cupsImageDensity
[cc
];
671 *out
++ = cupsImageDensity
[255];
673 *out
++ = cupsImageDensity
[cm
];
678 *out
++ = cupsImageDensity
[255];
680 *out
++ = cupsImageDensity
[cy
];
690 k
= min(c
, min(m
, y
));
692 *out
++ = (255 - in
[1] / 4) * (c
- k
) / 255 + k
;
693 *out
++ = (255 - in
[2] / 4) * (m
- k
) / 255 + k
;
694 *out
++ = (255 - in
[0] / 4) * (y
- k
) / 255 + k
;
702 * 'cupsImageRGBToCMYK()' - Convert RGB colors to CMYK.
707 const cups_ib_t
*in
, /* I - Input pixels */
708 cups_ib_t
*out
, /* I - Output pixels */
709 int count
) /* I - Number of pixels */
711 int c
, m
, y
, k
, /* CMYK values */
712 km
; /* Maximum K value */
713 int cc
, cm
, cy
; /* Calibrated CMY values */
716 if (cupsImageHaveProfile
)
722 k
= min(c
, min(m
, y
));
724 if ((km
= max(c
, max(m
, y
))) > k
)
725 k
= k
* k
* k
/ (km
* km
);
731 cc
= (cupsImageMatrix
[0][0][c
] +
732 cupsImageMatrix
[0][1][m
] +
733 cupsImageMatrix
[0][2][y
]);
734 cm
= (cupsImageMatrix
[1][0][c
] +
735 cupsImageMatrix
[1][1][m
] +
736 cupsImageMatrix
[1][2][y
]);
737 cy
= (cupsImageMatrix
[2][0][c
] +
738 cupsImageMatrix
[2][1][m
] +
739 cupsImageMatrix
[2][2][y
]);
744 *out
++ = cupsImageDensity
[255];
746 *out
++ = cupsImageDensity
[cc
];
751 *out
++ = cupsImageDensity
[255];
753 *out
++ = cupsImageDensity
[cm
];
758 *out
++ = cupsImageDensity
[255];
760 *out
++ = cupsImageDensity
[cy
];
762 *out
++ = cupsImageDensity
[k
];
772 k
= min(c
, min(m
, y
));
774 if ((km
= max(c
, max(m
, y
))) > k
)
775 k
= k
* k
* k
/ (km
* km
);
792 * 'cupsImageRGBToRGB()' - Convert RGB colors to device-dependent RGB.
797 const cups_ib_t
*in
, /* I - Input pixels */
798 cups_ib_t
*out
, /* I - Output pixels */
799 int count
) /* I - Number of pixels */
801 int c
, m
, y
, k
; /* CMYK values */
802 int cr
, cg
, cb
; /* Calibrated RGB values */
805 if (cupsImageHaveProfile
)
812 k
= min(c
, min(m
, y
));
817 cr
= cupsImageMatrix
[0][0][c
] +
818 cupsImageMatrix
[0][1][m
] +
819 cupsImageMatrix
[0][2][y
] + k
;
820 cg
= cupsImageMatrix
[1][0][c
] +
821 cupsImageMatrix
[1][1][m
] +
822 cupsImageMatrix
[1][2][y
] + k
;
823 cb
= cupsImageMatrix
[2][0][c
] +
824 cupsImageMatrix
[2][1][m
] +
825 cupsImageMatrix
[2][2][y
] + k
;
830 *out
++ = 255 - cupsImageDensity
[255];
832 *out
++ = 255 - cupsImageDensity
[cr
];
837 *out
++ = 255 - cupsImageDensity
[255];
839 *out
++ = 255 - cupsImageDensity
[cg
];
844 *out
++ = 255 - cupsImageDensity
[255];
846 *out
++ = 255 - cupsImageDensity
[cb
];
854 memcpy(out
, in
, count
* 3);
856 if (cupsImageColorSpace
== CUPS_CSPACE_CIELab
||
857 cupsImageColorSpace
>= CUPS_CSPACE_ICC1
)
867 else if (cupsImageColorSpace
== CUPS_CSPACE_CIEXYZ
)
882 * 'cupsImageRGBToWhite()' - Convert RGB colors to luminance.
887 const cups_ib_t
*in
, /* I - Input pixels */
888 cups_ib_t
*out
, /* I - Output pixels */
889 int count
) /* I - Number of pixels */
891 if (cupsImageHaveProfile
)
895 *out
++ = 255 - cupsImageDensity
[255 - (31 * in
[0] + 61 * in
[1] + 8 * in
[2]) / 100];
904 *out
++ = (31 * in
[0] + 61 * in
[1] + 8 * in
[2]) / 100;
913 * 'cupsImageSetProfile()' - Set the device color profile.
917 cupsImageSetProfile(float d
, /* I - Ink/marker density */
918 float g
, /* I - Ink/marker gamma */
919 float matrix
[3][3]) /* I - Color transform matrix */
921 int i
, j
, k
; /* Looping vars */
922 float m
; /* Current matrix value */
923 int *im
; /* Pointer into cupsImageMatrix */
927 * Allocate memory for the profile data...
930 if (cupsImageMatrix
== NULL
)
931 cupsImageMatrix
= calloc(3, sizeof(cups_clut_t
));
933 if (cupsImageMatrix
== NULL
)
936 if (cupsImageDensity
== NULL
)
937 cupsImageDensity
= calloc(256, sizeof(int));
939 if (cupsImageDensity
== NULL
)
943 * Populate the profile lookup tables...
946 cupsImageHaveProfile
= 1;
948 for (i
= 0, im
= cupsImageMatrix
[0][0]; i
< 3; i
++)
949 for (j
= 0; j
< 3; j
++)
950 for (k
= 0, m
= matrix
[i
][j
]; k
< 256; k
++)
951 *im
++ = (int)(k
* m
+ 0.5);
953 for (k
= 0, im
= cupsImageDensity
; k
< 256; k
++)
954 *im
++ = 255.0 * d
* pow((float)k
/ 255.0, g
) + 0.5;
959 * 'cupsImageSetRasterColorSpace()' - Set the destination colorspace.
963 cupsImageSetRasterColorSpace(
964 cups_cspace_t cs
) /* I - Destination colorspace */
967 * Set the destination colorspace...
970 cupsImageColorSpace
= cs
;
973 * Don't use color profiles in colorimetric colorspaces...
976 if (cs
== CUPS_CSPACE_CIEXYZ
||
977 cs
== CUPS_CSPACE_CIELab
||
978 cs
>= CUPS_CSPACE_ICC1
)
979 cupsImageHaveProfile
= 0;
984 * 'cupsImageWhiteToBlack()' - Convert luminance colors to black.
988 cupsImageWhiteToBlack(
989 const cups_ib_t
*in
, /* I - Input pixels */
990 cups_ib_t
*out
, /* I - Output pixels */
991 int count
) /* I - Number of pixels */
993 if (cupsImageHaveProfile
)
996 *out
++ = cupsImageDensity
[255 - *in
++];
1002 *out
++ = 255 - *in
++;
1009 * 'cupsImageWhiteToCMY()' - Convert luminance colors to CMY.
1013 cupsImageWhiteToCMY(
1014 const cups_ib_t
*in
, /* I - Input pixels */
1015 cups_ib_t
*out
, /* I - Output pixels */
1016 int count
) /* I - Number of pixels */
1018 if (cupsImageHaveProfile
)
1021 out
[0] = cupsImageDensity
[255 - *in
++];
1032 *out
++ = 255 - *in
++;
1039 * 'cupsImageWhiteToCMYK()' - Convert luminance colors to CMYK.
1043 cupsImageWhiteToCMYK(
1044 const cups_ib_t
*in
, /* I - Input pixels */
1045 cups_ib_t
*out
, /* I - Output pixels */
1046 int count
) /* I - Number of pixels */
1048 if (cupsImageHaveProfile
)
1054 *out
++ = cupsImageDensity
[255 - *in
++];
1063 *out
++ = 255 - *in
++;
1070 * 'cupsImageWhiteToRGB()' - Convert luminance data to RGB.
1074 cupsImageWhiteToRGB(
1075 const cups_ib_t
*in
, /* I - Input pixels */
1076 cups_ib_t
*out
, /* I - Output pixels */
1077 int count
) /* I - Number of pixels */
1079 if (cupsImageHaveProfile
)
1083 out
[0] = 255 - cupsImageDensity
[255 - *in
++];
1098 if (cupsImageColorSpace
== CUPS_CSPACE_CIELab
||
1099 cupsImageColorSpace
>= CUPS_CSPACE_ICC1
)
1100 rgb_to_lab(out
- 3);
1101 else if (cupsImageColorSpace
== CUPS_CSPACE_CIEXYZ
)
1102 rgb_to_xyz(out
- 3);
1111 * 'cupsImageWhiteToWhite()' - Convert luminance colors to device-dependent
1116 cupsImageWhiteToWhite(
1117 const cups_ib_t
*in
, /* I - Input pixels */
1118 cups_ib_t
*out
, /* I - Output pixels */
1119 int count
) /* I - Number of pixels */
1121 if (cupsImageHaveProfile
)
1124 *out
++ = 255 - cupsImageDensity
[255 - *in
++];
1128 memcpy(out
, in
, count
);
1133 * 'cielab()' - Map CIE Lab transformation...
1136 static float /* O - Adjusted color value */
1137 cielab(float x
, /* I - Raw color value */
1138 float xn
) /* I - Whitepoint color value */
1140 float x_xn
; /* Fraction of whitepoint */
1145 if (x_xn
> 0.008856)
1146 return (cbrt(x_xn
));
1148 return (7.787 * x_xn
+ 16.0 / 116.0);
1153 * 'huerotate()' - Rotate the hue, maintaining luminance.
1157 huerotate(float mat
[3][3], /* I - Matrix to append to */
1158 float rot
) /* I - Hue rotation in degrees */
1160 float hmat
[3][3]; /* Hue matrix */
1161 float lx
, ly
, lz
; /* Luminance vector */
1162 float xrs
, xrc
; /* X rotation sine/cosine */
1163 float yrs
, yrc
; /* Y rotation sine/cosine */
1164 float zrs
, zrc
; /* Z rotation sine/cosine */
1165 float zsx
, zsy
; /* Z shear x/y */
1169 * Load the identity matrix...
1175 * Rotate the grey vector into positive Z...
1180 xrotate(hmat
,xrs
,xrc
);
1182 yrs
= -1.0 / sqrt(3.0);
1183 yrc
= -M_SQRT2
* yrs
;
1184 yrotate(hmat
,yrs
,yrc
);
1187 * Shear the space to make the luminance plane horizontal...
1190 xform(hmat
, 0.3086, 0.6094, 0.0820, &lx
, &ly
, &lz
);
1193 zshear(hmat
, zsx
, zsy
);
1199 zrs
= sin(rot
* M_PI
/ 180.0);
1200 zrc
= cos(rot
* M_PI
/ 180.0);
1202 zrotate(hmat
, zrs
, zrc
);
1205 * Unshear the space to put the luminance plane back...
1208 zshear(hmat
, -zsx
, -zsy
);
1211 * Rotate the grey vector back into place...
1214 yrotate(hmat
, -yrs
, yrc
);
1215 xrotate(hmat
, -xrs
, xrc
);
1218 * Append it to the current matrix...
1221 mult(hmat
, mat
, mat
);
1226 * 'ident()' - Make an identity matrix.
1230 ident(float mat
[3][3]) /* I - Matrix to identify */
1245 * 'mult()' - Multiply two matrices.
1249 mult(float a
[3][3], /* I - First matrix */
1250 float b
[3][3], /* I - Second matrix */
1251 float c
[3][3]) /* I - Destination matrix */
1253 int x
, y
; /* Looping vars */
1254 float temp
[3][3]; /* Temporary matrix */
1258 * Multiply a and b, putting the result in temp...
1261 for (y
= 0; y
< 3; y
++)
1262 for (x
= 0; x
< 3; x
++)
1263 temp
[y
][x
] = b
[y
][0] * a
[0][x
] +
1268 * Copy temp to c (that way c can be a pointer to a or b).
1271 memcpy(c
, temp
, sizeof(temp
));
1276 * 'rgb_to_lab()' - Convert an RGB color to CIE Lab.
1280 rgb_to_lab(cups_ib_t
*val
) /* IO - Color value */
1282 float r
, /* Red value */
1283 g
, /* Green value */
1285 ciex
, /* CIE X value */
1286 ciey
, /* CIE Y value */
1287 ciez
, /* CIE Z value */
1288 ciey_yn
, /* Normalized luminance */
1289 ciel
, /* CIE L value */
1290 ciea
, /* CIE a value */
1291 cieb
; /* CIE b value */
1295 * Convert sRGB to linear RGB...
1298 r
= pow((val
[0] / 255.0 + 0.055) / 1.055, 2.4);
1299 g
= pow((val
[1] / 255.0 + 0.055) / 1.055, 2.4);
1300 b
= pow((val
[2] / 255.0 + 0.055) / 1.055, 2.4);
1303 * Convert to CIE XYZ...
1306 ciex
= 0.412453 * r
+ 0.357580 * g
+ 0.180423 * b
;
1307 ciey
= 0.212671 * r
+ 0.715160 * g
+ 0.072169 * b
;
1308 ciez
= 0.019334 * r
+ 0.119193 * g
+ 0.950227 * b
;
1311 * Normalize and convert to CIE Lab...
1314 ciey_yn
= ciey
/ D65_Y
;
1316 if (ciey_yn
> 0.008856)
1317 ciel
= 116 * cbrt(ciey_yn
) - 16;
1319 ciel
= 903.3 * ciey_yn
;
1322 ciea
= 500 * (cielab(ciex
, D65_X
) - cielab(ciey
, D65_Y
));
1323 cieb
= 200 * (cielab(ciey
, D65_Y
) - cielab(ciez
, D65_Z
));
1326 * Scale the L value and bias the a and b values by 128 so that all
1327 * numbers are from 0 to 255.
1330 ciel
= ciel
* 2.55 + 0.5;
1335 * Output 8-bit values...
1340 else if (ciel
< 255.0)
1347 else if (ciea
< 255.0)
1354 else if (cieb
< 255.0)
1362 * 'rgb_to_xyz()' - Convert an RGB color to CIE XYZ.
1366 rgb_to_xyz(cups_ib_t
*val
) /* IO - Color value */
1368 float r
, /* Red value */
1369 g
, /* Green value */
1371 ciex
, /* CIE X value */
1372 ciey
, /* CIE Y value */
1373 ciez
; /* CIE Z value */
1377 * Convert sRGB to linear RGB...
1380 r
= pow((val
[0] / 255.0 + 0.055) / 1.055, 2.4);
1381 g
= pow((val
[1] / 255.0 + 0.055) / 1.055, 2.4);
1382 b
= pow((val
[2] / 255.0 + 0.055) / 1.055, 2.4);
1385 * Convert to CIE XYZ...
1388 ciex
= 0.412453 * r
+ 0.357580 * g
+ 0.180423 * b
;
1389 ciey
= 0.212671 * r
+ 0.715160 * g
+ 0.072169 * b
;
1390 ciez
= 0.019334 * r
+ 0.119193 * g
+ 0.950227 * b
;
1393 * Encode as 8-bit XYZ...
1398 else if (ciex
< 1.1f
)
1399 val
[0] = (int)(231.8181f
* ciex
+ 0.5);
1405 else if (ciey
< 1.1f
)
1406 val
[1] = (int)(231.8181f
* ciey
+ 0.5);
1412 else if (ciez
< 1.1f
)
1413 val
[2] = (int)(231.8181f
* ciez
+ 0.5);
1420 * 'saturate()' - Make a saturation matrix.
1424 saturate(float mat
[3][3], /* I - Matrix to append to */
1425 float sat
) /* I - Desired color saturation */
1427 float smat
[3][3]; /* Saturation matrix */
1430 smat
[0][0] = (1.0 - sat
) * 0.3086 + sat
;
1431 smat
[0][1] = (1.0 - sat
) * 0.3086;
1432 smat
[0][2] = (1.0 - sat
) * 0.3086;
1433 smat
[1][0] = (1.0 - sat
) * 0.6094;
1434 smat
[1][1] = (1.0 - sat
) * 0.6094 + sat
;
1435 smat
[1][2] = (1.0 - sat
) * 0.6094;
1436 smat
[2][0] = (1.0 - sat
) * 0.0820;
1437 smat
[2][1] = (1.0 - sat
) * 0.0820;
1438 smat
[2][2] = (1.0 - sat
) * 0.0820 + sat
;
1440 mult(smat
, mat
, mat
);
1445 * 'xform()' - Transform a 3D point using a matrix...
1449 xform(float mat
[3][3], /* I - Matrix */
1450 float x
, /* I - Input X coordinate */
1451 float y
, /* I - Input Y coordinate */
1452 float z
, /* I - Input Z coordinate */
1453 float *tx
, /* O - Output X coordinate */
1454 float *ty
, /* O - Output Y coordinate */
1455 float *tz
) /* O - Output Z coordinate */
1457 *tx
= x
* mat
[0][0] + y
* mat
[1][0] + z
* mat
[2][0];
1458 *ty
= x
* mat
[0][1] + y
* mat
[1][1] + z
* mat
[2][1];
1459 *tz
= x
* mat
[0][2] + y
* mat
[1][2] + z
* mat
[2][2];
1464 * 'xrotate()' - Rotate about the x (red) axis...
1468 xrotate(float mat
[3][3], /* I - Matrix */
1469 float rs
, /* I - Rotation angle sine */
1470 float rc
) /* I - Rotation angle cosine */
1472 float rmat
[3][3]; /* I - Rotation matrix */
1487 mult(rmat
, mat
, mat
);
1492 * 'yrotate()' - Rotate about the y (green) axis...
1496 yrotate(float mat
[3][3], /* I - Matrix */
1497 float rs
, /* I - Rotation angle sine */
1498 float rc
) /* I - Rotation angle cosine */
1500 float rmat
[3][3]; /* I - Rotation matrix */
1520 * 'zrotate()' - Rotate about the z (blue) axis...
1524 zrotate(float mat
[3][3], /* I - Matrix */
1525 float rs
, /* I - Rotation angle sine */
1526 float rc
) /* I - Rotation angle cosine */
1528 float rmat
[3][3]; /* I - Rotation matrix */
1548 * 'zshear()' - Shear z using x and y...
1552 zshear(float mat
[3][3], /* I - Matrix */
1553 float dx
, /* I - X shear */
1554 float dy
) /* I - Y shear */
1556 float smat
[3][3]; /* Shear matrix */
1571 mult(smat
, mat
, mat
);