]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/image-colorspace.c
Load cups into easysw/current.
[thirdparty/cups.git] / filter / image-colorspace.c
1 /*
2 * "$Id: image-colorspace.c 5520 2006-05-12 16:37:36Z mike $"
3 *
4 * Colorspace conversions for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1993-2006 by Easy Software Products.
7 *
8 * The color saturation/hue matrix stuff is provided thanks to Mr. Paul
9 * Haeberli at "http://www.sgi.com/grafica/matrix/index.html".
10 *
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
16 * at:
17 *
18 * Attn: CUPS Licensing Information
19 * Easy Software Products
20 * 44141 Airport View Drive, Suite 204
21 * Hollywood, Maryland 20636 USA
22 *
23 * Voice: (301) 373-9600
24 * EMail: cups-info@cups.org
25 * WWW: http://www.cups.org
26 *
27 * This file is subject to the Apple OS-Developed Software exception.
28 *
29 * Contents:
30 *
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
35 * RGB.
36 * cupsImageCMYKToWhite() - Convert CMYK colors to luminance.
37 * cupsImageLut() - Adjust all pixel values with the given
38 * LUT.
39 * cupsImageRGBAdjust() - Adjust the hue and saturation of the
40 * given RGB colors.
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
45 * RGB.
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...
67 */
68
69 /*
70 * Include necessary headers...
71 */
72
73 #include "image-private.h"
74
75
76 /*
77 * Define some math constants that are required...
78 */
79
80 #ifndef M_PI
81 # define M_PI 3.14159265358979323846
82 #endif /* !M_PI */
83
84 #ifndef M_SQRT2
85 # define M_SQRT2 1.41421356237309504880
86 #endif /* !M_SQRT2 */
87
88 #ifndef M_SQRT1_2
89 # define M_SQRT1_2 0.70710678118654752440
90 #endif /* !M_SQRT1_2 */
91
92 /*
93 * CIE XYZ whitepoint...
94 */
95
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)
99
100
101 /*
102 * Lookup table structure...
103 */
104
105 typedef int cups_clut_t[3][256];
106
107
108 /*
109 * Local globals...
110 */
111
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 */
120
121
122 /*
123 * Local functions...
124 */
125
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);
138
139
140 /*
141 * 'cupsImageCMYKToBlack()' - Convert CMYK data to black.
142 */
143
144 void
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 */
149 {
150 int k; /* Black value */
151
152
153 if (cupsImageHaveProfile)
154 while (count > 0)
155 {
156 k = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 + in[3];
157
158 if (k < 255)
159 *out++ = cupsImageDensity[k];
160 else
161 *out++ = cupsImageDensity[255];
162
163 in += 4;
164 count --;
165 }
166 else
167 while (count > 0)
168 {
169 k = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 + in[3];
170
171 if (k < 255)
172 *out++ = k;
173 else
174 *out++ = 255;
175
176 in += 4;
177 count --;
178 }
179 }
180
181
182 /*
183 * 'cupsImageCMYKToCMY()' - Convert CMYK colors to CMY.
184 */
185
186 void
187 cupsImageCMYKToCMY(
188 const cups_ib_t *in, /* I - Input pixels */
189 cups_ib_t *out, /* I - Output pixels */
190 int count) /* I - Number of pixels */
191 {
192 int c, m, y, k; /* CMYK values */
193 int cc, cm, cy; /* Calibrated CMY values */
194
195
196 if (cupsImageHaveProfile)
197 while (count > 0)
198 {
199 c = *in++;
200 m = *in++;
201 y = *in++;
202 k = *in++;
203
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;
213
214 if (cc < 0)
215 *out++ = 0;
216 else if (cc > 255)
217 *out++ = cupsImageDensity[255];
218 else
219 *out++ = cupsImageDensity[cc];
220
221 if (cm < 0)
222 *out++ = 0;
223 else if (cm > 255)
224 *out++ = cupsImageDensity[255];
225 else
226 *out++ = cupsImageDensity[cm];
227
228 if (cy < 0)
229 *out++ = 0;
230 else if (cy > 255)
231 *out++ = cupsImageDensity[255];
232 else
233 *out++ = cupsImageDensity[cy];
234
235 count --;
236 }
237 else
238 while (count > 0)
239 {
240 c = *in++;
241 m = *in++;
242 y = *in++;
243 k = *in++;
244
245 c += k;
246 m += k;
247 y += k;
248
249 if (c < 255)
250 *out++ = c;
251 else
252 *out++ = 255;
253
254 if (m < 255)
255 *out++ = y;
256 else
257 *out++ = 255;
258
259 if (y < 255)
260 *out++ = y;
261 else
262 *out++ = 255;
263
264 count --;
265 }
266 }
267
268
269 /*
270 * 'cupsImageCMYKToCMYK()' - Convert CMYK colors to CMYK.
271 */
272
273 void
274 cupsImageCMYKToCMYK(
275 const cups_ib_t *in, /* I - Input pixels */
276 cups_ib_t *out, /* I - Output pixels */
277 int count) /* I - Number of pixels */
278 {
279 int c, m, y, k; /* CMYK values */
280 int cc, cm, cy; /* Calibrated CMY values */
281
282
283 if (cupsImageHaveProfile)
284 while (count > 0)
285 {
286 c = *in++;
287 m = *in++;
288 y = *in++;
289 k = *in++;
290
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]);
300
301 if (cc < 0)
302 *out++ = 0;
303 else if (cc > 255)
304 *out++ = cupsImageDensity[255];
305 else
306 *out++ = cupsImageDensity[cc];
307
308 if (cm < 0)
309 *out++ = 0;
310 else if (cm > 255)
311 *out++ = cupsImageDensity[255];
312 else
313 *out++ = cupsImageDensity[cm];
314
315 if (cy < 0)
316 *out++ = 0;
317 else if (cy > 255)
318 *out++ = cupsImageDensity[255];
319 else
320 *out++ = cupsImageDensity[cy];
321
322 *out++ = cupsImageDensity[k];
323
324 count --;
325 }
326 else if (in != out)
327 {
328 while (count > 0)
329 {
330 *out++ = *in++;
331 *out++ = *in++;
332 *out++ = *in++;
333 *out++ = *in++;
334
335 count --;
336 }
337 }
338 }
339
340
341 /*
342 * 'cupsImageCMYKToRGB()' - Convert CMYK colors to device-dependent RGB.
343 */
344
345 void
346 cupsImageCMYKToRGB(
347 const cups_ib_t *in, /* I - Input pixels */
348 cups_ib_t *out, /* I - Output pixels */
349 int count) /* I - Number of pixels */
350 {
351 int c, m, y, k; /* CMYK values */
352 int cr, cg, cb; /* Calibrated RGB values */
353
354
355 if (cupsImageHaveProfile)
356 {
357 while (count > 0)
358 {
359 c = *in++;
360 m = *in++;
361 y = *in++;
362 k = *in++;
363
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;
373
374 if (cr < 0)
375 *out++ = 255;
376 else if (cr > 255)
377 *out++ = 255 - cupsImageDensity[255];
378 else
379 *out++ = 255 - cupsImageDensity[cr];
380
381 if (cg < 0)
382 *out++ = 255;
383 else if (cg > 255)
384 *out++ = 255 - cupsImageDensity[255];
385 else
386 *out++ = 255 - cupsImageDensity[cg];
387
388 if (cb < 0)
389 *out++ = 255;
390 else if (cb > 255)
391 *out++ = 255 - cupsImageDensity[255];
392 else
393 *out++ = 255 - cupsImageDensity[cb];
394
395 count --;
396 }
397 }
398 else
399 {
400 while (count > 0)
401 {
402 c = 255 - *in++;
403 m = 255 - *in++;
404 y = 255 - *in++;
405 k = *in++;
406
407 c -= k;
408 m -= k;
409 y -= k;
410
411 if (c > 0)
412 *out++ = c;
413 else
414 *out++ = 0;
415
416 if (m > 0)
417 *out++ = m;
418 else
419 *out++ = 0;
420
421 if (y > 0)
422 *out++ = y;
423 else
424 *out++ = 0;
425
426 if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
427 cupsImageColorSpace >= CUPS_CSPACE_ICC1)
428 rgb_to_lab(out - 3);
429 else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
430 rgb_to_xyz(out - 3);
431
432 count --;
433 }
434 }
435 }
436
437
438 /*
439 * 'cupsImageCMYKToWhite()' - Convert CMYK colors to luminance.
440 */
441
442 void
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 */
447 {
448 int w; /* White value */
449
450
451 if (cupsImageHaveProfile)
452 {
453 while (count > 0)
454 {
455 w = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 - in[3];
456
457 if (w > 0)
458 *out++ = cupsImageDensity[w];
459 else
460 *out++ = cupsImageDensity[0];
461
462 in += 4;
463 count --;
464 }
465 }
466 else
467 {
468 while (count > 0)
469 {
470 w = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 - in[3];
471
472 if (w > 0)
473 *out++ = w;
474 else
475 *out++ = 0;
476
477 in += 4;
478 count --;
479 }
480 }
481 }
482
483
484 /*
485 * 'cupsImageLut()' - Adjust all pixel values with the given LUT.
486 */
487
488 void
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 */
492 {
493 while (count > 0)
494 {
495 *pixels = lut[*pixels];
496 pixels ++;
497 count --;
498 }
499 }
500
501
502 /*
503 * 'cupsImageRGBAdjust()' - Adjust the hue and saturation of the given RGB colors.
504 */
505
506 void
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) */
511 {
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 */
517
518
519 if (saturation != last_sat ||
520 hue != last_hue)
521 {
522 /*
523 * Build the color adjustment matrix...
524 */
525
526 ident(mat);
527 saturate(mat, saturation * 0.01);
528 huerotate(mat, (float)hue);
529
530 /*
531 * Allocate memory for the lookup table...
532 */
533
534 if (lut == NULL)
535 lut = calloc(3, sizeof(cups_clut_t));
536
537 if (lut == NULL)
538 return;
539
540 /*
541 * Convert the matrix into a 3x3 array of lookup tables...
542 */
543
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;
548
549 /*
550 * Save the saturation and hue to compare later...
551 */
552
553 last_sat = saturation;
554 last_hue = hue;
555 }
556
557 /*
558 * Adjust each pixel in the given buffer.
559 */
560
561 while (count > 0)
562 {
563 i = lut[0][0][pixels[0]] +
564 lut[1][0][pixels[1]] +
565 lut[2][0][pixels[2]];
566 if (i < 0)
567 pixels[0] = 0;
568 else if (i > 255)
569 pixels[0] = 255;
570 else
571 pixels[0] = i;
572
573 i = lut[0][1][pixels[0]] +
574 lut[1][1][pixels[1]] +
575 lut[2][1][pixels[2]];
576 if (i < 0)
577 pixels[1] = 0;
578 else if (i > 255)
579 pixels[1] = 255;
580 else
581 pixels[1] = i;
582
583 i = lut[0][2][pixels[0]] +
584 lut[1][2][pixels[1]] +
585 lut[2][2][pixels[2]];
586 if (i < 0)
587 pixels[2] = 0;
588 else if (i > 255)
589 pixels[2] = 255;
590 else
591 pixels[2] = i;
592
593 count --;
594 pixels += 3;
595 }
596 }
597
598
599 /*
600 * 'cupsImageRGBToBlack()' - Convert RGB data to black.
601 */
602
603 void
604 cupsImageRGBToBlack(
605 const cups_ib_t *in, /* I - Input pixels */
606 cups_ib_t *out, /* I - Output pixels */
607 int count) /* I - Number of pixels */
608 {
609 if (cupsImageHaveProfile)
610 while (count > 0)
611 {
612 *out++ = cupsImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100];
613 in += 3;
614 count --;
615 }
616 else
617 while (count > 0)
618 {
619 *out++ = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100;
620 in += 3;
621 count --;
622 }
623 }
624
625
626 /*
627 * 'cupsImageRGBToCMY()' - Convert RGB colors to CMY.
628 */
629
630 void
631 cupsImageRGBToCMY(
632 const cups_ib_t *in, /* I - Input pixels */
633 cups_ib_t *out, /* I - Output pixels */
634 int count) /* I - Number of pixels */
635 {
636 int c, m, y, k; /* CMYK values */
637 int cc, cm, cy; /* Calibrated CMY values */
638
639
640 if (cupsImageHaveProfile)
641 while (count > 0)
642 {
643 c = 255 - *in++;
644 m = 255 - *in++;
645 y = 255 - *in++;
646 k = min(c, min(m, y));
647 c -= k;
648 m -= k;
649 y -= k;
650
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;
660
661 if (cc < 0)
662 *out++ = 0;
663 else if (cc > 255)
664 *out++ = cupsImageDensity[255];
665 else
666 *out++ = cupsImageDensity[cc];
667
668 if (cm < 0)
669 *out++ = 0;
670 else if (cm > 255)
671 *out++ = cupsImageDensity[255];
672 else
673 *out++ = cupsImageDensity[cm];
674
675 if (cy < 0)
676 *out++ = 0;
677 else if (cy > 255)
678 *out++ = cupsImageDensity[255];
679 else
680 *out++ = cupsImageDensity[cy];
681
682 count --;
683 }
684 else
685 while (count > 0)
686 {
687 c = 255 - in[0];
688 m = 255 - in[1];
689 y = 255 - in[2];
690 k = min(c, min(m, y));
691
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;
695 in += 3;
696 count --;
697 }
698 }
699
700
701 /*
702 * 'cupsImageRGBToCMYK()' - Convert RGB colors to CMYK.
703 */
704
705 void
706 cupsImageRGBToCMYK(
707 const cups_ib_t *in, /* I - Input pixels */
708 cups_ib_t *out, /* I - Output pixels */
709 int count) /* I - Number of pixels */
710 {
711 int c, m, y, k, /* CMYK values */
712 km; /* Maximum K value */
713 int cc, cm, cy; /* Calibrated CMY values */
714
715
716 if (cupsImageHaveProfile)
717 while (count > 0)
718 {
719 c = 255 - *in++;
720 m = 255 - *in++;
721 y = 255 - *in++;
722 k = min(c, min(m, y));
723
724 if ((km = max(c, max(m, y))) > k)
725 k = k * k * k / (km * km);
726
727 c -= k;
728 m -= k;
729 y -= k;
730
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]);
740
741 if (cc < 0)
742 *out++ = 0;
743 else if (cc > 255)
744 *out++ = cupsImageDensity[255];
745 else
746 *out++ = cupsImageDensity[cc];
747
748 if (cm < 0)
749 *out++ = 0;
750 else if (cm > 255)
751 *out++ = cupsImageDensity[255];
752 else
753 *out++ = cupsImageDensity[cm];
754
755 if (cy < 0)
756 *out++ = 0;
757 else if (cy > 255)
758 *out++ = cupsImageDensity[255];
759 else
760 *out++ = cupsImageDensity[cy];
761
762 *out++ = cupsImageDensity[k];
763
764 count --;
765 }
766 else
767 while (count > 0)
768 {
769 c = 255 - *in++;
770 m = 255 - *in++;
771 y = 255 - *in++;
772 k = min(c, min(m, y));
773
774 if ((km = max(c, max(m, y))) > k)
775 k = k * k * k / (km * km);
776
777 c -= k;
778 m -= k;
779 y -= k;
780
781 *out++ = c;
782 *out++ = m;
783 *out++ = y;
784 *out++ = k;
785
786 count --;
787 }
788 }
789
790
791 /*
792 * 'cupsImageRGBToRGB()' - Convert RGB colors to device-dependent RGB.
793 */
794
795 void
796 cupsImageRGBToRGB(
797 const cups_ib_t *in, /* I - Input pixels */
798 cups_ib_t *out, /* I - Output pixels */
799 int count) /* I - Number of pixels */
800 {
801 int c, m, y, k; /* CMYK values */
802 int cr, cg, cb; /* Calibrated RGB values */
803
804
805 if (cupsImageHaveProfile)
806 {
807 while (count > 0)
808 {
809 c = 255 - *in++;
810 m = 255 - *in++;
811 y = 255 - *in++;
812 k = min(c, min(m, y));
813 c -= k;
814 m -= k;
815 y -= k;
816
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;
826
827 if (cr < 0)
828 *out++ = 255;
829 else if (cr > 255)
830 *out++ = 255 - cupsImageDensity[255];
831 else
832 *out++ = 255 - cupsImageDensity[cr];
833
834 if (cg < 0)
835 *out++ = 255;
836 else if (cg > 255)
837 *out++ = 255 - cupsImageDensity[255];
838 else
839 *out++ = 255 - cupsImageDensity[cg];
840
841 if (cb < 0)
842 *out++ = 255;
843 else if (cb > 255)
844 *out++ = 255 - cupsImageDensity[255];
845 else
846 *out++ = 255 - cupsImageDensity[cb];
847
848 count --;
849 }
850 }
851 else
852 {
853 if (in != out)
854 memcpy(out, in, count * 3);
855
856 if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
857 cupsImageColorSpace >= CUPS_CSPACE_ICC1)
858 {
859 while (count > 0)
860 {
861 rgb_to_lab(out);
862
863 out += 3;
864 count --;
865 }
866 }
867 else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
868 {
869 while (count > 0)
870 {
871 rgb_to_xyz(out);
872
873 out += 3;
874 count --;
875 }
876 }
877 }
878 }
879
880
881 /*
882 * 'cupsImageRGBToWhite()' - Convert RGB colors to luminance.
883 */
884
885 void
886 cupsImageRGBToWhite(
887 const cups_ib_t *in, /* I - Input pixels */
888 cups_ib_t *out, /* I - Output pixels */
889 int count) /* I - Number of pixels */
890 {
891 if (cupsImageHaveProfile)
892 {
893 while (count > 0)
894 {
895 *out++ = 255 - cupsImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100];
896 in += 3;
897 count --;
898 }
899 }
900 else
901 {
902 while (count > 0)
903 {
904 *out++ = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100;
905 in += 3;
906 count --;
907 }
908 }
909 }
910
911
912 /*
913 * 'cupsImageSetProfile()' - Set the device color profile.
914 */
915
916 void
917 cupsImageSetProfile(float d, /* I - Ink/marker density */
918 float g, /* I - Ink/marker gamma */
919 float matrix[3][3]) /* I - Color transform matrix */
920 {
921 int i, j, k; /* Looping vars */
922 float m; /* Current matrix value */
923 int *im; /* Pointer into cupsImageMatrix */
924
925
926 /*
927 * Allocate memory for the profile data...
928 */
929
930 if (cupsImageMatrix == NULL)
931 cupsImageMatrix = calloc(3, sizeof(cups_clut_t));
932
933 if (cupsImageMatrix == NULL)
934 return;
935
936 if (cupsImageDensity == NULL)
937 cupsImageDensity = calloc(256, sizeof(int));
938
939 if (cupsImageDensity == NULL)
940 return;
941
942 /*
943 * Populate the profile lookup tables...
944 */
945
946 cupsImageHaveProfile = 1;
947
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);
952
953 for (k = 0, im = cupsImageDensity; k < 256; k ++)
954 *im++ = 255.0 * d * pow((float)k / 255.0, g) + 0.5;
955 }
956
957
958 /*
959 * 'cupsImageSetRasterColorSpace()' - Set the destination colorspace.
960 */
961
962 void
963 cupsImageSetRasterColorSpace(
964 cups_cspace_t cs) /* I - Destination colorspace */
965 {
966 /*
967 * Set the destination colorspace...
968 */
969
970 cupsImageColorSpace = cs;
971
972 /*
973 * Don't use color profiles in colorimetric colorspaces...
974 */
975
976 if (cs == CUPS_CSPACE_CIEXYZ ||
977 cs == CUPS_CSPACE_CIELab ||
978 cs >= CUPS_CSPACE_ICC1)
979 cupsImageHaveProfile = 0;
980 }
981
982
983 /*
984 * 'cupsImageWhiteToBlack()' - Convert luminance colors to black.
985 */
986
987 void
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 */
992 {
993 if (cupsImageHaveProfile)
994 while (count > 0)
995 {
996 *out++ = cupsImageDensity[255 - *in++];
997 count --;
998 }
999 else
1000 while (count > 0)
1001 {
1002 *out++ = 255 - *in++;
1003 count --;
1004 }
1005 }
1006
1007
1008 /*
1009 * 'cupsImageWhiteToCMY()' - Convert luminance colors to CMY.
1010 */
1011
1012 void
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 */
1017 {
1018 if (cupsImageHaveProfile)
1019 while (count > 0)
1020 {
1021 out[0] = cupsImageDensity[255 - *in++];
1022 out[1] = out[0];
1023 out[2] = out[0];
1024 out += 3;
1025 count --;
1026 }
1027 else
1028 while (count > 0)
1029 {
1030 *out++ = 255 - *in;
1031 *out++ = 255 - *in;
1032 *out++ = 255 - *in++;
1033 count --;
1034 }
1035 }
1036
1037
1038 /*
1039 * 'cupsImageWhiteToCMYK()' - Convert luminance colors to CMYK.
1040 */
1041
1042 void
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 */
1047 {
1048 if (cupsImageHaveProfile)
1049 while (count > 0)
1050 {
1051 *out++ = 0;
1052 *out++ = 0;
1053 *out++ = 0;
1054 *out++ = cupsImageDensity[255 - *in++];
1055 count --;
1056 }
1057 else
1058 while (count > 0)
1059 {
1060 *out++ = 0;
1061 *out++ = 0;
1062 *out++ = 0;
1063 *out++ = 255 - *in++;
1064 count --;
1065 }
1066 }
1067
1068
1069 /*
1070 * 'cupsImageWhiteToRGB()' - Convert luminance data to RGB.
1071 */
1072
1073 void
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 */
1078 {
1079 if (cupsImageHaveProfile)
1080 {
1081 while (count > 0)
1082 {
1083 out[0] = 255 - cupsImageDensity[255 - *in++];
1084 out[1] = out[0];
1085 out[2] = out[0];
1086 out += 3;
1087 count --;
1088 }
1089 }
1090 else
1091 {
1092 while (count > 0)
1093 {
1094 *out++ = *in;
1095 *out++ = *in;
1096 *out++ = *in++;
1097
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);
1103
1104 count --;
1105 }
1106 }
1107 }
1108
1109
1110 /*
1111 * 'cupsImageWhiteToWhite()' - Convert luminance colors to device-dependent
1112 * luminance.
1113 */
1114
1115 void
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 */
1120 {
1121 if (cupsImageHaveProfile)
1122 while (count > 0)
1123 {
1124 *out++ = 255 - cupsImageDensity[255 - *in++];
1125 count --;
1126 }
1127 else if (in != out)
1128 memcpy(out, in, count);
1129 }
1130
1131
1132 /*
1133 * 'cielab()' - Map CIE Lab transformation...
1134 */
1135
1136 static float /* O - Adjusted color value */
1137 cielab(float x, /* I - Raw color value */
1138 float xn) /* I - Whitepoint color value */
1139 {
1140 float x_xn; /* Fraction of whitepoint */
1141
1142
1143 x_xn = x / xn;
1144
1145 if (x_xn > 0.008856)
1146 return (cbrt(x_xn));
1147 else
1148 return (7.787 * x_xn + 16.0 / 116.0);
1149 }
1150
1151
1152 /*
1153 * 'huerotate()' - Rotate the hue, maintaining luminance.
1154 */
1155
1156 static void
1157 huerotate(float mat[3][3], /* I - Matrix to append to */
1158 float rot) /* I - Hue rotation in degrees */
1159 {
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 */
1166
1167
1168 /*
1169 * Load the identity matrix...
1170 */
1171
1172 ident(hmat);
1173
1174 /*
1175 * Rotate the grey vector into positive Z...
1176 */
1177
1178 xrs = M_SQRT1_2;
1179 xrc = M_SQRT1_2;
1180 xrotate(hmat,xrs,xrc);
1181
1182 yrs = -1.0 / sqrt(3.0);
1183 yrc = -M_SQRT2 * yrs;
1184 yrotate(hmat,yrs,yrc);
1185
1186 /*
1187 * Shear the space to make the luminance plane horizontal...
1188 */
1189
1190 xform(hmat, 0.3086, 0.6094, 0.0820, &lx, &ly, &lz);
1191 zsx = lx / lz;
1192 zsy = ly / lz;
1193 zshear(hmat, zsx, zsy);
1194
1195 /*
1196 * Rotate the hue...
1197 */
1198
1199 zrs = sin(rot * M_PI / 180.0);
1200 zrc = cos(rot * M_PI / 180.0);
1201
1202 zrotate(hmat, zrs, zrc);
1203
1204 /*
1205 * Unshear the space to put the luminance plane back...
1206 */
1207
1208 zshear(hmat, -zsx, -zsy);
1209
1210 /*
1211 * Rotate the grey vector back into place...
1212 */
1213
1214 yrotate(hmat, -yrs, yrc);
1215 xrotate(hmat, -xrs, xrc);
1216
1217 /*
1218 * Append it to the current matrix...
1219 */
1220
1221 mult(hmat, mat, mat);
1222 }
1223
1224
1225 /*
1226 * 'ident()' - Make an identity matrix.
1227 */
1228
1229 static void
1230 ident(float mat[3][3]) /* I - Matrix to identify */
1231 {
1232 mat[0][0] = 1.0;
1233 mat[0][1] = 0.0;
1234 mat[0][2] = 0.0;
1235 mat[1][0] = 0.0;
1236 mat[1][1] = 1.0;
1237 mat[1][2] = 0.0;
1238 mat[2][0] = 0.0;
1239 mat[2][1] = 0.0;
1240 mat[2][2] = 1.0;
1241 }
1242
1243
1244 /*
1245 * 'mult()' - Multiply two matrices.
1246 */
1247
1248 static void
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 */
1252 {
1253 int x, y; /* Looping vars */
1254 float temp[3][3]; /* Temporary matrix */
1255
1256
1257 /*
1258 * Multiply a and b, putting the result in temp...
1259 */
1260
1261 for (y = 0; y < 3; y ++)
1262 for (x = 0; x < 3; x ++)
1263 temp[y][x] = b[y][0] * a[0][x] +
1264 b[y][1] * a[1][x] +
1265 b[y][2] * a[2][x];
1266
1267 /*
1268 * Copy temp to c (that way c can be a pointer to a or b).
1269 */
1270
1271 memcpy(c, temp, sizeof(temp));
1272 }
1273
1274
1275 /*
1276 * 'rgb_to_lab()' - Convert an RGB color to CIE Lab.
1277 */
1278
1279 static void
1280 rgb_to_lab(cups_ib_t *val) /* IO - Color value */
1281 {
1282 float r, /* Red value */
1283 g, /* Green value */
1284 b, /* Blue 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 */
1292
1293
1294 /*
1295 * Convert sRGB to linear RGB...
1296 */
1297
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);
1301
1302 /*
1303 * Convert to CIE XYZ...
1304 */
1305
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;
1309
1310 /*
1311 * Normalize and convert to CIE Lab...
1312 */
1313
1314 ciey_yn = ciey / D65_Y;
1315
1316 if (ciey_yn > 0.008856)
1317 ciel = 116 * cbrt(ciey_yn) - 16;
1318 else
1319 ciel = 903.3 * ciey_yn;
1320
1321 ciel = ciel;
1322 ciea = 500 * (cielab(ciex, D65_X) - cielab(ciey, D65_Y));
1323 cieb = 200 * (cielab(ciey, D65_Y) - cielab(ciez, D65_Z));
1324
1325 /*
1326 * Scale the L value and bias the a and b values by 128 so that all
1327 * numbers are from 0 to 255.
1328 */
1329
1330 ciel = ciel * 2.55 + 0.5;
1331 ciea += 128.5;
1332 cieb += 128.5;
1333
1334 /*
1335 * Output 8-bit values...
1336 */
1337
1338 if (ciel < 0.0)
1339 val[0] = 0;
1340 else if (ciel < 255.0)
1341 val[0] = (int)ciel;
1342 else
1343 val[0] = 255;
1344
1345 if (ciea < 0.0)
1346 val[1] = 0;
1347 else if (ciea < 255.0)
1348 val[1] = (int)ciea;
1349 else
1350 val[1] = 255;
1351
1352 if (cieb < 0.0)
1353 val[2] = 0;
1354 else if (cieb < 255.0)
1355 val[2] = (int)cieb;
1356 else
1357 val[2] = 255;
1358 }
1359
1360
1361 /*
1362 * 'rgb_to_xyz()' - Convert an RGB color to CIE XYZ.
1363 */
1364
1365 static void
1366 rgb_to_xyz(cups_ib_t *val) /* IO - Color value */
1367 {
1368 float r, /* Red value */
1369 g, /* Green value */
1370 b, /* Blue value */
1371 ciex, /* CIE X value */
1372 ciey, /* CIE Y value */
1373 ciez; /* CIE Z value */
1374
1375
1376 /*
1377 * Convert sRGB to linear RGB...
1378 */
1379
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);
1383
1384 /*
1385 * Convert to CIE XYZ...
1386 */
1387
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;
1391
1392 /*
1393 * Encode as 8-bit XYZ...
1394 */
1395
1396 if (ciex < 0.0f)
1397 val[0] = 0;
1398 else if (ciex < 1.1f)
1399 val[0] = (int)(231.8181f * ciex + 0.5);
1400 else
1401 val[0] = 255;
1402
1403 if (ciey < 0.0f)
1404 val[1] = 0;
1405 else if (ciey < 1.1f)
1406 val[1] = (int)(231.8181f * ciey + 0.5);
1407 else
1408 val[1] = 255;
1409
1410 if (ciez < 0.0f)
1411 val[2] = 0;
1412 else if (ciez < 1.1f)
1413 val[2] = (int)(231.8181f * ciez + 0.5);
1414 else
1415 val[2] = 255;
1416 }
1417
1418
1419 /*
1420 * 'saturate()' - Make a saturation matrix.
1421 */
1422
1423 static void
1424 saturate(float mat[3][3], /* I - Matrix to append to */
1425 float sat) /* I - Desired color saturation */
1426 {
1427 float smat[3][3]; /* Saturation matrix */
1428
1429
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;
1439
1440 mult(smat, mat, mat);
1441 }
1442
1443
1444 /*
1445 * 'xform()' - Transform a 3D point using a matrix...
1446 */
1447
1448 static void
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 */
1456 {
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];
1460 }
1461
1462
1463 /*
1464 * 'xrotate()' - Rotate about the x (red) axis...
1465 */
1466
1467 static void
1468 xrotate(float mat[3][3], /* I - Matrix */
1469 float rs, /* I - Rotation angle sine */
1470 float rc) /* I - Rotation angle cosine */
1471 {
1472 float rmat[3][3]; /* I - Rotation matrix */
1473
1474
1475 rmat[0][0] = 1.0;
1476 rmat[0][1] = 0.0;
1477 rmat[0][2] = 0.0;
1478
1479 rmat[1][0] = 0.0;
1480 rmat[1][1] = rc;
1481 rmat[1][2] = rs;
1482
1483 rmat[2][0] = 0.0;
1484 rmat[2][1] = -rs;
1485 rmat[2][2] = rc;
1486
1487 mult(rmat, mat, mat);
1488 }
1489
1490
1491 /*
1492 * 'yrotate()' - Rotate about the y (green) axis...
1493 */
1494
1495 static void
1496 yrotate(float mat[3][3], /* I - Matrix */
1497 float rs, /* I - Rotation angle sine */
1498 float rc) /* I - Rotation angle cosine */
1499 {
1500 float rmat[3][3]; /* I - Rotation matrix */
1501
1502
1503 rmat[0][0] = rc;
1504 rmat[0][1] = 0.0;
1505 rmat[0][2] = -rs;
1506
1507 rmat[1][0] = 0.0;
1508 rmat[1][1] = 1.0;
1509 rmat[1][2] = 0.0;
1510
1511 rmat[2][0] = rs;
1512 rmat[2][1] = 0.0;
1513 rmat[2][2] = rc;
1514
1515 mult(rmat,mat,mat);
1516 }
1517
1518
1519 /*
1520 * 'zrotate()' - Rotate about the z (blue) axis...
1521 */
1522
1523 static void
1524 zrotate(float mat[3][3], /* I - Matrix */
1525 float rs, /* I - Rotation angle sine */
1526 float rc) /* I - Rotation angle cosine */
1527 {
1528 float rmat[3][3]; /* I - Rotation matrix */
1529
1530
1531 rmat[0][0] = rc;
1532 rmat[0][1] = rs;
1533 rmat[0][2] = 0.0;
1534
1535 rmat[1][0] = -rs;
1536 rmat[1][1] = rc;
1537 rmat[1][2] = 0.0;
1538
1539 rmat[2][0] = 0.0;
1540 rmat[2][1] = 0.0;
1541 rmat[2][2] = 1.0;
1542
1543 mult(rmat,mat,mat);
1544 }
1545
1546
1547 /*
1548 * 'zshear()' - Shear z using x and y...
1549 */
1550
1551 static void
1552 zshear(float mat[3][3], /* I - Matrix */
1553 float dx, /* I - X shear */
1554 float dy) /* I - Y shear */
1555 {
1556 float smat[3][3]; /* Shear matrix */
1557
1558
1559 smat[0][0] = 1.0;
1560 smat[0][1] = 0.0;
1561 smat[0][2] = dx;
1562
1563 smat[1][0] = 0.0;
1564 smat[1][1] = 1.0;
1565 smat[1][2] = dy;
1566
1567 smat[2][0] = 0.0;
1568 smat[2][1] = 0.0;
1569 smat[2][2] = 1.0;
1570
1571 mult(smat, mat, mat);
1572 }
1573
1574
1575 /*
1576 * End of "$Id: image-colorspace.c 5520 2006-05-12 16:37:36Z mike $".
1577 */