2 |
- |
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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 |
}
|