4 * Colorspace conversions for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1993-2006 by Easy Software Products.
9 * The color saturation/hue matrix stuff is provided thanks to Mr. Paul
10 * Haeberli at "http://www.sgi.com/grafica/matrix/index.html".
12 * These coded instructions, statements, and computer programs are the
13 * property of Apple Inc. and are protected by Federal copyright
14 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
15 * which should have been included with this file. If this file is
16 * file is missing or damaged, see the license at "http://www.cups.org/".
18 * This file is subject to the Apple OS-Developed Software exception.
22 * cupsImageCMYKToBlack() - Convert CMYK data to black.
23 * cupsImageCMYKToCMY() - Convert CMYK colors to CMY.
24 * cupsImageCMYKToCMYK() - Convert CMYK colors to CMYK.
25 * cupsImageCMYKToRGB() - Convert CMYK colors to device-dependent
27 * cupsImageCMYKToWhite() - Convert CMYK colors to luminance.
28 * cupsImageLut() - Adjust all pixel values with the given
30 * cupsImageRGBAdjust() - Adjust the hue and saturation of the
32 * cupsImageRGBToBlack() - Convert RGB data to black.
33 * cupsImageRGBToCMY() - Convert RGB colors to CMY.
34 * cupsImageRGBToCMYK() - Convert RGB colors to CMYK.
35 * cupsImageRGBToRGB() - Convert RGB colors to device-dependent
37 * cupsImageRGBToWhite() - Convert RGB colors to luminance.
38 * cupsImageSetProfile() - Set the device color profile.
39 * cupsImageSetRasterColorSpace() - Set the destination colorspace.
40 * cupsImageWhiteToBlack() - Convert luminance colors to black.
41 * cupsImageWhiteToCMY() - Convert luminance colors to CMY.
42 * cupsImageWhiteToCMYK() - Convert luminance colors to CMYK.
43 * cupsImageWhiteToRGB() - Convert luminance data to RGB.
44 * cupsImageWhiteToWhite() - Convert luminance colors to device-
45 * dependent luminance.
46 * cielab() - Map CIE Lab transformation...
47 * huerotate() - Rotate the hue, maintaining luminance.
48 * ident() - Make an identity matrix.
49 * mult() - Multiply two matrices.
50 * rgb_to_lab() - Convert an RGB color to CIE Lab.
51 * rgb_to_xyz() - Convert an RGB color to CIE XYZ.
52 * saturate() - Make a saturation matrix.
53 * xform() - Transform a 3D point using a matrix...
54 * xrotate() - Rotate about the x (red) axis...
55 * yrotate() - Rotate about the y (green) axis...
56 * zrotate() - Rotate about the z (blue) axis...
57 * zshear() - Shear z using x and y...
61 * Include necessary headers...
64 #include "image-private.h"
68 * Define some math constants that are required...
72 # define M_PI 3.14159265358979323846
76 # define M_SQRT2 1.41421356237309504880
80 # define M_SQRT1_2 0.70710678118654752440
81 #endif /* !M_SQRT1_2 */
84 * CIE XYZ whitepoint...
87 #define D65_X (0.412453 + 0.357580 + 0.180423)
88 #define D65_Y (0.212671 + 0.715160 + 0.072169)
89 #define D65_Z (0.019334 + 0.119193 + 0.950227)
93 * Lookup table structure...
96 typedef int cups_clut_t[3][256];
103 static int cupsImageHaveProfile = 0;
104 /* Do we have a color profile? */
105 static int *cupsImageDensity;
106 /* Ink/marker density LUT */
107 static cups_clut_t *cupsImageMatrix;
108 /* Color transform matrix LUT */
109 static cups_cspace_t cupsImageColorSpace = CUPS_CSPACE_RGB;
110 /* Destination colorspace */
117 static float cielab(float x, float xn);
118 static void huerotate(float [3][3], float);
119 static void ident(float [3][3]);
120 static void mult(float [3][3], float [3][3], float [3][3]);
121 static void rgb_to_lab(cups_ib_t *val);
122 static void rgb_to_xyz(cups_ib_t *val);
123 static void saturate(float [3][3], float);
124 static void xform(float [3][3], float, float, float, float *, float *, float *);
125 static void xrotate(float [3][3], float, float);
126 static void yrotate(float [3][3], float, float);
127 static void zrotate(float [3][3], float, float);
128 static void zshear(float [3][3], float, float);
132 * 'cupsImageCMYKToBlack()' - Convert CMYK data to black.
136 cupsImageCMYKToBlack(
137 const cups_ib_t *in, /* I - Input pixels */
138 cups_ib_t *out, /* I - Output pixels */
139 int count) /* I - Number of pixels */
141 int k; /* Black value */
144 if (cupsImageHaveProfile)
147 k = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 + in[3];
150 *out++ = cupsImageDensity[k];
152 *out++ = cupsImageDensity[255];
160 k = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 + in[3];
174 * 'cupsImageCMYKToCMY()' - Convert CMYK colors to CMY.
179 const cups_ib_t *in, /* I - Input pixels */
180 cups_ib_t *out, /* I - Output pixels */
181 int count) /* I - Number of pixels */
183 int c, m, y, k; /* CMYK values */
184 int cc, cm, cy; /* Calibrated CMY values */
187 if (cupsImageHaveProfile)
195 cc = cupsImageMatrix[0][0][c] +
196 cupsImageMatrix[0][1][m] +
197 cupsImageMatrix[0][2][y] + k;
198 cm = cupsImageMatrix[1][0][c] +
199 cupsImageMatrix[1][1][m] +
200 cupsImageMatrix[1][2][y] + k;
201 cy = cupsImageMatrix[2][0][c] +
202 cupsImageMatrix[2][1][m] +
203 cupsImageMatrix[2][2][y] + k;
208 *out++ = cupsImageDensity[255];
210 *out++ = cupsImageDensity[cc];
215 *out++ = cupsImageDensity[255];
217 *out++ = cupsImageDensity[cm];
222 *out++ = cupsImageDensity[255];
224 *out++ = cupsImageDensity[cy];
261 * 'cupsImageCMYKToCMYK()' - Convert CMYK colors to CMYK.
266 const cups_ib_t *in, /* I - Input pixels */
267 cups_ib_t *out, /* I - Output pixels */
268 int count) /* I - Number of pixels */
270 int c, m, y, k; /* CMYK values */
271 int cc, cm, cy; /* Calibrated CMY values */
274 if (cupsImageHaveProfile)
282 cc = (cupsImageMatrix[0][0][c] +
283 cupsImageMatrix[0][1][m] +
284 cupsImageMatrix[0][2][y]);
285 cm = (cupsImageMatrix[1][0][c] +
286 cupsImageMatrix[1][1][m] +
287 cupsImageMatrix[1][2][y]);
288 cy = (cupsImageMatrix[2][0][c] +
289 cupsImageMatrix[2][1][m] +
290 cupsImageMatrix[2][2][y]);
295 *out++ = cupsImageDensity[255];
297 *out++ = cupsImageDensity[cc];
302 *out++ = cupsImageDensity[255];
304 *out++ = cupsImageDensity[cm];
309 *out++ = cupsImageDensity[255];
311 *out++ = cupsImageDensity[cy];
313 *out++ = cupsImageDensity[k];
333 * 'cupsImageCMYKToRGB()' - Convert CMYK colors to device-dependent RGB.
338 const cups_ib_t *in, /* I - Input pixels */
339 cups_ib_t *out, /* I - Output pixels */
340 int count) /* I - Number of pixels */
342 int c, m, y, k; /* CMYK values */
343 int cr, cg, cb; /* Calibrated RGB values */
346 if (cupsImageHaveProfile)
355 cr = cupsImageMatrix[0][0][c] +
356 cupsImageMatrix[0][1][m] +
357 cupsImageMatrix[0][2][y] + k;
358 cg = cupsImageMatrix[1][0][c] +
359 cupsImageMatrix[1][1][m] +
360 cupsImageMatrix[1][2][y] + k;
361 cb = cupsImageMatrix[2][0][c] +
362 cupsImageMatrix[2][1][m] +
363 cupsImageMatrix[2][2][y] + k;
368 *out++ = 255 - cupsImageDensity[255];
370 *out++ = 255 - cupsImageDensity[cr];
375 *out++ = 255 - cupsImageDensity[255];
377 *out++ = 255 - cupsImageDensity[cg];
382 *out++ = 255 - cupsImageDensity[255];
384 *out++ = 255 - cupsImageDensity[cb];
417 if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
418 cupsImageColorSpace >= CUPS_CSPACE_ICC1)
420 else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
430 * 'cupsImageCMYKToWhite()' - Convert CMYK colors to luminance.
434 cupsImageCMYKToWhite(
435 const cups_ib_t *in, /* I - Input pixels */
436 cups_ib_t *out, /* I - Output pixels */
437 int count) /* I - Number of pixels */
439 int w; /* White value */
442 if (cupsImageHaveProfile)
446 w = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 - in[3];
449 *out++ = cupsImageDensity[w];
451 *out++ = cupsImageDensity[0];
461 w = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 - in[3];
476 * 'cupsImageLut()' - Adjust all pixel values with the given LUT.
480 cupsImageLut(cups_ib_t *pixels, /* IO - Input/output pixels */
481 int count, /* I - Number of pixels/bytes to adjust */
482 const cups_ib_t *lut) /* I - Lookup table */
486 *pixels = lut[*pixels];
494 * 'cupsImageRGBAdjust()' - Adjust the hue and saturation of the given RGB colors.
498 cupsImageRGBAdjust(cups_ib_t *pixels, /* IO - Input/output pixels */
499 int count, /* I - Number of pixels to adjust */
500 int saturation,/* I - Color saturation (%) */
501 int hue) /* I - Color hue (degrees) */
503 int i, j, k; /* Looping vars */
504 float mat[3][3]; /* Color adjustment matrix */
505 static int last_sat = 100, /* Last saturation used */
506 last_hue = 0; /* Last hue used */
507 static cups_clut_t *lut = NULL; /* Lookup table for matrix */
510 if (saturation != last_sat || hue != last_hue || !lut)
513 * Build the color adjustment matrix...
517 saturate(mat, saturation * 0.01);
518 huerotate(mat, (float)hue);
521 * Allocate memory for the lookup table...
525 lut = calloc(3, sizeof(cups_clut_t));
531 * Convert the matrix into a 3x3 array of lookup tables...
534 for (i = 0; i < 3; i ++)
535 for (j = 0; j < 3; j ++)
536 for (k = 0; k < 256; k ++)
537 lut[i][j][k] = mat[i][j] * k + 0.5;
540 * Save the saturation and hue to compare later...
543 last_sat = saturation;
548 * Adjust each pixel in the given buffer.
553 i = lut[0][0][pixels[0]] +
554 lut[1][0][pixels[1]] +
555 lut[2][0][pixels[2]];
563 i = lut[0][1][pixels[0]] +
564 lut[1][1][pixels[1]] +
565 lut[2][1][pixels[2]];
573 i = lut[0][2][pixels[0]] +
574 lut[1][2][pixels[1]] +
575 lut[2][2][pixels[2]];
590 * 'cupsImageRGBToBlack()' - Convert RGB data to black.
595 const cups_ib_t *in, /* I - Input pixels */
596 cups_ib_t *out, /* I - Output pixels */
597 int count) /* I - Number of pixels */
599 if (cupsImageHaveProfile)
602 *out++ = cupsImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100];
609 *out++ = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100;
617 * 'cupsImageRGBToCMY()' - Convert RGB colors to CMY.
622 const cups_ib_t *in, /* I - Input pixels */
623 cups_ib_t *out, /* I - Output pixels */
624 int count) /* I - Number of pixels */
626 int c, m, y, k; /* CMYK values */
627 int cc, cm, cy; /* Calibrated CMY values */
630 if (cupsImageHaveProfile)
636 k = min(c, min(m, y));
641 cc = cupsImageMatrix[0][0][c] +
642 cupsImageMatrix[0][1][m] +
643 cupsImageMatrix[0][2][y] + k;
644 cm = cupsImageMatrix[1][0][c] +
645 cupsImageMatrix[1][1][m] +
646 cupsImageMatrix[1][2][y] + k;
647 cy = cupsImageMatrix[2][0][c] +
648 cupsImageMatrix[2][1][m] +
649 cupsImageMatrix[2][2][y] + k;
654 *out++ = cupsImageDensity[255];
656 *out++ = cupsImageDensity[cc];
661 *out++ = cupsImageDensity[255];
663 *out++ = cupsImageDensity[cm];
668 *out++ = cupsImageDensity[255];
670 *out++ = cupsImageDensity[cy];
680 k = min(c, min(m, y));
682 *out++ = (255 - in[1] / 4) * (c - k) / 255 + k;
683 *out++ = (255 - in[2] / 4) * (m - k) / 255 + k;
684 *out++ = (255 - in[0] / 4) * (y - k) / 255 + k;
692 * 'cupsImageRGBToCMYK()' - Convert RGB colors to CMYK.
697 const cups_ib_t *in, /* I - Input pixels */
698 cups_ib_t *out, /* I - Output pixels */
699 int count) /* I - Number of pixels */
701 int c, m, y, k, /* CMYK values */
702 km; /* Maximum K value */
703 int cc, cm, cy; /* Calibrated CMY values */
706 if (cupsImageHaveProfile)
712 k = min(c, min(m, y));
714 if ((km = max(c, max(m, y))) > k)
715 k = k * k * k / (km * km);
721 cc = (cupsImageMatrix[0][0][c] +
722 cupsImageMatrix[0][1][m] +
723 cupsImageMatrix[0][2][y]);
724 cm = (cupsImageMatrix[1][0][c] +
725 cupsImageMatrix[1][1][m] +
726 cupsImageMatrix[1][2][y]);
727 cy = (cupsImageMatrix[2][0][c] +
728 cupsImageMatrix[2][1][m] +
729 cupsImageMatrix[2][2][y]);
734 *out++ = cupsImageDensity[255];
736 *out++ = cupsImageDensity[cc];
741 *out++ = cupsImageDensity[255];
743 *out++ = cupsImageDensity[cm];
748 *out++ = cupsImageDensity[255];
750 *out++ = cupsImageDensity[cy];
752 *out++ = cupsImageDensity[k];
762 k = min(c, min(m, y));
764 if ((km = max(c, max(m, y))) > k)
765 k = k * k * k / (km * km);
782 * 'cupsImageRGBToRGB()' - Convert RGB colors to device-dependent RGB.
787 const cups_ib_t *in, /* I - Input pixels */
788 cups_ib_t *out, /* I - Output pixels */
789 int count) /* I - Number of pixels */
791 int c, m, y, k; /* CMYK values */
792 int cr, cg, cb; /* Calibrated RGB values */
795 if (cupsImageHaveProfile)
802 k = min(c, min(m, y));
807 cr = cupsImageMatrix[0][0][c] +
808 cupsImageMatrix[0][1][m] +
809 cupsImageMatrix[0][2][y] + k;
810 cg = cupsImageMatrix[1][0][c] +
811 cupsImageMatrix[1][1][m] +
812 cupsImageMatrix[1][2][y] + k;
813 cb = cupsImageMatrix[2][0][c] +
814 cupsImageMatrix[2][1][m] +
815 cupsImageMatrix[2][2][y] + k;
820 *out++ = 255 - cupsImageDensity[255];
822 *out++ = 255 - cupsImageDensity[cr];
827 *out++ = 255 - cupsImageDensity[255];
829 *out++ = 255 - cupsImageDensity[cg];
834 *out++ = 255 - cupsImageDensity[255];
836 *out++ = 255 - cupsImageDensity[cb];
844 memcpy(out, in, count * 3);
846 if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
847 cupsImageColorSpace >= CUPS_CSPACE_ICC1)
857 else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
872 * 'cupsImageRGBToWhite()' - Convert RGB colors to luminance.
877 const cups_ib_t *in, /* I - Input pixels */
878 cups_ib_t *out, /* I - Output pixels */
879 int count) /* I - Number of pixels */
881 if (cupsImageHaveProfile)
885 *out++ = 255 - cupsImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100];
894 *out++ = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100;
903 * 'cupsImageSetProfile()' - Set the device color profile.
907 cupsImageSetProfile(float d, /* I - Ink/marker density */
908 float g, /* I - Ink/marker gamma */
909 float matrix[3][3]) /* I - Color transform matrix */
911 int i, j, k; /* Looping vars */
912 float m; /* Current matrix value */
913 int *im; /* Pointer into cupsImageMatrix */
917 * Allocate memory for the profile data...
920 if (cupsImageMatrix == NULL)
921 cupsImageMatrix = calloc(3, sizeof(cups_clut_t));
923 if (cupsImageMatrix == NULL)
926 if (cupsImageDensity == NULL)
927 cupsImageDensity = calloc(256, sizeof(int));
929 if (cupsImageDensity == NULL)
933 * Populate the profile lookup tables...
936 cupsImageHaveProfile = 1;
938 for (i = 0, im = cupsImageMatrix[0][0]; i < 3; i ++)
939 for (j = 0; j < 3; j ++)
940 for (k = 0, m = matrix[i][j]; k < 256; k ++)
941 *im++ = (int)(k * m + 0.5);
943 for (k = 0, im = cupsImageDensity; k < 256; k ++)
944 *im++ = 255.0 * d * pow((float)k / 255.0, g) + 0.5;
949 * 'cupsImageSetRasterColorSpace()' - Set the destination colorspace.
953 cupsImageSetRasterColorSpace(
954 cups_cspace_t cs) /* I - Destination colorspace */
957 * Set the destination colorspace...
960 cupsImageColorSpace = cs;
963 * Don't use color profiles in colorimetric colorspaces...
966 if (cs == CUPS_CSPACE_CIEXYZ ||
967 cs == CUPS_CSPACE_CIELab ||
968 cs >= CUPS_CSPACE_ICC1)
969 cupsImageHaveProfile = 0;
974 * 'cupsImageWhiteToBlack()' - Convert luminance colors to black.
978 cupsImageWhiteToBlack(
979 const cups_ib_t *in, /* I - Input pixels */
980 cups_ib_t *out, /* I - Output pixels */
981 int count) /* I - Number of pixels */
983 if (cupsImageHaveProfile)
986 *out++ = cupsImageDensity[255 - *in++];
992 *out++ = 255 - *in++;
999 * 'cupsImageWhiteToCMY()' - Convert luminance colors to CMY.
1003 cupsImageWhiteToCMY(
1004 const cups_ib_t *in, /* I - Input pixels */
1005 cups_ib_t *out, /* I - Output pixels */
1006 int count) /* I - Number of pixels */
1008 if (cupsImageHaveProfile)
1011 out[0] = cupsImageDensity[255 - *in++];
1022 *out++ = 255 - *in++;
1029 * 'cupsImageWhiteToCMYK()' - Convert luminance colors to CMYK.
1033 cupsImageWhiteToCMYK(
1034 const cups_ib_t *in, /* I - Input pixels */
1035 cups_ib_t *out, /* I - Output pixels */
1036 int count) /* I - Number of pixels */
1038 if (cupsImageHaveProfile)
1044 *out++ = cupsImageDensity[255 - *in++];
1053 *out++ = 255 - *in++;
1060 * 'cupsImageWhiteToRGB()' - Convert luminance data to RGB.
1064 cupsImageWhiteToRGB(
1065 const cups_ib_t *in, /* I - Input pixels */
1066 cups_ib_t *out, /* I - Output pixels */
1067 int count) /* I - Number of pixels */
1069 if (cupsImageHaveProfile)
1073 out[0] = 255 - cupsImageDensity[255 - *in++];
1088 if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
1089 cupsImageColorSpace >= CUPS_CSPACE_ICC1)
1090 rgb_to_lab(out - 3);
1091 else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
1092 rgb_to_xyz(out - 3);
1101 * 'cupsImageWhiteToWhite()' - Convert luminance colors to device-dependent
1106 cupsImageWhiteToWhite(
1107 const cups_ib_t *in, /* I - Input pixels */
1108 cups_ib_t *out, /* I - Output pixels */
1109 int count) /* I - Number of pixels */
1111 if (cupsImageHaveProfile)
1114 *out++ = 255 - cupsImageDensity[255 - *in++];
1118 memcpy(out, in, count);
1123 * 'cielab()' - Map CIE Lab transformation...
1126 static float /* O - Adjusted color value */
1127 cielab(float x, /* I - Raw color value */
1128 float xn) /* I - Whitepoint color value */
1130 float x_xn; /* Fraction of whitepoint */
1135 if (x_xn > 0.008856)
1136 return (cbrt(x_xn));
1138 return (7.787 * x_xn + 16.0 / 116.0);
1143 * 'huerotate()' - Rotate the hue, maintaining luminance.
1147 huerotate(float mat[3][3], /* I - Matrix to append to */
1148 float rot) /* I - Hue rotation in degrees */
1150 float hmat[3][3]; /* Hue matrix */
1151 float lx, ly, lz; /* Luminance vector */
1152 float xrs, xrc; /* X rotation sine/cosine */
1153 float yrs, yrc; /* Y rotation sine/cosine */
1154 float zrs, zrc; /* Z rotation sine/cosine */
1155 float zsx, zsy; /* Z shear x/y */
1159 * Load the identity matrix...
1165 * Rotate the grey vector into positive Z...
1170 xrotate(hmat,xrs,xrc);
1172 yrs = -1.0 / sqrt(3.0);
1173 yrc = -M_SQRT2 * yrs;
1174 yrotate(hmat,yrs,yrc);
1177 * Shear the space to make the luminance plane horizontal...
1180 xform(hmat, 0.3086, 0.6094, 0.0820, &lx, &ly, &lz);
1183 zshear(hmat, zsx, zsy);
1189 zrs = sin(rot * M_PI / 180.0);
1190 zrc = cos(rot * M_PI / 180.0);
1192 zrotate(hmat, zrs, zrc);
1195 * Unshear the space to put the luminance plane back...
1198 zshear(hmat, -zsx, -zsy);
1201 * Rotate the grey vector back into place...
1204 yrotate(hmat, -yrs, yrc);
1205 xrotate(hmat, -xrs, xrc);
1208 * Append it to the current matrix...
1211 mult(hmat, mat, mat);
1216 * 'ident()' - Make an identity matrix.
1220 ident(float mat[3][3]) /* I - Matrix to identify */
1235 * 'mult()' - Multiply two matrices.
1239 mult(float a[3][3], /* I - First matrix */
1240 float b[3][3], /* I - Second matrix */
1241 float c[3][3]) /* I - Destination matrix */
1243 int x, y; /* Looping vars */
1244 float temp[3][3]; /* Temporary matrix */
1248 * Multiply a and b, putting the result in temp...
1251 for (y = 0; y < 3; y ++)
1252 for (x = 0; x < 3; x ++)
1253 temp[y][x] = b[y][0] * a[0][x] +
1258 * Copy temp to c (that way c can be a pointer to a or b).
1261 memcpy(c, temp, sizeof(temp));
1266 * 'rgb_to_lab()' - Convert an RGB color to CIE Lab.
1270 rgb_to_lab(cups_ib_t *val) /* IO - Color value */
1272 float r, /* Red value */
1273 g, /* Green value */
1275 ciex, /* CIE X value */
1276 ciey, /* CIE Y value */
1277 ciez, /* CIE Z value */
1278 ciey_yn, /* Normalized luminance */
1279 ciel, /* CIE L value */
1280 ciea, /* CIE a value */
1281 cieb; /* CIE b value */
1285 * Convert sRGB to linear RGB...
1288 r = pow((val[0] / 255.0 + 0.055) / 1.055, 2.4);
1289 g = pow((val[1] / 255.0 + 0.055) / 1.055, 2.4);
1290 b = pow((val[2] / 255.0 + 0.055) / 1.055, 2.4);
1293 * Convert to CIE XYZ...
1296 ciex = 0.412453 * r + 0.357580 * g + 0.180423 * b;
1297 ciey = 0.212671 * r + 0.715160 * g + 0.072169 * b;
1298 ciez = 0.019334 * r + 0.119193 * g + 0.950227 * b;
1301 * Normalize and convert to CIE Lab...
1304 ciey_yn = ciey / D65_Y;
1306 if (ciey_yn > 0.008856)
1307 ciel = 116 * cbrt(ciey_yn) - 16;
1309 ciel = 903.3 * ciey_yn;
1312 ciea = 500 * (cielab(ciex, D65_X) - cielab(ciey, D65_Y));
1313 cieb = 200 * (cielab(ciey, D65_Y) - cielab(ciez, D65_Z));
1316 * Scale the L value and bias the a and b values by 128 so that all
1317 * numbers are from 0 to 255.
1320 ciel = ciel * 2.55 + 0.5;
1325 * Output 8-bit values...
1330 else if (ciel < 255.0)
1337 else if (ciea < 255.0)
1344 else if (cieb < 255.0)
1352 * 'rgb_to_xyz()' - Convert an RGB color to CIE XYZ.
1356 rgb_to_xyz(cups_ib_t *val) /* IO - Color value */
1358 float r, /* Red value */
1359 g, /* Green value */
1361 ciex, /* CIE X value */
1362 ciey, /* CIE Y value */
1363 ciez; /* CIE Z value */
1367 * Convert sRGB to linear RGB...
1370 r = pow((val[0] / 255.0 + 0.055) / 1.055, 2.4);
1371 g = pow((val[1] / 255.0 + 0.055) / 1.055, 2.4);
1372 b = pow((val[2] / 255.0 + 0.055) / 1.055, 2.4);
1375 * Convert to CIE XYZ...
1378 ciex = 0.412453 * r + 0.357580 * g + 0.180423 * b;
1379 ciey = 0.212671 * r + 0.715160 * g + 0.072169 * b;
1380 ciez = 0.019334 * r + 0.119193 * g + 0.950227 * b;
1383 * Encode as 8-bit XYZ...
1388 else if (ciex < 1.1f)
1389 val[0] = (int)(231.8181f * ciex + 0.5);
1395 else if (ciey < 1.1f)
1396 val[1] = (int)(231.8181f * ciey + 0.5);
1402 else if (ciez < 1.1f)
1403 val[2] = (int)(231.8181f * ciez + 0.5);
1410 * 'saturate()' - Make a saturation matrix.
1414 saturate(float mat[3][3], /* I - Matrix to append to */
1415 float sat) /* I - Desired color saturation */
1417 float smat[3][3]; /* Saturation matrix */
1420 smat[0][0] = (1.0 - sat) * 0.3086 + sat;
1421 smat[0][1] = (1.0 - sat) * 0.3086;
1422 smat[0][2] = (1.0 - sat) * 0.3086;
1423 smat[1][0] = (1.0 - sat) * 0.6094;
1424 smat[1][1] = (1.0 - sat) * 0.6094 + sat;
1425 smat[1][2] = (1.0 - sat) * 0.6094;
1426 smat[2][0] = (1.0 - sat) * 0.0820;
1427 smat[2][1] = (1.0 - sat) * 0.0820;
1428 smat[2][2] = (1.0 - sat) * 0.0820 + sat;
1430 mult(smat, mat, mat);
1435 * 'xform()' - Transform a 3D point using a matrix...
1439 xform(float mat[3][3], /* I - Matrix */
1440 float x, /* I - Input X coordinate */
1441 float y, /* I - Input Y coordinate */
1442 float z, /* I - Input Z coordinate */
1443 float *tx, /* O - Output X coordinate */
1444 float *ty, /* O - Output Y coordinate */
1445 float *tz) /* O - Output Z coordinate */
1447 *tx = x * mat[0][0] + y * mat[1][0] + z * mat[2][0];
1448 *ty = x * mat[0][1] + y * mat[1][1] + z * mat[2][1];
1449 *tz = x * mat[0][2] + y * mat[1][2] + z * mat[2][2];
1454 * 'xrotate()' - Rotate about the x (red) axis...
1458 xrotate(float mat[3][3], /* I - Matrix */
1459 float rs, /* I - Rotation angle sine */
1460 float rc) /* I - Rotation angle cosine */
1462 float rmat[3][3]; /* I - Rotation matrix */
1477 mult(rmat, mat, mat);
1482 * 'yrotate()' - Rotate about the y (green) axis...
1486 yrotate(float mat[3][3], /* I - Matrix */
1487 float rs, /* I - Rotation angle sine */
1488 float rc) /* I - Rotation angle cosine */
1490 float rmat[3][3]; /* I - Rotation matrix */
1510 * 'zrotate()' - Rotate about the z (blue) axis...
1514 zrotate(float mat[3][3], /* I - Matrix */
1515 float rs, /* I - Rotation angle sine */
1516 float rc) /* I - Rotation angle cosine */
1518 float rmat[3][3]; /* I - Rotation matrix */
1538 * 'zshear()' - Shear z using x and y...
1542 zshear(float mat[3][3], /* I - Matrix */
1543 float dx, /* I - X shear */
1544 float dy) /* I - Y shear */
1546 float smat[3][3]; /* Shear matrix */
1561 mult(smat, mat, mat);