xref: /plan9/sys/src/cmd/gs/src/gxdcconv.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gxdcconv.c,v 1.6 2002/08/22 07:12:29 henrys Exp $ */
18 /* Conversion between device color spaces for Ghostscript */
19 #include "gx.h"
20 #include "gsdcolor.h"		/* for gxcmap.h */
21 #include "gxdcconv.h"		/* interface */
22 #include "gxdevice.h"		/* for gxcmap.h */
23 #include "gxcmap.h"
24 #include "gxfarith.h"
25 #include "gxlum.h"
26 #include "gxistate.h"
27 
28 /*
29  * The CMYK to RGB algorithms specified by Adobe are, e.g.,
30  *      R = 1.0 - min(1.0, C + K)
31  *      C = max(0.0, min(1.0, 1 - R - UCR))
32  * We got better results on displays with
33  *      R = (1.0 - C) * (1.0 - K)
34  *      C = max(0.0, min(1.0, 1 - R / (1 - UCR)))
35  * For utmost compatibility, we offer the Adobe algorithms as an option:
36  */
37 #define USE_ADOBE_CMYK_RGB
38 
39 /* ------ Color space conversion ------ */
40 
41 /* Only 4 of the 6 conversions are implemented here; */
42 /* the other 2 (Gray to RGB/CMYK) are trivial. */
43 
44 /* Convert RGB to Gray. */
45 frac
color_rgb_to_gray(frac r,frac g,frac b,const gs_imager_state * pis)46 color_rgb_to_gray(frac r, frac g, frac b, const gs_imager_state * pis)
47 {
48     return (r * (unsigned long)lum_red_weight +
49 	    g * (unsigned long)lum_green_weight +
50 	    b * (unsigned long)lum_blue_weight +
51 	    (lum_all_weights / 2))
52 	/ lum_all_weights;
53 }
54 
55 /* Convert RGB to CMYK. */
56 /* Note that this involves black generation and undercolor removal. */
57 void
color_rgb_to_cmyk(frac r,frac g,frac b,const gs_imager_state * pis,frac cmyk[4])58 color_rgb_to_cmyk(frac r, frac g, frac b, const gs_imager_state * pis,
59 		  frac cmyk[4])
60 {
61     frac c = frac_1 - r, m = frac_1 - g, y = frac_1 - b;
62     frac k = (c < m ? min(c, y) : min(m, y));
63 
64     /*
65      * The default UCR and BG functions are pretty arbitrary,
66      * but they must agree with the ones in gs_init.ps.
67      */
68     frac bg =
69 	(pis == NULL ? k : pis->black_generation == NULL ? frac_0 :
70 	 gx_map_color_frac(pis, k, black_generation));
71     signed_frac ucr =
72 	(pis == NULL ? k : pis->undercolor_removal == NULL ? frac_0 :
73 	 gx_map_color_frac(pis, k, undercolor_removal));
74 
75     if (ucr == frac_1)
76 	cmyk[0] = cmyk[1] = cmyk[2] = 0;
77     else if (ucr == frac_0)
78 	cmyk[0] = c, cmyk[1] = m, cmyk[2] = y;
79     else {
80 #ifdef USE_ADOBE_CMYK_RGB
81 	/* C = max(0.0, min(1.0, 1 - R - UCR)), etc. */
82 	signed_frac not_ucr = (ucr < 0 ? frac_1 + ucr : frac_1);
83 
84 	cmyk[0] = (c < ucr ? frac_0 : c > not_ucr ? frac_1 : c - ucr);
85 	cmyk[1] = (m < ucr ? frac_0 : m > not_ucr ? frac_1 : m - ucr);
86 	cmyk[2] = (y < ucr ? frac_0 : y > not_ucr ? frac_1 : y - ucr);
87 #else
88 	/* C = max(0.0, min(1.0, 1 - R / (1 - UCR))), etc. */
89 	float denom = frac2float(frac_1 - ucr);		/* unscaled */
90 	float v;
91 
92 	v = (float)frac_1 - r / denom;	/* unscaled */
93 	cmyk[0] =
94 	    (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac) v);
95 	v = (float)frac_1 - g / denom;	/* unscaled */
96 	cmyk[1] =
97 	    (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac) v);
98 	v = (float)frac_1 - b / denom;	/* unscaled */
99 	cmyk[2] =
100 	    (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac) v);
101 #endif
102     }
103     cmyk[3] = bg;
104     if_debug7('c', "[c]RGB 0x%x,0x%x,0x%x -> CMYK 0x%x,0x%x,0x%x,0x%x\n",
105 	      r, g, b, cmyk[0], cmyk[1], cmyk[2], cmyk[3]);
106 }
107 
108 /* Convert CMYK to Gray. */
109 frac
color_cmyk_to_gray(frac c,frac m,frac y,frac k,const gs_imager_state * pis)110 color_cmyk_to_gray(frac c, frac m, frac y, frac k, const gs_imager_state * pis)
111 {
112     frac not_gray = color_rgb_to_gray(c, m, y, pis);
113 
114     return (not_gray > frac_1 - k ?	/* gray + k > 1.0 */
115 	    frac_0 : frac_1 - (not_gray + k));
116 }
117 
118 /* Convert CMYK to RGB. */
119 void
color_cmyk_to_rgb(frac c,frac m,frac y,frac k,const gs_imager_state * pis,frac rgb[3])120 color_cmyk_to_rgb(frac c, frac m, frac y, frac k, const gs_imager_state * pis,
121 		  frac rgb[3])
122 {
123     switch (k) {
124 	case frac_0:
125 	    rgb[0] = frac_1 - c;
126 	    rgb[1] = frac_1 - m;
127 	    rgb[2] = frac_1 - y;
128 	    break;
129 	case frac_1:
130 	    rgb[0] = rgb[1] = rgb[2] = frac_0;
131 	    break;
132 	default:
133 	    {
134 #ifdef USE_ADOBE_CMYK_RGB
135 		/* R = 1.0 - min(1.0, C + K), etc. */
136 		frac not_k = frac_1 - k;
137 
138 		rgb[0] = (c > not_k ? frac_0 : not_k - c);
139 		rgb[1] = (m > not_k ? frac_0 : not_k - m);
140 		rgb[2] = (y > not_k ? frac_0 : not_k - y);
141 #else
142 		/* R = (1.0 - C) * (1.0 - K), etc. */
143 		ulong not_k = frac_1 - k;
144 
145 		/* Compute not_k * (frac_1 - v) / frac_1 efficiently. */
146 		ulong prod;
147 
148 #define deduct_black(v)\
149   (prod = (frac_1 - (v)) * not_k, frac_1_quo(prod))
150 		rgb[0] = deduct_black(c);
151 		rgb[1] = deduct_black(m);
152 		rgb[2] = deduct_black(y);
153 #undef deduct_black
154 #endif
155 	    }
156     }
157     if_debug7('c', "[c]CMYK 0x%x,0x%x,0x%x,0x%x -> RGB 0x%x,0x%x,0x%x\n",
158 	      c, m, y, k, rgb[0], rgb[1], rgb[2]);
159 }
160