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