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