Tizen 2.0 Release
[platform/upstream/cups-filters.git] / cupsfilters / image-colorspace.c
1 /*
2  * "$Id$"
3  *
4  *   Colorspace conversions for CUPS.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
7  *   Copyright 1993-2006 by Easy Software Products.
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
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/".
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
96 typedef int cups_clut_t[3][256];
97
98
99 /*
100  * Local globals...
101  */
102
103 static int              cupsImageHaveProfile = 0;
104                                         /* Do we have a color profile? */
105 static int              *cupsImageDensity;
106                                         /* Ink/marker density LUT */
107 static cups_clut_t      *cupsImageMatrix;
108                                         /* Color transform matrix LUT */
109 static cups_cspace_t    cupsImageColorSpace = CUPS_CSPACE_RGB;
110                                         /* Destination colorspace */
111
112
113 /*
114  * Local functions...
115  */
116
117 static float    cielab(float x, float xn);
118 static void     huerotate(float [3][3], float);
119 static void     ident(float [3][3]);
120 static void     mult(float [3][3], float [3][3], float [3][3]);
121 static void     rgb_to_lab(cups_ib_t *val);
122 static void     rgb_to_xyz(cups_ib_t *val);
123 static void     saturate(float [3][3], float);
124 static void     xform(float [3][3], float, float, float, float *, float *, float *);
125 static void     xrotate(float [3][3], float, float);
126 static void     yrotate(float [3][3], float, float);
127 static void     zrotate(float [3][3], float, float);
128 static void     zshear(float [3][3], float, float);
129
130
131 /*
132  * 'cupsImageCMYKToBlack()' - Convert CMYK data to black.
133  */
134
135 void
136 cupsImageCMYKToBlack(
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
177 void
178 cupsImageCMYKToCMY(
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
264 void
265 cupsImageCMYKToCMYK(
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
336 void
337 cupsImageCMYKToRGB(
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
417       if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
418           cupsImageColorSpace >= CUPS_CSPACE_ICC1)
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
433 void
434 cupsImageCMYKToWhite(
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
479 void
480 cupsImageLut(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
497 void
498 cupsImageRGBAdjust(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 || hue != last_hue || !lut)
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
593 void
594 cupsImageRGBToBlack(
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
620 void
621 cupsImageRGBToCMY(
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
695 void
696 cupsImageRGBToCMYK(
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
785 void
786 cupsImageRGBToRGB(
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
846     if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
847         cupsImageColorSpace >= CUPS_CSPACE_ICC1)
848     {
849       while (count > 0)
850       {
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);
862
863         out += 3;
864         count --;
865       }
866     }
867   }
868 }
869
870
871 /*
872  * 'cupsImageRGBToWhite()' - Convert RGB colors to luminance.
873  */
874
875 void
876 cupsImageRGBToWhite(
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
906 void
907 cupsImageSetProfile(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
952 void
953 cupsImageSetRasterColorSpace(
954     cups_cspace_t cs)                   /* I - Destination colorspace */
955 {
956  /*
957   * Set the destination colorspace...
958   */
959
960   cupsImageColorSpace = cs;
961
962  /*
963   * Don't use color profiles in colorimetric colorspaces...
964   */
965
966   if (cs == CUPS_CSPACE_CIEXYZ ||
967       cs == CUPS_CSPACE_CIELab ||
968       cs >= CUPS_CSPACE_ICC1)
969     cupsImageHaveProfile = 0;
970 }
971
972
973 /*
974  * 'cupsImageWhiteToBlack()' - Convert luminance colors to black.
975  */
976
977 void
978 cupsImageWhiteToBlack(
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
1002 void
1003 cupsImageWhiteToCMY(
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
1032 void
1033 cupsImageWhiteToCMYK(
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
1063 void
1064 cupsImageWhiteToRGB(
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
1088       if (cupsImageColorSpace == CUPS_CSPACE_CIELab ||
1089           cupsImageColorSpace >= CUPS_CSPACE_ICC1)
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
1105 void
1106 cupsImageWhiteToWhite(
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
1126 static float                            /* O - Adjusted color value */
1127 cielab(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
1146 static void
1147 huerotate(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
1219 static void
1220 ident(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
1238 static void
1239 mult(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
1269 static void
1270 rgb_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
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);
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
1320   ciel = ciel * 2.55 + 0.5;
1321   ciea += 128.5;
1322   cieb += 128.5;
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)
1336     val[1] = 0;
1337   else if (ciea < 255.0)
1338     val[1] = (int)ciea;
1339   else
1340     val[1] = 255;
1341
1342   if (cieb < 0.0)
1343     val[2] = 0;
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
1355 static void
1356 rgb_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
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);
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  /*
1383   * Encode as 8-bit XYZ...
1384   */
1385
1386   if (ciex < 0.0f)
1387     val[0] = 0;
1388   else if (ciex < 1.1f)
1389     val[0] = (int)(231.8181f * ciex + 0.5);
1390   else
1391     val[0] = 255;
1392
1393   if (ciey < 0.0f)
1394     val[1] = 0;
1395   else if (ciey < 1.1f)
1396     val[1] = (int)(231.8181f * ciey + 0.5);
1397   else
1398     val[1] = 255;
1399
1400   if (ciez < 0.0f)
1401     val[2] = 0;
1402   else if (ciez < 1.1f)
1403     val[2] = (int)(231.8181f * ciez + 0.5);
1404   else
1405     val[2] = 255;
1406 }
1407
1408
1409 /* 
1410  * 'saturate()' - Make a saturation matrix.
1411  */
1412
1413 static void
1414 saturate(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
1438 static void
1439 xform(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
1457 static void
1458 xrotate(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
1485 static void
1486 yrotate(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
1513 static void
1514 zrotate(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
1541 static void
1542 zshear(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 /*
1566  * End of "$Id$".
1567  */