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