]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/image-colorspace.c
Merge changes from CUPS 1.4svn-r7961.
[thirdparty/cups.git] / filter / image-colorspace.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: image-colorspace.c 7720 2008-07-11 22:46:21Z mike $"
ef416fc2 3 *
4 * Colorspace conversions for the Common UNIX Printing System (CUPS).
5 *
1f0275e3 6 * Copyright 2007-2008 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
1f0275e3 510 if (saturation != last_sat || hue != last_hue || !lut)
ef416fc2 511 {
512 /*
513 * Build the color adjustment matrix...
514 */
515
516 ident(mat);
517 saturate(mat, saturation * 0.01);
518 huerotate(mat, (float)hue);
519
520 /*
521 * Allocate memory for the lookup table...
522 */
523
524 if (lut == NULL)
525 lut = calloc(3, sizeof(cups_clut_t));
526
527 if (lut == NULL)
528 return;
529
530 /*
531 * Convert the matrix into a 3x3 array of lookup tables...
532 */
533
534 for (i = 0; i < 3; i ++)
535 for (j = 0; j < 3; j ++)
536 for (k = 0; k < 256; k ++)
537 lut[i][j][k] = mat[i][j] * k + 0.5;
538
539 /*
540 * Save the saturation and hue to compare later...
541 */
542
543 last_sat = saturation;
544 last_hue = hue;
545 }
546
547 /*
548 * Adjust each pixel in the given buffer.
549 */
550
551 while (count > 0)
552 {
553 i = lut[0][0][pixels[0]] +
554 lut[1][0][pixels[1]] +
555 lut[2][0][pixels[2]];
556 if (i < 0)
557 pixels[0] = 0;
558 else if (i > 255)
559 pixels[0] = 255;
560 else
561 pixels[0] = i;
562
563 i = lut[0][1][pixels[0]] +
564 lut[1][1][pixels[1]] +
565 lut[2][1][pixels[2]];
566 if (i < 0)
567 pixels[1] = 0;
568 else if (i > 255)
569 pixels[1] = 255;
570 else
571 pixels[1] = i;
572
573 i = lut[0][2][pixels[0]] +
574 lut[1][2][pixels[1]] +
575 lut[2][2][pixels[2]];
576 if (i < 0)
577 pixels[2] = 0;
578 else if (i > 255)
579 pixels[2] = 255;
580 else
581 pixels[2] = i;
582
583 count --;
584 pixels += 3;
585 }
586}
587
588
589/*
590 * 'cupsImageRGBToBlack()' - Convert RGB data to black.
591 */
592
593void
594cupsImageRGBToBlack(
595 const cups_ib_t *in, /* I - Input pixels */
596 cups_ib_t *out, /* I - Output pixels */
597 int count) /* I - Number of pixels */
598{
599 if (cupsImageHaveProfile)
600 while (count > 0)
601 {
602 *out++ = cupsImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100];
603 in += 3;
604 count --;
605 }
606 else
607 while (count > 0)
608 {
609 *out++ = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100;
610 in += 3;
611 count --;
612 }
613}
614
615
616/*
617 * 'cupsImageRGBToCMY()' - Convert RGB colors to CMY.
618 */
619
620void
621cupsImageRGBToCMY(
622 const cups_ib_t *in, /* I - Input pixels */
623 cups_ib_t *out, /* I - Output pixels */
624 int count) /* I - Number of pixels */
625{
626 int c, m, y, k; /* CMYK values */
627 int cc, cm, cy; /* Calibrated CMY values */
628
629
630 if (cupsImageHaveProfile)
631 while (count > 0)
632 {
633 c = 255 - *in++;
634 m = 255 - *in++;
635 y = 255 - *in++;
636 k = min(c, min(m, y));
637 c -= k;
638 m -= k;
639 y -= k;
640
641 cc = cupsImageMatrix[0][0][c] +
642 cupsImageMatrix[0][1][m] +
643 cupsImageMatrix[0][2][y] + k;
644 cm = cupsImageMatrix[1][0][c] +
645 cupsImageMatrix[1][1][m] +
646 cupsImageMatrix[1][2][y] + k;
647 cy = cupsImageMatrix[2][0][c] +
648 cupsImageMatrix[2][1][m] +
649 cupsImageMatrix[2][2][y] + k;
650
651 if (cc < 0)
652 *out++ = 0;
653 else if (cc > 255)
654 *out++ = cupsImageDensity[255];
655 else
656 *out++ = cupsImageDensity[cc];
657
658 if (cm < 0)
659 *out++ = 0;
660 else if (cm > 255)
661 *out++ = cupsImageDensity[255];
662 else
663 *out++ = cupsImageDensity[cm];
664
665 if (cy < 0)
666 *out++ = 0;
667 else if (cy > 255)
668 *out++ = cupsImageDensity[255];
669 else
670 *out++ = cupsImageDensity[cy];
671
672 count --;
673 }
674 else
675 while (count > 0)
676 {
677 c = 255 - in[0];
678 m = 255 - in[1];
679 y = 255 - in[2];
680 k = min(c, min(m, y));
681
682 *out++ = (255 - in[1] / 4) * (c - k) / 255 + k;
683 *out++ = (255 - in[2] / 4) * (m - k) / 255 + k;
684 *out++ = (255 - in[0] / 4) * (y - k) / 255 + k;
685 in += 3;
686 count --;
687 }
688}
689
690
691/*
692 * 'cupsImageRGBToCMYK()' - Convert RGB colors to CMYK.
693 */
694
695void
696cupsImageRGBToCMYK(
697 const cups_ib_t *in, /* I - Input pixels */
698 cups_ib_t *out, /* I - Output pixels */
699 int count) /* I - Number of pixels */
700{
701 int c, m, y, k, /* CMYK values */
702 km; /* Maximum K value */
703 int cc, cm, cy; /* Calibrated CMY values */
704
705
706 if (cupsImageHaveProfile)
707 while (count > 0)
708 {
709 c = 255 - *in++;
710 m = 255 - *in++;
711 y = 255 - *in++;
712 k = min(c, min(m, y));
713
714 if ((km = max(c, max(m, y))) > k)
715 k = k * k * k / (km * km);
716
717 c -= k;
718 m -= k;
719 y -= k;
720
721 cc = (cupsImageMatrix[0][0][c] +
722 cupsImageMatrix[0][1][m] +
723 cupsImageMatrix[0][2][y]);
724 cm = (cupsImageMatrix[1][0][c] +
725 cupsImageMatrix[1][1][m] +
726 cupsImageMatrix[1][2][y]);
727 cy = (cupsImageMatrix[2][0][c] +
728 cupsImageMatrix[2][1][m] +
729 cupsImageMatrix[2][2][y]);
730
731 if (cc < 0)
732 *out++ = 0;
733 else if (cc > 255)
734 *out++ = cupsImageDensity[255];
735 else
736 *out++ = cupsImageDensity[cc];
737
738 if (cm < 0)
739 *out++ = 0;
740 else if (cm > 255)
741 *out++ = cupsImageDensity[255];
742 else
743 *out++ = cupsImageDensity[cm];
744
745 if (cy < 0)
746 *out++ = 0;
747 else if (cy > 255)
748 *out++ = cupsImageDensity[255];
749 else
750 *out++ = cupsImageDensity[cy];
751
752 *out++ = cupsImageDensity[k];
753
754 count --;
755 }
756 else
757 while (count > 0)
758 {
759 c = 255 - *in++;
760 m = 255 - *in++;
761 y = 255 - *in++;
762 k = min(c, min(m, y));
763
764 if ((km = max(c, max(m, y))) > k)
765 k = k * k * k / (km * km);
766
767 c -= k;
768 m -= k;
769 y -= k;
770
771 *out++ = c;
772 *out++ = m;
773 *out++ = y;
774 *out++ = k;
775
776 count --;
777 }
778}
779
780
781/*
782 * 'cupsImageRGBToRGB()' - Convert RGB colors to device-dependent RGB.
783 */
784
785void
786cupsImageRGBToRGB(
787 const cups_ib_t *in, /* I - Input pixels */
788 cups_ib_t *out, /* I - Output pixels */
789 int count) /* I - Number of pixels */
790{
791 int c, m, y, k; /* CMYK values */
792 int cr, cg, cb; /* Calibrated RGB values */
793
794
795 if (cupsImageHaveProfile)
796 {
797 while (count > 0)
798 {
799 c = 255 - *in++;
800 m = 255 - *in++;
801 y = 255 - *in++;
802 k = min(c, min(m, y));
803 c -= k;
804 m -= k;
805 y -= k;
806
807 cr = cupsImageMatrix[0][0][c] +
808 cupsImageMatrix[0][1][m] +
809 cupsImageMatrix[0][2][y] + k;
810 cg = cupsImageMatrix[1][0][c] +
811 cupsImageMatrix[1][1][m] +
812 cupsImageMatrix[1][2][y] + k;
813 cb = cupsImageMatrix[2][0][c] +
814 cupsImageMatrix[2][1][m] +
815 cupsImageMatrix[2][2][y] + k;
816
817 if (cr < 0)
818 *out++ = 255;
819 else if (cr > 255)
820 *out++ = 255 - cupsImageDensity[255];
821 else
822 *out++ = 255 - cupsImageDensity[cr];
823
824 if (cg < 0)
825 *out++ = 255;
826 else if (cg > 255)
827 *out++ = 255 - cupsImageDensity[255];
828 else
829 *out++ = 255 - cupsImageDensity[cg];
830
831 if (cb < 0)
832 *out++ = 255;
833 else if (cb > 255)
834 *out++ = 255 - cupsImageDensity[255];
835 else
836 *out++ = 255 - cupsImageDensity[cb];
837
838 count --;
839 }
840 }
841 else
842 {
843 if (in != out)
844 memcpy(out, in, count * 3);
845
f301802f 846 if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
847 cupsImageColorSpace >= CUPS_CSPACE_ICC1)
ef416fc2 848 {
849 while (count > 0)
850 {
f301802f 851 rgb_to_lab(out);
852
853 out += 3;
854 count --;
855 }
856 }
857 else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
858 {
859 while (count > 0)
860 {
861 rgb_to_xyz(out);
ef416fc2 862
863 out += 3;
864 count --;
865 }
866 }
867 }
868}
869
870
871/*
872 * 'cupsImageRGBToWhite()' - Convert RGB colors to luminance.
873 */
874
875void
876cupsImageRGBToWhite(
877 const cups_ib_t *in, /* I - Input pixels */
878 cups_ib_t *out, /* I - Output pixels */
879 int count) /* I - Number of pixels */
880{
881 if (cupsImageHaveProfile)
882 {
883 while (count > 0)
884 {
885 *out++ = 255 - cupsImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100];
886 in += 3;
887 count --;
888 }
889 }
890 else
891 {
892 while (count > 0)
893 {
894 *out++ = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100;
895 in += 3;
896 count --;
897 }
898 }
899}
900
901
902/*
903 * 'cupsImageSetProfile()' - Set the device color profile.
904 */
905
906void
907cupsImageSetProfile(float d, /* I - Ink/marker density */
908 float g, /* I - Ink/marker gamma */
909 float matrix[3][3]) /* I - Color transform matrix */
910{
911 int i, j, k; /* Looping vars */
912 float m; /* Current matrix value */
913 int *im; /* Pointer into cupsImageMatrix */
914
915
916 /*
917 * Allocate memory for the profile data...
918 */
919
920 if (cupsImageMatrix == NULL)
921 cupsImageMatrix = calloc(3, sizeof(cups_clut_t));
922
923 if (cupsImageMatrix == NULL)
924 return;
925
926 if (cupsImageDensity == NULL)
927 cupsImageDensity = calloc(256, sizeof(int));
928
929 if (cupsImageDensity == NULL)
930 return;
931
932 /*
933 * Populate the profile lookup tables...
934 */
935
936 cupsImageHaveProfile = 1;
937
938 for (i = 0, im = cupsImageMatrix[0][0]; i < 3; i ++)
939 for (j = 0; j < 3; j ++)
940 for (k = 0, m = matrix[i][j]; k < 256; k ++)
941 *im++ = (int)(k * m + 0.5);
942
943 for (k = 0, im = cupsImageDensity; k < 256; k ++)
944 *im++ = 255.0 * d * pow((float)k / 255.0, g) + 0.5;
945}
946
947
948/*
949 * 'cupsImageSetRasterColorSpace()' - Set the destination colorspace.
950 */
951
952void
953cupsImageSetRasterColorSpace(
954 cups_cspace_t cs) /* I - Destination colorspace */
955{
956 /*
957 * Set the destination colorspace...
958 */
959
f301802f 960 cupsImageColorSpace = cs;
ef416fc2 961
962 /*
963 * Don't use color profiles in colorimetric colorspaces...
964 */
965
f301802f 966 if (cs == CUPS_CSPACE_CIEXYZ ||
967 cs == CUPS_CSPACE_CIELab ||
968 cs >= CUPS_CSPACE_ICC1)
ef416fc2 969 cupsImageHaveProfile = 0;
970}
971
972
973/*
974 * 'cupsImageWhiteToBlack()' - Convert luminance colors to black.
975 */
976
977void
978cupsImageWhiteToBlack(
979 const cups_ib_t *in, /* I - Input pixels */
980 cups_ib_t *out, /* I - Output pixels */
981 int count) /* I - Number of pixels */
982{
983 if (cupsImageHaveProfile)
984 while (count > 0)
985 {
986 *out++ = cupsImageDensity[255 - *in++];
987 count --;
988 }
989 else
990 while (count > 0)
991 {
992 *out++ = 255 - *in++;
993 count --;
994 }
995}
996
997
998/*
999 * 'cupsImageWhiteToCMY()' - Convert luminance colors to CMY.
1000 */
1001
1002void
1003cupsImageWhiteToCMY(
1004 const cups_ib_t *in, /* I - Input pixels */
1005 cups_ib_t *out, /* I - Output pixels */
1006 int count) /* I - Number of pixels */
1007{
1008 if (cupsImageHaveProfile)
1009 while (count > 0)
1010 {
1011 out[0] = cupsImageDensity[255 - *in++];
1012 out[1] = out[0];
1013 out[2] = out[0];
1014 out += 3;
1015 count --;
1016 }
1017 else
1018 while (count > 0)
1019 {
1020 *out++ = 255 - *in;
1021 *out++ = 255 - *in;
1022 *out++ = 255 - *in++;
1023 count --;
1024 }
1025}
1026
1027
1028/*
1029 * 'cupsImageWhiteToCMYK()' - Convert luminance colors to CMYK.
1030 */
1031
1032void
1033cupsImageWhiteToCMYK(
1034 const cups_ib_t *in, /* I - Input pixels */
1035 cups_ib_t *out, /* I - Output pixels */
1036 int count) /* I - Number of pixels */
1037{
1038 if (cupsImageHaveProfile)
1039 while (count > 0)
1040 {
1041 *out++ = 0;
1042 *out++ = 0;
1043 *out++ = 0;
1044 *out++ = cupsImageDensity[255 - *in++];
1045 count --;
1046 }
1047 else
1048 while (count > 0)
1049 {
1050 *out++ = 0;
1051 *out++ = 0;
1052 *out++ = 0;
1053 *out++ = 255 - *in++;
1054 count --;
1055 }
1056}
1057
1058
1059/*
1060 * 'cupsImageWhiteToRGB()' - Convert luminance data to RGB.
1061 */
1062
1063void
1064cupsImageWhiteToRGB(
1065 const cups_ib_t *in, /* I - Input pixels */
1066 cups_ib_t *out, /* I - Output pixels */
1067 int count) /* I - Number of pixels */
1068{
1069 if (cupsImageHaveProfile)
1070 {
1071 while (count > 0)
1072 {
1073 out[0] = 255 - cupsImageDensity[255 - *in++];
1074 out[1] = out[0];
1075 out[2] = out[0];
1076 out += 3;
1077 count --;
1078 }
1079 }
1080 else
1081 {
1082 while (count > 0)
1083 {
1084 *out++ = *in;
1085 *out++ = *in;
1086 *out++ = *in++;
1087
f301802f 1088 if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
1089 cupsImageColorSpace >= CUPS_CSPACE_ICC1)
ef416fc2 1090 rgb_to_lab(out - 3);
1091 else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ)
1092 rgb_to_xyz(out - 3);
1093
1094 count --;
1095 }
1096 }
1097}
1098
1099
1100/*
1101 * 'cupsImageWhiteToWhite()' - Convert luminance colors to device-dependent
1102 * luminance.
1103 */
1104
1105void
1106cupsImageWhiteToWhite(
1107 const cups_ib_t *in, /* I - Input pixels */
1108 cups_ib_t *out, /* I - Output pixels */
1109 int count) /* I - Number of pixels */
1110{
1111 if (cupsImageHaveProfile)
1112 while (count > 0)
1113 {
1114 *out++ = 255 - cupsImageDensity[255 - *in++];
1115 count --;
1116 }
1117 else if (in != out)
1118 memcpy(out, in, count);
1119}
1120
1121
1122/*
1123 * 'cielab()' - Map CIE Lab transformation...
1124 */
1125
1126static float /* O - Adjusted color value */
1127cielab(float x, /* I - Raw color value */
1128 float xn) /* I - Whitepoint color value */
1129{
1130 float x_xn; /* Fraction of whitepoint */
1131
1132
1133 x_xn = x / xn;
1134
1135 if (x_xn > 0.008856)
1136 return (cbrt(x_xn));
1137 else
1138 return (7.787 * x_xn + 16.0 / 116.0);
1139}
1140
1141
1142/*
1143 * 'huerotate()' - Rotate the hue, maintaining luminance.
1144 */
1145
1146static void
1147huerotate(float mat[3][3], /* I - Matrix to append to */
1148 float rot) /* I - Hue rotation in degrees */
1149{
1150 float hmat[3][3]; /* Hue matrix */
1151 float lx, ly, lz; /* Luminance vector */
1152 float xrs, xrc; /* X rotation sine/cosine */
1153 float yrs, yrc; /* Y rotation sine/cosine */
1154 float zrs, zrc; /* Z rotation sine/cosine */
1155 float zsx, zsy; /* Z shear x/y */
1156
1157
1158 /*
1159 * Load the identity matrix...
1160 */
1161
1162 ident(hmat);
1163
1164 /*
1165 * Rotate the grey vector into positive Z...
1166 */
1167
1168 xrs = M_SQRT1_2;
1169 xrc = M_SQRT1_2;
1170 xrotate(hmat,xrs,xrc);
1171
1172 yrs = -1.0 / sqrt(3.0);
1173 yrc = -M_SQRT2 * yrs;
1174 yrotate(hmat,yrs,yrc);
1175
1176 /*
1177 * Shear the space to make the luminance plane horizontal...
1178 */
1179
1180 xform(hmat, 0.3086, 0.6094, 0.0820, &lx, &ly, &lz);
1181 zsx = lx / lz;
1182 zsy = ly / lz;
1183 zshear(hmat, zsx, zsy);
1184
1185 /*
1186 * Rotate the hue...
1187 */
1188
1189 zrs = sin(rot * M_PI / 180.0);
1190 zrc = cos(rot * M_PI / 180.0);
1191
1192 zrotate(hmat, zrs, zrc);
1193
1194 /*
1195 * Unshear the space to put the luminance plane back...
1196 */
1197
1198 zshear(hmat, -zsx, -zsy);
1199
1200 /*
1201 * Rotate the grey vector back into place...
1202 */
1203
1204 yrotate(hmat, -yrs, yrc);
1205 xrotate(hmat, -xrs, xrc);
1206
1207 /*
1208 * Append it to the current matrix...
1209 */
1210
1211 mult(hmat, mat, mat);
1212}
1213
1214
1215/*
1216 * 'ident()' - Make an identity matrix.
1217 */
1218
1219static void
1220ident(float mat[3][3]) /* I - Matrix to identify */
1221{
1222 mat[0][0] = 1.0;
1223 mat[0][1] = 0.0;
1224 mat[0][2] = 0.0;
1225 mat[1][0] = 0.0;
1226 mat[1][1] = 1.0;
1227 mat[1][2] = 0.0;
1228 mat[2][0] = 0.0;
1229 mat[2][1] = 0.0;
1230 mat[2][2] = 1.0;
1231}
1232
1233
1234/*
1235 * 'mult()' - Multiply two matrices.
1236 */
1237
1238static void
1239mult(float a[3][3], /* I - First matrix */
1240 float b[3][3], /* I - Second matrix */
1241 float c[3][3]) /* I - Destination matrix */
1242{
1243 int x, y; /* Looping vars */
1244 float temp[3][3]; /* Temporary matrix */
1245
1246
1247 /*
1248 * Multiply a and b, putting the result in temp...
1249 */
1250
1251 for (y = 0; y < 3; y ++)
1252 for (x = 0; x < 3; x ++)
1253 temp[y][x] = b[y][0] * a[0][x] +
1254 b[y][1] * a[1][x] +
1255 b[y][2] * a[2][x];
1256
1257 /*
1258 * Copy temp to c (that way c can be a pointer to a or b).
1259 */
1260
1261 memcpy(c, temp, sizeof(temp));
1262}
1263
1264
1265/*
1266 * 'rgb_to_lab()' - Convert an RGB color to CIE Lab.
1267 */
1268
1269static void
1270rgb_to_lab(cups_ib_t *val) /* IO - Color value */
1271{
1272 float r, /* Red value */
1273 g, /* Green value */
1274 b, /* Blue value */
1275 ciex, /* CIE X value */
1276 ciey, /* CIE Y value */
1277 ciez, /* CIE Z value */
1278 ciey_yn, /* Normalized luminance */
1279 ciel, /* CIE L value */
1280 ciea, /* CIE a value */
1281 cieb; /* CIE b value */
1282
1283
1284 /*
1285 * Convert sRGB to linear RGB...
1286 */
1287
f301802f 1288 r = pow((val[0] / 255.0 + 0.055) / 1.055, 2.4);
1289 g = pow((val[1] / 255.0 + 0.055) / 1.055, 2.4);
1290 b = pow((val[2] / 255.0 + 0.055) / 1.055, 2.4);
ef416fc2 1291
1292 /*
1293 * Convert to CIE XYZ...
1294 */
1295
1296 ciex = 0.412453 * r + 0.357580 * g + 0.180423 * b;
1297 ciey = 0.212671 * r + 0.715160 * g + 0.072169 * b;
1298 ciez = 0.019334 * r + 0.119193 * g + 0.950227 * b;
1299
1300 /*
1301 * Normalize and convert to CIE Lab...
1302 */
1303
1304 ciey_yn = ciey / D65_Y;
1305
1306 if (ciey_yn > 0.008856)
1307 ciel = 116 * cbrt(ciey_yn) - 16;
1308 else
1309 ciel = 903.3 * ciey_yn;
1310
1311 ciel = ciel;
1312 ciea = 500 * (cielab(ciex, D65_X) - cielab(ciey, D65_Y));
1313 cieb = 200 * (cielab(ciey, D65_Y) - cielab(ciez, D65_Z));
1314
1315 /*
1316 * Scale the L value and bias the a and b values by 128 so that all
1317 * numbers are from 0 to 255.
1318 */
1319
f301802f 1320 ciel = ciel * 2.55 + 0.5;
1321 ciea += 128.5;
1322 cieb += 128.5;
ef416fc2 1323
1324 /*
1325 * Output 8-bit values...
1326 */
1327
1328 if (ciel < 0.0)
1329 val[0] = 0;
1330 else if (ciel < 255.0)
1331 val[0] = (int)ciel;
1332 else
1333 val[0] = 255;
1334
1335 if (ciea < 0.0)
f301802f 1336 val[1] = 0;
ef416fc2 1337 else if (ciea < 255.0)
1338 val[1] = (int)ciea;
1339 else
1340 val[1] = 255;
1341
1342 if (cieb < 0.0)
f301802f 1343 val[2] = 0;
ef416fc2 1344 else if (cieb < 255.0)
1345 val[2] = (int)cieb;
1346 else
1347 val[2] = 255;
1348}
1349
1350
1351/*
1352 * 'rgb_to_xyz()' - Convert an RGB color to CIE XYZ.
1353 */
1354
1355static void
1356rgb_to_xyz(cups_ib_t *val) /* IO - Color value */
1357{
1358 float r, /* Red value */
1359 g, /* Green value */
1360 b, /* Blue value */
1361 ciex, /* CIE X value */
1362 ciey, /* CIE Y value */
1363 ciez; /* CIE Z value */
1364
1365
1366 /*
1367 * Convert sRGB to linear RGB...
1368 */
1369
f301802f 1370 r = pow((val[0] / 255.0 + 0.055) / 1.055, 2.4);
1371 g = pow((val[1] / 255.0 + 0.055) / 1.055, 2.4);
1372 b = pow((val[2] / 255.0 + 0.055) / 1.055, 2.4);
ef416fc2 1373
1374 /*
1375 * Convert to CIE XYZ...
1376 */
1377
1378 ciex = 0.412453 * r + 0.357580 * g + 0.180423 * b;
1379 ciey = 0.212671 * r + 0.715160 * g + 0.072169 * b;
1380 ciez = 0.019334 * r + 0.119193 * g + 0.950227 * b;
1381
1382 /*
f301802f 1383 * Encode as 8-bit XYZ...
ef416fc2 1384 */
1385
f301802f 1386 if (ciex < 0.0f)
ef416fc2 1387 val[0] = 0;
f301802f 1388 else if (ciex < 1.1f)
1389 val[0] = (int)(231.8181f * ciex + 0.5);
ef416fc2 1390 else
1391 val[0] = 255;
1392
f301802f 1393 if (ciey < 0.0f)
ef416fc2 1394 val[1] = 0;
f301802f 1395 else if (ciey < 1.1f)
1396 val[1] = (int)(231.8181f * ciey + 0.5);
ef416fc2 1397 else
1398 val[1] = 255;
1399
f301802f 1400 if (ciez < 0.0f)
ef416fc2 1401 val[2] = 0;
f301802f 1402 else if (ciez < 1.1f)
1403 val[2] = (int)(231.8181f * ciez + 0.5);
ef416fc2 1404 else
1405 val[2] = 255;
1406}
1407
1408
1409/*
1410 * 'saturate()' - Make a saturation matrix.
1411 */
1412
1413static void
1414saturate(float mat[3][3], /* I - Matrix to append to */
1415 float sat) /* I - Desired color saturation */
1416{
1417 float smat[3][3]; /* Saturation matrix */
1418
1419
1420 smat[0][0] = (1.0 - sat) * 0.3086 + sat;
1421 smat[0][1] = (1.0 - sat) * 0.3086;
1422 smat[0][2] = (1.0 - sat) * 0.3086;
1423 smat[1][0] = (1.0 - sat) * 0.6094;
1424 smat[1][1] = (1.0 - sat) * 0.6094 + sat;
1425 smat[1][2] = (1.0 - sat) * 0.6094;
1426 smat[2][0] = (1.0 - sat) * 0.0820;
1427 smat[2][1] = (1.0 - sat) * 0.0820;
1428 smat[2][2] = (1.0 - sat) * 0.0820 + sat;
1429
1430 mult(smat, mat, mat);
1431}
1432
1433
1434/*
1435 * 'xform()' - Transform a 3D point using a matrix...
1436 */
1437
1438static void
1439xform(float mat[3][3], /* I - Matrix */
1440 float x, /* I - Input X coordinate */
1441 float y, /* I - Input Y coordinate */
1442 float z, /* I - Input Z coordinate */
1443 float *tx, /* O - Output X coordinate */
1444 float *ty, /* O - Output Y coordinate */
1445 float *tz) /* O - Output Z coordinate */
1446{
1447 *tx = x * mat[0][0] + y * mat[1][0] + z * mat[2][0];
1448 *ty = x * mat[0][1] + y * mat[1][1] + z * mat[2][1];
1449 *tz = x * mat[0][2] + y * mat[1][2] + z * mat[2][2];
1450}
1451
1452
1453/*
1454 * 'xrotate()' - Rotate about the x (red) axis...
1455 */
1456
1457static void
1458xrotate(float mat[3][3], /* I - Matrix */
1459 float rs, /* I - Rotation angle sine */
1460 float rc) /* I - Rotation angle cosine */
1461{
1462 float rmat[3][3]; /* I - Rotation matrix */
1463
1464
1465 rmat[0][0] = 1.0;
1466 rmat[0][1] = 0.0;
1467 rmat[0][2] = 0.0;
1468
1469 rmat[1][0] = 0.0;
1470 rmat[1][1] = rc;
1471 rmat[1][2] = rs;
1472
1473 rmat[2][0] = 0.0;
1474 rmat[2][1] = -rs;
1475 rmat[2][2] = rc;
1476
1477 mult(rmat, mat, mat);
1478}
1479
1480
1481/*
1482 * 'yrotate()' - Rotate about the y (green) axis...
1483 */
1484
1485static void
1486yrotate(float mat[3][3], /* I - Matrix */
1487 float rs, /* I - Rotation angle sine */
1488 float rc) /* I - Rotation angle cosine */
1489{
1490 float rmat[3][3]; /* I - Rotation matrix */
1491
1492
1493 rmat[0][0] = rc;
1494 rmat[0][1] = 0.0;
1495 rmat[0][2] = -rs;
1496
1497 rmat[1][0] = 0.0;
1498 rmat[1][1] = 1.0;
1499 rmat[1][2] = 0.0;
1500
1501 rmat[2][0] = rs;
1502 rmat[2][1] = 0.0;
1503 rmat[2][2] = rc;
1504
1505 mult(rmat,mat,mat);
1506}
1507
1508
1509/*
1510 * 'zrotate()' - Rotate about the z (blue) axis...
1511 */
1512
1513static void
1514zrotate(float mat[3][3], /* I - Matrix */
1515 float rs, /* I - Rotation angle sine */
1516 float rc) /* I - Rotation angle cosine */
1517{
1518 float rmat[3][3]; /* I - Rotation matrix */
1519
1520
1521 rmat[0][0] = rc;
1522 rmat[0][1] = rs;
1523 rmat[0][2] = 0.0;
1524
1525 rmat[1][0] = -rs;
1526 rmat[1][1] = rc;
1527 rmat[1][2] = 0.0;
1528
1529 rmat[2][0] = 0.0;
1530 rmat[2][1] = 0.0;
1531 rmat[2][2] = 1.0;
1532
1533 mult(rmat,mat,mat);
1534}
1535
1536
1537/*
1538 * 'zshear()' - Shear z using x and y...
1539 */
1540
1541static void
1542zshear(float mat[3][3], /* I - Matrix */
1543 float dx, /* I - X shear */
1544 float dy) /* I - Y shear */
1545{
1546 float smat[3][3]; /* Shear matrix */
1547
1548
1549 smat[0][0] = 1.0;
1550 smat[0][1] = 0.0;
1551 smat[0][2] = dx;
1552
1553 smat[1][0] = 0.0;
1554 smat[1][1] = 1.0;
1555 smat[1][2] = dy;
1556
1557 smat[2][0] = 0.0;
1558 smat[2][1] = 0.0;
1559 smat[2][2] = 1.0;
1560
1561 mult(smat, mat, mat);
1562}
1563
1564
1565/*
b19ccc9e 1566 * End of "$Id: image-colorspace.c 7720 2008-07-11 22:46:21Z mike $".
ef416fc2 1567 */