1 /* Copyright (C) 1995, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gdevht.c,v 1.3.6.1.2.1 2003/01/17 00:49:00 giles Exp $ */
20 /* Halftoning device implementation */
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gxdevice.h"
24 #include "gdevht.h"
25 #include "gxdcolor.h"
26 #include "gxdcconv.h"
27 #include "gxdither.h"
28 
29 /* The device procedures */
30 private dev_proc_open_device(ht_open);
31 private dev_proc_map_rgb_color(ht_map_rgb_color);
32 private dev_proc_map_color_rgb(ht_map_color_rgb);
33 private dev_proc_fill_rectangle(ht_fill_rectangle);
34 private dev_proc_map_cmyk_color(ht_map_cmyk_color);
35 private dev_proc_map_rgb_alpha_color(ht_map_rgb_alpha_color);
36 private dev_proc_fill_path(ht_fill_path);
37 private dev_proc_stroke_path(ht_stroke_path);
38 private dev_proc_fill_mask(ht_fill_mask);
39 private dev_proc_fill_trapezoid(ht_fill_trapezoid);
40 private dev_proc_fill_parallelogram(ht_fill_parallelogram);
41 private dev_proc_fill_triangle(ht_fill_triangle);
42 private dev_proc_draw_thin_line(ht_draw_thin_line);
43 private const gx_device_ht gs_ht_device =
44 {std_device_dci_body(gx_device_ht, 0, "halftoner",
45 		     0, 0, 1, 1,
46 		     1, 8, 255, 0, 0, 0),
47  {ht_open,
48   gx_forward_get_initial_matrix,
49   gx_forward_sync_output,
50   gx_forward_output_page,
51   gx_default_close_device,
52   ht_map_rgb_color,
53   ht_map_color_rgb,
54   ht_fill_rectangle,
55   gx_default_tile_rectangle,
56   gx_default_copy_mono,
57   gx_default_copy_color,
58   gx_default_draw_line,
59   gx_default_get_bits,
60   gx_forward_get_params,
61   gx_forward_put_params,
62   ht_map_cmyk_color,
63   gx_forward_get_xfont_procs,
64   gx_forward_get_xfont_device,
65   ht_map_rgb_alpha_color,
66   gx_forward_get_page_device,
67   gx_forward_get_alpha_bits,
68   gx_default_copy_alpha,
69   gx_forward_get_band,
70   gx_default_copy_rop,
71   ht_fill_path,
72   ht_stroke_path,
73   ht_fill_mask,
74   ht_fill_trapezoid,
75   ht_fill_parallelogram,
76   ht_fill_triangle,
77   ht_draw_thin_line,
78   gx_default_begin_image,
79   gx_default_image_data,
80   gx_default_end_image,
81   gx_default_strip_tile_rectangle,
82   gx_default_strip_copy_rop,
83   gx_forward_get_clipping_box,
84   gx_default_begin_typed_image,
85   gx_no_get_bits_rectangle,
86   gx_default_map_color_rgb_alpha,
87   gx_no_create_compositor,
88   gx_forward_get_hardware_params,
89   gx_default_text_begin,
90   gx_default_finish_copydevice
91  }
92 };
93 
94 /*
95  * Define the packing of two target colors and a halftone level into
96  * a gx_color_index.  Since C doesn't let us cast between a structure
97  * and a scalar, we have to use explicit shifting and masking.
98  */
99 #define cx_color0(color) ((color) & htdev->color_mask)
100 #define cx_color1(color) (((color) >> htdev->color_shift) & htdev->color_mask)
101 #define cx_level(color) ((color) >> htdev->level_shift)
102 #define cx_values(c0, c1, lev)\
103   ( ((lev) << htdev->level_shift) + ((c1) << htdev->color_shift) + (c0) )
104 
105 /* ---------------- Non-drawing procedures ---------------- */
106 
107 /* Open the device.  Right now we just make some error checks. */
108 private int
ht_open(gx_device * dev)109 ht_open(gx_device * dev)
110 {
111     gx_device_ht *htdev = (gx_device_ht *) dev;
112     const gx_device *target = htdev->target;
113     const gx_device_halftone *pdht = htdev->dev_ht;
114     int target_depth;
115     uint num_levels;
116 
117     if (target == 0 || pdht == 0 || pdht->num_comp != 0)
118 	return_error(gs_error_rangecheck);
119     /*
120      * Make sure we can fit a halftone level and two target colors
121      * into a gx_color_index.  If we're lucky, we can pack them into
122      * even less space.
123      */
124     target_depth = target->color_info.depth;
125     num_levels = pdht->order.num_levels;
126     {
127 	int depth = target_depth * 2 + num_levels;
128 
129 	if (depth > sizeof(gx_color_index) * 8)
130 	    return_error(gs_error_rangecheck);
131 	/*
132 	 * If there are too few halftone levels (fewer than 32),
133 	 * we can't treat this device as contone.
134 	 */
135 	if (num_levels < 32)
136 	    return_error(gs_error_rangecheck);
137 	/* Set up color information. */
138 	htdev->color_info.num_components = target->color_info.num_components;
139 	htdev->color_info.depth = depth;
140 	htdev->color_info.max_gray = num_levels - 1;
141 	htdev->color_info.max_color = num_levels - 1;
142 	htdev->color_info.dither_grays = num_levels;
143 	htdev->color_info.dither_colors = num_levels;
144     }
145     htdev->color_shift = target_depth;
146     htdev->level_shift = target_depth * 2;
147     htdev->color_mask = ((gx_color_index) 1 << target_depth) - 1;
148     htdev->phase.x = imod(-htdev->ht_phase.x, pdht->lcm_width);
149     htdev->phase.y = imod(-htdev->ht_phase.y, pdht->lcm_height);
150     return 0;
151 }
152 
153 /* Map from RGB or CMYK colors to the packed representation. */
154 private gx_color_index
ht_finish_map_color(const gx_device_ht * htdev,int code,const gx_device_color * pdevc)155 ht_finish_map_color(const gx_device_ht * htdev, int code,
156 		    const gx_device_color * pdevc)
157 {
158     if (code < 0)
159 	return gx_no_color_index;
160     if (gx_dc_is_pure(pdevc))
161 	return cx_values(pdevc->colors.pure, 0, 0);
162     if (gx_dc_is_binary_halftone(pdevc))
163 	return cx_values(pdevc->colors.binary.color[0],
164 			 pdevc->colors.binary.color[1],
165 			 pdevc->colors.binary.b_level);
166     lprintf("bad type in ht color mapping!");
167     return gx_no_color_index;
168 }
169 private gx_color_index
ht_map_rgb_color(gx_device * dev,gx_color_value r,gx_color_value g,gx_color_value b)170 ht_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
171 		 gx_color_value b)
172 {
173     return ht_map_rgb_alpha_color(dev, r, g, b, gx_max_color_value);
174 }
175 private gx_color_index
ht_map_cmyk_color(gx_device * dev,gx_color_value c,gx_color_value m,gx_color_value y,gx_color_value k)176 ht_map_cmyk_color(gx_device * dev, gx_color_value c, gx_color_value m,
177 		  gx_color_value y, gx_color_value k)
178 {
179     gx_device_ht *htdev = (gx_device_ht *) dev;
180     gx_device_color devc;
181     frac fc = cv2frac(k);
182     frac fk = cv2frac(k);
183     int code =
184     (c == m && m == y ?
185      gx_render_device_gray(color_cmyk_to_gray(fc, fc, fc, fk, NULL),
186 			   gx_max_color_value,
187 			   &devc, htdev->target, htdev->dev_ht,
188 			   &htdev->ht_phase) :
189      gx_render_device_color(fc, cv2frac(m), cv2frac(y),
190 			    fk, false, gx_max_color_value,
191 			    &devc, htdev->target, htdev->dev_ht,
192 			    &htdev->ht_phase));
193 
194     return ht_finish_map_color(htdev, code, &devc);
195 }
196 private gx_color_index
ht_map_rgb_alpha_color(gx_device * dev,gx_color_value r,gx_color_value g,gx_color_value b,gx_color_value alpha)197 ht_map_rgb_alpha_color(gx_device * dev, gx_color_value r,
198 		   gx_color_value g, gx_color_value b, gx_color_value alpha)
199 {
200     gx_device_ht *htdev = (gx_device_ht *) dev;
201     gx_device_color devc;
202     int code =
203     (r == g && g == b ?
204      gx_render_device_gray(cv2frac(r), alpha,
205 			   &devc, htdev->target, htdev->dev_ht,
206 			   &htdev->ht_phase) :
207      gx_render_device_color(cv2frac(r), cv2frac(g), cv2frac(b),
208 			    frac_0, false, alpha,
209 			    &devc, htdev->target, htdev->dev_ht,
210 			    &htdev->ht_phase));
211 
212     return ht_finish_map_color(htdev, code, &devc);
213 }
214 
215 /* Map back to an RGB color. */
216 private int
ht_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])217 ht_map_color_rgb(gx_device * dev, gx_color_index color,
218 		 gx_color_value prgb[3])
219 {
220     gx_device_ht *htdev = (gx_device_ht *) dev;
221     gx_device *tdev = htdev->target;
222     gx_color_index color0 = cx_color0(color);
223     uint level = cx_level(color);
224 
225     dev_proc_map_color_rgb((*map)) = dev_proc(tdev, map_color_rgb);
226 
227     if (level == 0)
228 	return (*map) (tdev, color0, prgb);
229     {
230 	gx_color_index color1 = cx_color1(color);
231 	gx_color_value rgb0[3], rgb1[3];
232 	uint num_levels = htdev->dev_ht->order.num_levels;
233 	int i;
234 
235 	(*map) (tdev, color0, rgb0);
236 	(*map) (tdev, color1, rgb1);
237 	for (i = 0; i < 3; ++i)
238 	    prgb[i] = rgb0[i] +
239 		(rgb1[i] - rgb0[i]) * (ulong) level / num_levels;
240 	return 0;
241     }
242 }
243 
244 /* ---------------- Drawing procedures ---------------- */
245 
246 /*
247  * Map a (pure) contone color into a gx_device_color, either pure or
248  * halftoned.  Return 0 if pure, 1 if halftoned, <0 if the original color
249  * wasn't pure.  (This is not a driver procedure.)
250  */
251 private int
ht_map_device_color(const gx_device_ht * htdev,gx_device_color * pdevc,const gx_device_color * pcdevc)252 ht_map_device_color(const gx_device_ht * htdev, gx_device_color * pdevc,
253 		    const gx_device_color * pcdevc)
254 {
255     if (!gx_dc_is_pure(pcdevc))
256 	return -1;
257     {
258 	gx_color_index color = pcdevc->colors.pure;
259 	gx_color_index color0 = cx_color0(color);
260 	uint level = cx_level(color);
261 
262 	if (level == 0) {
263 	    color_set_pure(pdevc, color0);
264 	    return 0;
265 	} else {
266 	    color_set_binary_halftone(pdevc, htdev->dev_ht, color0,
267 				      cx_color1(color), level);
268 	    color_set_phase(pdevc, htdev->phase.x, htdev->phase.y);
269 	    return 1;
270 	}
271     }
272 }
273 
274 /* Fill a rectangle by tiling with a halftone. */
275 private int
ht_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)276 ht_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
277 		  gx_color_index color)
278 {
279     gx_device_ht *htdev = (gx_device_ht *) dev;
280     gx_device *tdev = htdev->target;
281     gx_color_index color0 = cx_color0(color);
282     uint level = cx_level(color);
283 
284     if (level == 0)
285 	return (*dev_proc(tdev, fill_rectangle))
286 	    (tdev, x, y, w, h, color0);
287     {
288 	const gx_ht_order *porder = &htdev->dev_ht->order;
289 	gx_ht_cache *pcache = porder->cache;
290 	gx_ht_tile *tile;
291 
292 	/* Ensure that the tile cache is current. */
293 	if (pcache->order.bits != porder->bits)
294 	    gx_ht_init_cache(pcache, porder);
295 	/* Ensure that the tile we want is cached. */
296 	tile = gx_render_ht(pcache, level);
297 	if (tile == 0)
298 	    return_error(gs_error_Fatal);
299 	/* Fill the rectangle with the tile. */
300 	return (*dev_proc(tdev, strip_tile_rectangle))
301 	    (tdev, &tile->tiles, x, y, w, h, color0, cx_color1(color),
302 	     htdev->phase.x, htdev->phase.y);
303     }
304 }
305 
306 /*
307  * Create a halftoned color if necessary for the high-level drawing
308  * operations.
309  */
310 
311 #define MAP_DRAWING_COLOR(proc, default_proc)\
312 	gx_device_ht *htdev = (gx_device_ht *)dev;\
313 	gx_device_color dcolor;\
314 	gx_device *tdev;\
315 	const gx_device_color *tdcolor;\
316 \
317 	if ( ht_map_device_color(htdev, &dcolor, pdcolor) < 0 )\
318 	  tdev = dev, tdcolor = pdcolor, proc = default_proc;\
319 	else\
320 	  tdev = htdev->target, tdcolor = &dcolor,\
321 	    proc = dev_proc(tdev, proc)
322 
323 private int
ht_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)324 ht_fill_path(gx_device * dev,
325 	     const gs_imager_state * pis, gx_path * ppath,
326 	     const gx_fill_params * params,
327 	     const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
328 {
329     dev_proc_fill_path((*fill_path));
330     MAP_DRAWING_COLOR(fill_path, gx_default_fill_path);
331     return (*fill_path) (tdev, pis, ppath, params, tdcolor, pcpath);
332 }
333 
334 private int
ht_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)335 ht_stroke_path(gx_device * dev,
336 	       const gs_imager_state * pis, gx_path * ppath,
337 	       const gx_stroke_params * params,
338 	       const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
339 {
340     dev_proc_stroke_path((*stroke_path));
341     MAP_DRAWING_COLOR(stroke_path, gx_default_stroke_path);
342     return (*stroke_path) (tdev, pis, ppath, params, tdcolor, pcpath);
343 }
344 
345 private int
ht_fill_mask(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,const gx_drawing_color * pdcolor,int depth,gs_logical_operation_t lop,const gx_clip_path * pcpath)346 ht_fill_mask(gx_device * dev,
347 	     const byte * data, int data_x, int raster, gx_bitmap_id id,
348 	     int x, int y, int width, int height,
349 	     const gx_drawing_color * pdcolor, int depth,
350 	     gs_logical_operation_t lop, const gx_clip_path * pcpath)
351 {
352     dev_proc_fill_mask((*fill_mask));
353     MAP_DRAWING_COLOR(fill_mask, gx_default_fill_mask);
354     return (*fill_mask) (tdev, data, data_x, raster, id, x, y,
355 			 width, height, tdcolor, depth, lop, pcpath);
356 }
357 
358 private int
ht_fill_trapezoid(gx_device * dev,const gs_fixed_edge * left,const gs_fixed_edge * right,fixed ybot,fixed ytop,bool swap_axes,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)359 ht_fill_trapezoid(gx_device * dev,
360 		  const gs_fixed_edge * left, const gs_fixed_edge * right,
361 		  fixed ybot, fixed ytop, bool swap_axes,
362 	       const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
363 {
364     dev_proc_fill_trapezoid((*fill_trapezoid));
365     MAP_DRAWING_COLOR(fill_trapezoid, gx_default_fill_trapezoid);
366     return (*fill_trapezoid) (tdev, left, right, ybot, ytop, swap_axes,
367 			      tdcolor, lop);
368 }
369 
370 private int
ht_fill_parallelogram(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)371 ht_fill_parallelogram(gx_device * dev,
372 		 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
373 	       const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
374 {
375     dev_proc_fill_parallelogram((*fill_parallelogram));
376     MAP_DRAWING_COLOR(fill_parallelogram, gx_default_fill_parallelogram);
377     return (*fill_parallelogram) (tdev, px, py, ax, ay, bx, by,
378 				  tdcolor, lop);
379 }
380 
381 private int
ht_fill_triangle(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)382 ht_fill_triangle(gx_device * dev,
383 		 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
384 	       const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
385 {
386     dev_proc_fill_triangle((*fill_triangle));
387     MAP_DRAWING_COLOR(fill_triangle, gx_default_fill_triangle);
388     return (*fill_triangle) (tdev, px, py, ax, ay, bx, by,
389 			     tdcolor, lop);
390 }
391 
392 private int
ht_draw_thin_line(gx_device * dev,fixed fx0,fixed fy0,fixed fx1,fixed fy1,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)393 ht_draw_thin_line(gx_device * dev,
394 		  fixed fx0, fixed fy0, fixed fx1, fixed fy1,
395 	       const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
396 {
397     dev_proc_draw_thin_line((*draw_thin_line));
398     MAP_DRAWING_COLOR(draw_thin_line, gx_default_draw_thin_line);
399     return (*draw_thin_line) (tdev, fx0, fy0, fx1, fy1, tdcolor, lop);
400 }
401