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