1 /* Copyright (C) 1991, 1995, 1996, 1997, 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: gdevbit.c,v 1.10 2004/06/23 18:57:15 stefan Exp $ */
18 /* "Plain bits" devices to measure rendering time. */
19 #include "math_.h"
20 #include "gdevprn.h"
21 #include "gsparam.h"
22 #include "gscrd.h"
23 #include "gscrdp.h"
24 #include "gxlum.h"
25 #include "gdevdcrd.h"
26
27 /* Define the device parameters. */
28 #ifndef X_DPI
29 # define X_DPI 72
30 #endif
31 #ifndef Y_DPI
32 # define Y_DPI 72
33 #endif
34
35 /* The device descriptor */
36 private dev_proc_map_rgb_color(bit_mono_map_color);
37 private dev_proc_map_color_rgb(bit_map_color_rgb);
38 private dev_proc_map_cmyk_color(bit_map_cmyk_color);
39 private dev_proc_get_params(bit_get_params);
40 private dev_proc_put_params(bit_put_params);
41 private dev_proc_print_page(bit_print_page);
42
43 #define bit_procs(encode_color)\
44 { gdev_prn_open,\
45 gx_default_get_initial_matrix,\
46 NULL, /* sync_output */\
47 gdev_prn_output_page,\
48 gdev_prn_close,\
49 encode_color, /* map_rgb_color */\
50 bit_map_color_rgb, /* map_color_rgb */\
51 NULL, /* fill_rectangle */\
52 NULL, /* tile_rectangle */\
53 NULL, /* copy_mono */\
54 NULL, /* copy_color */\
55 NULL, /* draw_line */\
56 NULL, /* get_bits */\
57 bit_get_params,\
58 bit_put_params,\
59 encode_color, /* map_cmyk_color */\
60 NULL, /* get_xfont_procs */\
61 NULL, /* get_xfont_device */\
62 NULL, /* map_rgb_alpha_color */\
63 gx_page_device_get_page_device, /* get_page_device */\
64 NULL, /* get_alpha_bits */\
65 NULL, /* copy_alpha */\
66 NULL, /* get_band */\
67 NULL, /* copy_rop */\
68 NULL, /* fill_path */\
69 NULL, /* stroke_path */\
70 NULL, /* fill_mask */\
71 NULL, /* fill_trapezoid */\
72 NULL, /* fill_parallelogram */\
73 NULL, /* fill_triangle */\
74 NULL, /* draw_thin_line */\
75 NULL, /* begin_image */\
76 NULL, /* image_data */\
77 NULL, /* end_image */\
78 NULL, /* strip_tile_rectangle */\
79 NULL, /* strip_copy_rop */\
80 NULL, /* get_clipping_box */\
81 NULL, /* begin_typed_image */\
82 NULL, /* get_bits_rectangle */\
83 NULL, /* map_color_rgb_alpha */\
84 NULL, /* create_compositor */\
85 NULL, /* get_hardware_params */\
86 NULL, /* text_begin */\
87 NULL, /* finish_copydevice */\
88 NULL, /* begin_transparency_group */\
89 NULL, /* end_transparency_group */\
90 NULL, /* begin_transparency_mask */\
91 NULL, /* end_transparency_mask */\
92 NULL, /* discard_transparency_layer */\
93 NULL, /* get_color_mapping_procs */\
94 NULL, /* get_color_comp_index */\
95 encode_color, /* encode_color */\
96 bit_map_color_rgb /* decode_color */\
97 }
98
99 /*
100 * The following macro is used in get_params and put_params to determine the
101 * num_components for the current device. It works using the device name
102 * character after "bit" which is either '\0', 'r', or 'c'. Any new devices
103 * that are added to this module must modify this macro to return the
104 * correct num_components. This is needed to support the ForceMono
105 * parameter, which alters dev->num_components.
106 */
107 #define REAL_NUM_COMPONENTS(dev) (dev->dname[3] == 'c' ? 4 : \
108 dev->dname[3] == 'r' ? 3 : 1)
109
110 private const gx_device_procs bitmono_procs =
111 bit_procs(bit_mono_map_color);
112 const gx_device_printer gs_bit_device =
113 {prn_device_body(gx_device_printer, bitmono_procs, "bit",
114 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
115 X_DPI, Y_DPI,
116 0, 0, 0, 0, /* margins */
117 1, 1, 1, 0, 2, 1, bit_print_page)
118 };
119
120 private const gx_device_procs bitrgb_procs =
121 bit_procs(gx_default_rgb_map_rgb_color);
122 const gx_device_printer gs_bitrgb_device =
123 {prn_device_body(gx_device_printer, bitrgb_procs, "bitrgb",
124 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
125 X_DPI, Y_DPI,
126 0, 0, 0, 0, /* margins */
127 3, 4, 1, 1, 2, 2, bit_print_page)
128 };
129
130 private const gx_device_procs bitcmyk_procs =
131 bit_procs(bit_map_cmyk_color);
132 const gx_device_printer gs_bitcmyk_device =
133 {prn_device_body(gx_device_printer, bitcmyk_procs, "bitcmyk",
134 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
135 X_DPI, Y_DPI,
136 0, 0, 0, 0, /* margins */
137 4, 4, 1, 1, 2, 2, bit_print_page)
138 };
139
140 /* Map gray to color. */
141 /* Note that 1-bit monochrome is a special case. */
142 private gx_color_index
bit_mono_map_color(gx_device * dev,const gx_color_value cv[])143 bit_mono_map_color(gx_device * dev, const gx_color_value cv[])
144 {
145 int bpc = dev->color_info.depth;
146 int drop = sizeof(gx_color_value) * 8 - bpc;
147 gx_color_value gray = cv[0];
148
149 return (bpc == 1 ? gx_max_color_value - gray : gray) >> drop;
150 }
151
152 /* Map color to RGB. This has 3 separate cases, but since it is rarely */
153 /* used, we do a case test rather than providing 3 separate routines. */
154 private int
bit_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value cv[4])155 bit_map_color_rgb(gx_device * dev, gx_color_index color, gx_color_value cv[4])
156 {
157 int depth = dev->color_info.depth;
158 int ncomp = REAL_NUM_COMPONENTS(dev);
159 int bpc = depth / ncomp;
160 uint mask = (1 << bpc) - 1;
161
162 #define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / mask))
163
164 switch (ncomp) {
165 case 1: /* gray */
166 cv[0] =
167 (depth == 1 ? (color ? 0 : gx_max_color_value) :
168 cvalue(color));
169 break;
170 case 3: /* RGB */
171 {
172 gx_color_index cshift = color;
173
174 cv[2] = cvalue(cshift & mask);
175 cshift >>= bpc;
176 cv[1] = cvalue(cshift & mask);
177 cv[0] = cvalue(cshift >> bpc);
178 }
179 break;
180 case 4: /* CMYK */
181 /* Map CMYK back to RGB. */
182 {
183 gx_color_index cshift = color;
184 uint c, m, y, k;
185
186 k = cshift & mask;
187 cshift >>= bpc;
188 y = cshift & mask;
189 cshift >>= bpc;
190 m = cshift & mask;
191 c = cshift >> bpc;
192 /* We use our improved conversion rule.... */
193 cv[0] = cvalue((mask - c) * (mask - k) / mask);
194 cv[1] = cvalue((mask - m) * (mask - k) / mask);
195 cv[2] = cvalue((mask - y) * (mask - k) / mask);
196 }
197 break;
198 }
199 return 0;
200 #undef cvalue
201 }
202
203 /* Map CMYK to color. */
204 private gx_color_index
bit_map_cmyk_color(gx_device * dev,const gx_color_value cv[])205 bit_map_cmyk_color(gx_device * dev, const gx_color_value cv[])
206 {
207 int bpc = dev->color_info.depth / 4;
208 int drop = sizeof(gx_color_value) * 8 - bpc;
209 gx_color_index color =
210 (((((((gx_color_index) cv[0] >> drop) << bpc) +
211 (cv[1] >> drop)) << bpc) +
212 (cv[2] >> drop)) << bpc) +
213 (cv[3] >> drop);
214
215 return (color == gx_no_color_index ? color ^ 1 : color);
216 }
217
218 /* Get parameters. We provide a default CRD. */
219 private int
bit_get_params(gx_device * pdev,gs_param_list * plist)220 bit_get_params(gx_device * pdev, gs_param_list * plist)
221 {
222 int code, ecode;
223 /*
224 * The following is a hack to get the original num_components.
225 * See comment above.
226 */
227 int real_ncomps = REAL_NUM_COMPONENTS(pdev);
228 int ncomps = pdev->color_info.num_components;
229 int forcemono = (ncomps == real_ncomps ? 0 : 1);
230
231 /*
232 * Temporarily set num_components back to the "real" value to avoid
233 * confusing those that rely on it.
234 */
235 pdev->color_info.num_components = real_ncomps;
236
237 ecode = gdev_prn_get_params(pdev, plist);
238 code = sample_device_crd_get_params(pdev, plist, "CRDDefault");
239 if (code < 0)
240 ecode = code;
241 if ((code = param_write_int(plist, "ForceMono", &forcemono)) < 0) {
242 ecode = code;
243 }
244
245 /* Restore the working num_components */
246 pdev->color_info.num_components = ncomps;
247
248 return ecode;
249 }
250
251 /* Set parameters. We allow setting the number of bits per component. */
252 /* Also, ForceMono=1 forces monochrome output from RGB/CMYK devices. */
253 private int
bit_put_params(gx_device * pdev,gs_param_list * plist)254 bit_put_params(gx_device * pdev, gs_param_list * plist)
255 {
256 gx_device_color_info save_info;
257 int ncomps = pdev->color_info.num_components;
258 int real_ncomps = REAL_NUM_COMPONENTS(pdev);
259 int bpc = pdev->color_info.depth / real_ncomps;
260 int v;
261 int ecode = 0;
262 int code;
263 static const byte depths[4][16] = {
264 {1, 2, 0, 4, 8, 0, 0, 8, 0, 0, 0, 16, 0, 0, 0, 16},
265 {0},
266 {4, 8, 0, 16, 16, 0, 0, 24, 0, 0, 0, 40, 0, 0, 0, 48},
267 {4, 8, 0, 16, 32, 0, 0, 32, 0, 0, 0, 48, 0, 0, 0, 64}
268 };
269 const char *vname;
270
271 /*
272 * Temporarily set num_components back to the "real" value to avoid
273 * confusing those that rely on it.
274 */
275 pdev->color_info.num_components = real_ncomps;
276
277 if ((code = param_read_int(plist, (vname = "GrayValues"), &v)) != 1 ||
278 (code = param_read_int(plist, (vname = "RedValues"), &v)) != 1 ||
279 (code = param_read_int(plist, (vname = "GreenValues"), &v)) != 1 ||
280 (code = param_read_int(plist, (vname = "BlueValues"), &v)) != 1
281 ) {
282 if (code < 0)
283 ecode = code;
284 else
285 switch (v) {
286 case 2: bpc = 1; break;
287 case 4: bpc = 2; break;
288 case 16: bpc = 4; break;
289 case 32: bpc = 5; break;
290 case 256: bpc = 8; break;
291 case 4096: bpc = 12; break;
292 case 65536: bpc = 16; break;
293 default:
294 param_signal_error(plist, vname,
295 ecode = gs_error_rangecheck);
296 }
297 }
298
299 switch (code = param_read_int(plist, (vname = "ForceMono"), &v)) {
300 case 0:
301 if (v == 1) {
302 ncomps = 1;
303 break;
304 }
305 else if (v == 0) {
306 ncomps = real_ncomps;
307 break;
308 }
309 code = gs_error_rangecheck;
310 default:
311 ecode = code;
312 param_signal_error(plist, vname, ecode);
313 case 1:
314 break;
315 }
316 if (ecode < 0)
317 return ecode;
318
319 /*
320 * Save the color_info in case gdev_prn_put_params fails, and for
321 * comparison. Note that depth is computed from real_ncomps.
322 */
323 save_info = pdev->color_info;
324 pdev->color_info.depth = depths[real_ncomps - 1][bpc - 1];
325 pdev->color_info.max_gray = pdev->color_info.max_color =
326 (pdev->color_info.dither_grays =
327 pdev->color_info.dither_colors =
328 (1 << bpc)) - 1;
329 ecode = gdev_prn_put_params(pdev, plist);
330 if (ecode < 0) {
331 pdev->color_info = save_info;
332 return ecode;
333 }
334 /* Now restore/change num_components. This is done after other */
335 /* processing since it is used in gx_default_put_params */
336 pdev->color_info.num_components = ncomps;
337 if (pdev->color_info.depth != save_info.depth ||
338 pdev->color_info.num_components != save_info.num_components
339 ) {
340 gs_closedevice(pdev);
341 }
342 /* Reset the map_cmyk_color procedure if appropriate. */
343 if (dev_proc(pdev, map_cmyk_color) == cmyk_1bit_map_cmyk_color ||
344 dev_proc(pdev, map_cmyk_color) == cmyk_8bit_map_cmyk_color ||
345 dev_proc(pdev, map_cmyk_color) == bit_map_cmyk_color) {
346 set_dev_proc(pdev, map_cmyk_color,
347 pdev->color_info.depth == 4 ? cmyk_1bit_map_cmyk_color :
348 pdev->color_info.depth == 32 ? cmyk_8bit_map_cmyk_color :
349 bit_map_cmyk_color);
350 }
351 /* Reset the sparable and linear shift, masks, bits. */
352 set_linear_color_bits_mask_shift(pdev);
353 pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
354 return 0;
355 }
356
357 /* Send the page to the printer. */
358 private int
bit_print_page(gx_device_printer * pdev,FILE * prn_stream)359 bit_print_page(gx_device_printer * pdev, FILE * prn_stream)
360 { /* Just dump the bits on the file. */
361 /* If the file is 'nul', don't even do the writes. */
362 int line_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
363 byte *in = gs_alloc_bytes(pdev->memory, line_size, "bit_print_page(in)");
364 byte *data;
365 int nul = !strcmp(pdev->fname, "nul");
366 int lnum = 0, bottom = pdev->height;
367
368 if (in == 0)
369 return_error(gs_error_VMerror);
370 for (; lnum < bottom; ++lnum) {
371 gdev_prn_get_bits(pdev, lnum, in, &data);
372 if (!nul)
373 fwrite(data, 1, line_size, prn_stream);
374 }
375 gs_free_object(pdev->memory, in, "bit_print_page(in)");
376 return 0;
377 }
378