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