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