2 * "$Id: image-colorspace.c 7720 2008-07-11 22:46:21Z mike $"
4 * Colorspace conversions for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 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
);
1566 * End of "$Id: image-colorspace.c 7720 2008-07-11 22:46:21Z mike $".