xref: /plan9/sys/src/cmd/gs/src/gxdevndi.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 1995, 1996, 1998, 1999 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: gxdevndi.c,v 1.6 2005/05/05 05:35:22 dan Exp $ */
18 #include "gx.h"
19 #include "gsstruct.h"
20 #include "gsdcolor.h"
21 #include "gxdevice.h"
22 #include "gxlum.h"
23 #include "gxcmap.h"
24 #include "gxdither.h"
25 #include "gzht.h"
26 #include "gxfrac.h"
27 #include "gxwts.h"
28 
29 /*
30  * Binary halftoning algorithms.
31  *
32  * The procedures in this file use halftoning (if necessary)
33  * to implement a given device color that has already gone through
34  * the transfer function.  There are two major cases: gray and color.
35  * Gray halftoning always uses a binary screen.  Color halftoning
36  * uses either a fast algorithm with a binary screen that produces
37  * relatively poor approximations, or a very slow algorithm with a
38  * general colored screen (or screens) that faithfully implements
39  * the Adobe specifications.
40  */
41 
42 /* Tables for fast computation of fractional color levels. */
43 /* We have to put the table before any uses of it because of a bug */
44 /* in the VAX C compiler. */
45 /* We have to split up the definition of the table itself because of a bug */
46 /*  in the IBM AIX 3.2 C compiler. */
47 private const gx_color_value q0[] = {
48     0
49 };
50 private const gx_color_value q1[] = {
51     0, frac_color_(1, 1)
52 };
53 private const gx_color_value q2[] = {
54     0, frac_color_(1, 2), frac_color_(2, 2)
55 };
56 private const gx_color_value q3[] = {
57     0, frac_color_(1, 3), frac_color_(2, 3), frac_color_(3, 3)
58 };
59 private const gx_color_value q4[] = {
60     0, frac_color_(1, 4), frac_color_(2, 4), frac_color_(3, 4),
61     frac_color_(4, 4)
62 };
63 private const gx_color_value q5[] = {
64     0, frac_color_(1, 5), frac_color_(2, 5), frac_color_(3, 5),
65     frac_color_(4, 5), frac_color_(5, 5)
66 };
67 private const gx_color_value q6[] = {
68     0, frac_color_(1, 6), frac_color_(2, 6), frac_color_(3, 6),
69     frac_color_(4, 6), frac_color_(5, 6), frac_color_(6, 6)
70 };
71 private const gx_color_value q7[] = {
72     0, frac_color_(1, 7), frac_color_(2, 7), frac_color_(3, 7),
73     frac_color_(4, 7), frac_color_(5, 7), frac_color_(6, 7), frac_color_(7, 7)
74 };
75 
76 /* We export fc_color_quo for the fractional_color macro in gzht.h. */
77 const gx_color_value *const fc_color_quo[8] = {
78     q0, q1, q2, q3, q4, q5, q6, q7
79 };
80 
81 /* Begin code for setting up WTS device color. This should probably
82    move into its own module. */
83 
84 /**
85  * gx_render_device_DevN_wts: Render DeviceN color by halftoning with WTS.
86  *
87  * This routine is the primary constructor for WTS device colors.
88  * Note that, in the WTS code path, we sample the plane_vector array
89  * during device color construction, while in the legacy code path,
90  * it is sampled in the set_ht_colors procedure, invoked from
91  * fill_rectangle. Does it affect correctness? I don't think so, but
92  * it needs to be tested.
93  **/
94 private int
gx_render_device_DeviceN_wts(frac * pcolor,gx_device_color * pdevc,gx_device * dev,gx_device_halftone * pdht,const gs_int_point * ht_phase)95 gx_render_device_DeviceN_wts(frac * pcolor,
96 			     gx_device_color * pdevc, gx_device * dev,
97 			     gx_device_halftone * pdht,
98 			     const gs_int_point * ht_phase)
99 {
100     int i;
101     gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
102     int num_comp = pdht->num_comp;
103 
104     for (i = 0; i < num_comp; i++) {
105 	cv[i] = 0;
106     }
107 
108     pdevc->type = gx_dc_type_wts;
109     pdevc->colors.wts.w_ht = pdht;
110 
111     if (dev->color_info.separable_and_linear != GX_CINFO_SEP_LIN) {
112 	/* Monochrome case may be inverted. */
113 	pdevc->colors.wts.plane_vector[1] =
114 	    dev_proc(dev, encode_color)(dev, cv);
115     }
116     for (i = 0; i < num_comp; i++) {
117 	pdevc->colors.wts.levels[i] = pcolor[i];
118 	cv[i] = gx_max_color_value;
119 	pdevc->colors.wts.plane_vector[i] =
120 	    dev_proc(dev, encode_color)(dev, cv);
121 	cv[i] = 0;
122     }
123     pdevc->colors.wts.num_components = num_comp;
124     return 0;
125 }
126 
127 /*
128  * Render DeviceN possibly by halftoning.
129  *  pcolors = pointer to an array color values (as fracs)
130  *  pdevc - pointer to device color structure
131  *  dev = pointer to device data structure
132  *  pht = pointer to halftone data structure
133  *  ht_phase  = halftone phase
134  *  gray_colorspace = true -> current color space is DeviceGray.
135  *  This is part of a kludge to minimize differences in the
136  *  regression testing.
137  */
138 int
gx_render_device_DeviceN(frac * pcolor,gx_device_color * pdevc,gx_device * dev,gx_device_halftone * pdht,const gs_int_point * ht_phase)139 gx_render_device_DeviceN(frac * pcolor,
140 	gx_device_color * pdevc, gx_device * dev,
141 	gx_device_halftone * pdht, const gs_int_point * ht_phase)
142 {
143     uint max_value[GS_CLIENT_COLOR_MAX_COMPONENTS];
144     frac dither_check = 0;
145     uint int_color[GS_CLIENT_COLOR_MAX_COMPONENTS];
146     gx_color_value vcolor[GS_CLIENT_COLOR_MAX_COMPONENTS];
147     int i;
148     int num_colors = dev->color_info.num_components;
149     uint l_color[GS_CLIENT_COLOR_MAX_COMPONENTS];
150 
151     if (pdht && pdht->components && pdht->components[0].corder.wts)
152 	return gx_render_device_DeviceN_wts(pcolor, pdevc, dev, pdht,
153 					    ht_phase);
154 
155     for (i=0; i<num_colors; i++) {
156 	max_value[i] = (dev->color_info.gray_index == i) ?
157 	     dev->color_info.dither_grays - 1 :
158 	     dev->color_info.dither_colors - 1;
159     }
160 
161     for (i = 0; i < num_colors; i++) {
162 	unsigned long hsize = pdht ?
163 		(unsigned) pdht->components[i].corder.num_levels
164 	    	: 1;
165 	unsigned long nshades = hsize * max_value[i] + 1;
166 	long shade = pcolor[i] * nshades / (frac_1_long + 1);
167 	int_color[i] = shade / hsize;
168 	l_color[i] = shade % hsize;
169 	if (max_value[i] < MIN_CONTONE_LEVELS)
170 	    dither_check |= l_color[i];
171     }
172 
173 #ifdef DEBUG
174     if (gs_debug_c('c')) {
175 	dlprintf1("[c]ncomp=%d ", num_colors);
176 	for (i = 0; i < num_colors; i++)
177 	    dlprintf1("0x%x, ", pcolor[i]);
178 	dlprintf("-->   ");
179 	for (i = 0; i < num_colors; i++)
180 	    dlprintf2("%x+0x%x, ", int_color[i], l_color[i]);
181 	dlprintf("\n");
182     }
183 #endif
184 
185     /* Check for no dithering required */
186     if (!dither_check) {
187 	for (i = 0; i < num_colors; i++)
188 	    vcolor[i] = fractional_color(int_color[i], max_value[i]);
189 	color_set_pure(pdevc, dev_proc(dev, encode_color)(dev, vcolor));
190 	return 0;
191     }
192 
193     /* Use the slow, general colored halftone algorithm. */
194 
195     for (i = 0; i < num_colors; i++)
196         _color_set_c(pdevc, i, int_color[i], l_color[i]);
197     gx_complete_halftone(pdevc, num_colors, pdht);
198 
199     color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
200 			    pdht->lcm_width, pdht->lcm_height);
201 
202     /* Determine if we are using only one component */
203     if (!(pdevc->colors.colored.plane_mask &
204 	 (pdevc->colors.colored.plane_mask - 1))) {
205 	/* We can reduce this color to a binary halftone or pure color. */
206 	return gx_devn_reduce_colored_halftone(pdevc, dev);
207     }
208 
209     return 1;
210 }
211 
212 /* Reduce a colored halftone to a binary halftone or pure color. */
213 /* This routine is called when only one component is being halftoned. */
214 int
gx_devn_reduce_colored_halftone(gx_device_color * pdevc,gx_device * dev)215 gx_devn_reduce_colored_halftone(gx_device_color *pdevc, gx_device *dev)
216 {
217     int planes = pdevc->colors.colored.plane_mask;
218     int num_colors = dev->color_info.num_components;
219     uint max_value[GS_CLIENT_COLOR_MAX_COMPONENTS];
220     uint b[GX_DEVICE_COLOR_MAX_COMPONENTS];
221     gx_color_value v[GX_DEVICE_COLOR_MAX_COMPONENTS];
222     gx_color_index c0, c1;
223     int i;
224 
225     for (i = 0; i < num_colors; i++) {
226 	max_value[i] = (dev->color_info.gray_index == i) ?
227 	     dev->color_info.dither_grays - 1 :
228 	     dev->color_info.dither_colors - 1;
229         b[i] = pdevc->colors.colored.c_base[i];
230         v[i] = fractional_color(b[i], max_value[i]);
231     }
232     c0 = dev_proc(dev, encode_color)(dev, v);
233 
234     if (planes == 0) {
235 	/*
236 	 * Use a pure color.  This case is unlikely, but it can occur if
237 	 * (and only if) the difference of each component from the nearest
238 	 * device color is less than one halftone level.
239 	 */
240 	color_set_pure(pdevc, c0);
241 	return 0;
242     } else {
243 	/* Use a binary color. */
244 	int i = 0;
245 	uint bi;
246 	const gx_device_halftone *pdht = pdevc->colors.colored.c_ht;
247 	/*
248 	 * NB: the halftone orders are all set up for an additive color
249 	 *     space.  To use these work with a subtractive color space, it is
250 	 *     necessary to invert both the color level and the color
251 	 *     pair. Note that if the original color was provided an
252 	 *     additive space, this will reverse (in an approximate sense)
253 	 *     the color conversion performed to express the color in
254 	 *     subtractive space.
255 	 */
256 	bool invert = dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE;
257 	uint level;
258 
259 	/* Convert plane mask bit position to component number */
260 	/* Determine i = log2(planes);  This works for powers of two */
261 	while (planes > 7) {
262 	    i += 3;
263 	    planes >>= 3;
264 	}
265 	i += planes >> 1;  /* log2 for 1,2,4 */
266 
267 	bi = b[i] + 1;
268 	v[i] = fractional_color(bi, max_value[i]);
269 	level = pdevc->colors.colored.c_level[i];
270         c1 = dev_proc(dev, encode_color)(dev, v);
271 	if (invert) {
272 	    level = pdht->components[i].corder.num_levels - level;
273 	    color_set_binary_halftone_component(pdevc, pdht, i, c1, c0, level);
274 	} else
275 	    color_set_binary_halftone_component(pdevc, pdht, i, c0, c1, level);
276 
277 	return 1;
278     }
279 }
280