xref: /plan9/sys/src/cmd/gs/src/gdevcdj.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1991, 1995-2001 artofcode LLC.  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: gdevcdj.c,v 1.15 2004/08/04 19:36:12 stefan Exp $*/
18 /* HP and Canon colour printer drivers */
19 
20 /****************************************************************
21  * The code in this file was contributed by the authors whose names and/or
22  * e-mail addresses appear below: Aladdin Enterprises takes no
23  * responsibility for it.  In the past, we have tried to keep it working,
24  * but too many users have made too many "improvements" without regard to
25  * the overall structure; the last three "improvements" required me to spend
26  * several hours fixing each one so that the code worked again at all.  For
27  * this reason, no further changes to this file will be accepted.  We are
28  * planning eventually to get these drivers rewritten from scratch.
29  *
30  *				L. Peter Deutsch
31  *				Aladdin Enterprises
32  *				February 28, 1996
33  ****************************************************************/
34 
35 /*
36  * Change history:
37  *	2000-08-20 Jonathan Kamens <jik@kamens.brookline.ma.us>:
38  *	  change to support printers with different X and Y resolution.
39  */
40 
41 /*
42  * Important compilation notes (YA).
43  *
44  * You may also try the cdj550cmyk driver after having defined
45  * USE_CDJ550_CMYK and added the needed definition in devs.mak. Not tried!
46  * (I have a BJC!) Also note that modes descriptions of CMYK printing
47  * is done under the BJC section of devices.doc.
48  *
49  * CMYK to RGB conversion is made a la GhostScript unless you define
50  * the preprocessor symbol USE_ADOBE_CMYK_RGB.
51  *
52  *   Ghostscript:	R = (1.0 - C) * (1.0 - K)
53  *   Adobe:		R = 1.0 - min(1.0, C + K)
54  *
55  * (and similarly for G and B).  Ghostscript claims its method achieves
56  * better results.
57  *
58  * For the BJC drivers, define BJC_DEFAULT_CENTEREDAREA if you want to
59  * have the  same top and bottom margins (default to use the tallest
60  * imageable area available, usually with a top margin smaller than
61  * the bottom one). Defining USE_RECOMMENDED_MARGINS has the same
62  * effect and also sets these margins to 12.4 mm. Other compilation
63  * defines are explained in devices.doc.
64  *
65  * You can also define BJC_INIT_800_AS_600 to not use BJC-800-specific code
66  * in the page initialization sequence (normally not useful to you at all,
67  * just for my debugging of the driver margins).
68  *
69  */
70 
71 #include "std.h"		/* to stop stdlib.h redefining types */
72 #include <stdlib.h>		/* for rand() */
73 #include "gdevprn.h"
74 #include "gdevpcl.h"
75 #include "gsparam.h"
76 #include "gsstate.h"
77 
78 /* Conversion stuff. */
79 #include "gxlum.h"
80 
81 /* Canon stuff */
82 
83 #include "gdevbjc.h"
84 
85 /***
86  *** This file contains multiple drivers.  The main body of code, and all
87  *** but the DesignJet driver, were contributed by George Cameron;
88  *** please contact g.cameron@biomed.abdn.ac.uk if you have questions.
89  *     1 - cdj500:	HP DeskJet 500C
90  *     2 - cdj550:	HP DeskJet 550C
91  *     3 - pjxl300:	HP PaintJet XL300
92  *     4 - pj:		HP PaintJet
93  *     5 - pjxl:	HP PaintJet XL
94  *     6 - declj250:	DEC LJ250
95  *** The DesignJet 650C driver was contributed by Koert Zeilstra;
96  *** please contact koert@zen.cais.com if you have questions.
97  *     7 - dnj650c      HP DesignJet 650C
98  *** The LaserJet 4 driver with dithering was contributed by Eckhard
99  *** Rueggeberg; please contact eckhard@ts.go.dlr.de if you have questions.
100  *     8 - lj4dith:	HP LaserJet 4 with dithering
101  *** The ESC/P driver (for Epson ESC/P compatible printers) was written by
102  *** Yoshio Kuniyoshi <yoshio@nak.math.keio.ac.jp>, but is not maintained at
103  *** the moment.
104  *     9 - esc/p:       Epson ESC/P-compatible printers
105  *** The BJC600 driver (which also works for BJC4000) was written first
106  *** by Yoshio Kuniyoshi <yoshio@nak.math.keio.ac.jp> and later modified by
107  *** Yves Arrouye <yves.arrouye@usa.net>. The current driver has been
108  *** completely rewritten by me (YA) for good color handling.
109  *    10 - bjc600:	BJC 600//4000 printers
110  *** The BJC800 driver is based on the bjc600 one. By YA too.
111  *    11 - bjc800:	BJC 800 printer
112  ***/
113 
114 /*
115  * All of the HP-like drivers have 8-bit (monochrome), 16-bit and 24-bit
116  *     (colour) and for the DJ 550C 32-bit, (colour, cmyk mode)
117  *     options in addition to the usual 1-bit and 3-bit modes
118  * It is also possible to set various printer-specific parameters
119  *     from the gs command line, eg.
120  *
121  *  gs -sDEVICE=cdj550 -dBitsPerPixel=16 -dDepletion=1 -dShingling=2 tiger.eps
122  *
123  * Please consult the appropriate section in the devices.doc file for
124  * further details on all these drivers.
125  *
126  * All of the BJC-like drivers have 1-bit and 8-bit monochrome modes, 8-bit,
127  *     16-bit, 24-bit and 32-bit colour cmyk mode (the 8-bit monochrome mode
128  *     is called "4-bit". If you want to add a CMYK printer, look at the
129  *     bjc6000/bjc800 devices declarations and initialization.
130  *
131  * If you want to support different color components for the same depth
132  * on a non-CMYK printer, look how this is done for CMYK printers in
133  * cdj_set_bpp.
134  *
135  */
136 
137 /*
138  * This taken from gsdparam.c. I hope it will be useable directly some day.
139  *
140  */
141 
142 #define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
143   switch ( ncode = pread(plist, (oname = pname), &pa) )\
144   {\
145   case 0:\
146 	if ( pa.size != psize )\
147 	  code = gs_error_rangecheck;\
148 	else {
149 /* The body of the processing code goes here. */
150 /* If it succeeds, it should do a 'break'; */
151 /* if it fails, it should set ecode and fall through. */
152 #define END_PARAM(pa, e)\
153 	}\
154 	goto e;\
155   default:\
156 	code = ncode;\
157 e:	param_signal_error(plist, oname, code);\
158   case 1:\
159 	pa.data = 0;		/* mark as not filled */\
160   }
161 
162 private int cdj_param_check_bytes(gs_param_list *, gs_param_name, const byte *, uint, bool);
163 private int cdj_param_check_float(gs_param_list *, gs_param_name, floatp, bool);
164 #define cdj_param_check_string(plist, pname, str, is_defined)\
165   cdj_param_check_bytes(plist, pname, (const byte *)(str), strlen(str),\
166 			is_defined)
167 
168 /*
169  * Drivers stuff.
170  *
171  */
172 
173 #define DESKJET_PRINT_LIMIT  0.04	/* 'real' top margin? */
174 #define PAINTJET_PRINT_LIMIT 0.0	/* This is a guess.. */
175 #define ESC_P_PRINT_LIMIT    0.335
176 
177 /* Margins are left, bottom, right, top. */
178 #define DESKJET_MARGINS_LETTER   (float)0.25, (float)0.50, (float)0.25, (float)0.167
179 #define DESKJET_MARGINS_A4       (float)0.125, (float)0.50, (float)0.143, (float)0.167
180 #define LJET4_MARGINS  		 (float)0.26, (float)0.0, (float)0.0, (float)0.0
181 /* The PaintJet and DesignJet seem to have the same margins */
182 /* regardless of paper size. */
183 #define PAINTJET_MARGINS         (float)0.167, (float)0.167, (float)0.167, (float)0.167
184 #define DESIGNJET_MARGINS        (float)0.167, (float)0.167, (float)0.167, (float)0.167
185 
186 /*
187  * With ESC/P commands, BJC-600 can print no more than 8 inches width.
188  * So it can't use full width of letter size paper.  Since non printable
189  * left side area is 0.134 inch, we set up margins as follows.
190  *
191  * Note to readers: the bjc drivers series do *not* use ESC/P commands
192  * but raster ops. Configuration of these drivers can be done through
193  * the gdevbjc.h file.
194  *
195  */
196 #define ESC_P_MARGINS_LETTER    (float)0.134, (float)(0.276+0.2), \
197  				(float)(0.366+0.01), (float)0.335
198 #define ESC_P_MARGINS_A4        (float)0.134, (float)(0.276+0.2), \
199 				(float)(0.166+0.01), (float)0.335
200 
201 /* Define bits-per-pixel for generic drivers - default is 24-bit mode */
202 #ifndef BITSPERPIXEL
203 #  define BITSPERPIXEL 24
204 #endif
205 
206 /*
207  * The following use of size_of rather than sizeof is required to work
208  * around a bug in Microsoft Visual C++ 5.0, which considers the THRESHOLD
209  * value (128 << SHIFT) to be unsigned because SHIFT is unsigned (because
210  * sizeof() is unsigned).
211  */
212 #define W size_of(word)
213 #define I size_of(int)
214 
215 
216 #define invert_word(v)\
217      ((v) >> 24) + (((v) >> 8) & 0xff00L) +\
218 	 (((word)(v) << 8) & 0xff0000L) + ((word)(v) << 24)
219 
220 
221 /* Printer types */
222 #define DJ500C   0
223 #define DJ550C   1
224 #define PJXL300  2
225 #define PJ180    3
226 #define PJXL180  4
227 #define DECLJ250 5
228 #define DNJ650C  6
229 #define LJ4DITH  7
230 #define ESC_P	 8
231 #define BJC600	 9
232 #define BJC800	 10
233 
234 /* No. of ink jets (used to minimise head movements) */
235 #define HEAD_ROWS_MONO 50
236 #define HEAD_ROWS_COLOUR 16
237 
238 /* Colour mapping procedures */
239 private dev_proc_map_cmyk_color (gdev_cmyk_map_cmyk_color);
240 private dev_proc_map_rgb_color (gdev_cmyk_map_rgb_color);
241 
242 private dev_proc_map_rgb_color (gdev_pcl_map_rgb_color);
243 private dev_proc_map_color_rgb (gdev_pcl_map_color_rgb);
244 private dev_proc_decode_color  (gdev_cmyk_map_color_cmyk);
245 
246 /* Print-page, parameters and miscellaneous procedures */
247 private dev_proc_open_device(dj500c_open);
248 private dev_proc_open_device(dj550c_open);
249 private dev_proc_open_device(dnj650c_open);
250 private dev_proc_open_device(lj4dith_open);
251 private dev_proc_open_device(pj_open);
252 private dev_proc_open_device(pjxl_open);
253 private dev_proc_open_device(pjxl300_open);
254 private dev_proc_open_device(escp_open);
255 private dev_proc_open_device(bjc_open);
256 
257 private dev_proc_print_page(declj250_print_page);
258 private dev_proc_print_page(dj500c_print_page);
259 private dev_proc_print_page(dj550c_print_page);
260 private dev_proc_print_page(dnj650c_print_page);
261 private dev_proc_print_page(lj4dith_print_page);
262 private dev_proc_print_page(pj_print_page);
263 private dev_proc_print_page(pjxl_print_page);
264 private dev_proc_print_page(pjxl300_print_page);
265 private dev_proc_print_page(escp_print_page);
266 private dev_proc_print_page(bjc_print_page);
267 
268 private dev_proc_get_params(cdj_get_params);
269 private dev_proc_get_params(pjxl_get_params);
270 private dev_proc_get_params(bjc_get_params);
271 #define ep_get_params cdj_get_params
272 
273 private dev_proc_put_params(cdj_put_params);
274 private dev_proc_put_params(pj_put_params);
275 private dev_proc_put_params(pjxl_put_params);
276 private dev_proc_put_params(bjc_put_params);
277 #define ep_put_params cdj_put_params
278 
279 /* The device descriptors */
280 
281 #define gx_prn_colour_device_common \
282     gx_prn_device_common; \
283     short cmyk;	  	/* 0: not CMYK-capable, > 0: printing CMYK, */ \
284 		  	/* < 0 : CMYK-capable, not printing CMYK */ \
285     uint default_depth;	/* Used only for CMYK-capable printers now. */ \
286     uint correction
287 
288 typedef struct gx_device_cdj_s gx_device_cdj;
289 struct gx_device_cdj_s {
290 	gx_device_common;
291 	gx_prn_colour_device_common;
292 	int shingling;		  /* Interlaced, multi-pass printing */
293 	int depletion;		  /* 'Intelligent' dot-removal */
294 };
295 
296 typedef struct gx_device_pjxl_s gx_device_pjxl;
297 struct gx_device_pjxl_s {
298 	gx_device_common;
299 	gx_prn_colour_device_common;
300 	int printqual;            /* Mechanical print quality */
301 	int rendertype;           /* Driver or printer dithering control */
302 };
303 
304 typedef struct gx_device_hp_s gx_device_hp;
305 struct gx_device_hp_s {
306 	gx_device_common;
307 	gx_prn_colour_device_common;
308 };
309 
310 typedef struct gx_device_hp_s gx_device_pj;
311 
312 typedef struct gx_device_bjc600_s gx_device_bjc600;
313 typedef struct gx_device_bjc800_s gx_device_bjc800;
314 
315 typedef struct gx_device_bjc800_s gx_device_bjc;
316 
317 #define bjc_params_common \
318     bool manualFeed;		/* Use manual feed */ \
319     int mediaType;		/* Cf. strings below */ \
320     bool mediaWeight_isSet;	/* Say if weight is an integer or null */ \
321     int mediaWeight;		/* Weigth of the media */ \
322     int printQuality;		/* Cf. strings below */ \
323     bool ditheringType;		/* Do dithering */ \
324     int colorComponents;	/* The number of *desired* color comps */ \
325     int printColors		/* 0: Transparent, \
326 				   1: C, 2: M, 4: Y, 7: K (Color decomp). \
327 				   if > 8, print in black ink. */
328 
329 typedef struct {
330     bjc_params_common;
331 
332     bool monochromePrint;	/* Print with black only */
333 } bjc600_params;
334 
335 typedef struct {
336     bjc_params_common;
337 } bjc_params;
338 
339 typedef bjc_params bjc800_params;
340 
341 #define gx_bjc_device_common \
342     gx_device_common; \
343     gx_prn_colour_device_common; \
344     int ptype; \
345     float printLimit
346 
347 struct gx_device_bjc600_s {
348         gx_bjc_device_common;
349 	bjc600_params bjc_p;
350 };
351 struct gx_device_bjc800_s {
352         gx_bjc_device_common;
353 	bjc800_params bjc_p;
354 };
355 
356 typedef struct {
357     gx_device_common;
358     gx_prn_colour_device_common;
359 } gx_device_colour_prn;
360 
361 /* Use the cprn_device macro to access generic fields (like cmyk,
362    default_depth and correction), and specific macros for specific
363    devices. */
364 
365 #define cprn_device     ((gx_device_colour_prn*) pdev)
366 
367 #define cdj       ((gx_device_cdj *)pdev)
368 #define pjxl      ((gx_device_pjxl *)pdev)
369 #define pj	((gx_device_pj *)pdev)
370 
371 #define bjc             ((gx_device_bjc*) pdev)
372 #define bjc600          ((gx_device_bjc600*) pdev)
373 #define bjc800          ((gx_device_bjc800*) pdev)
374 
375 #define bjcparams	(bjc->bjc_p)
376 #define bjc600params	(bjc600->bjc_p)
377 #define bjc800params	(bjc800->bjc_p)
378 
379 #define bjcversion(p)	(((gx_device_bjc*) pdev)->ptype == BJC800 ? \
380     BJC_BJC800_VERSION : BJC_BJC600_VERSION)
381 #define bjcversionstring(p)	(((gx_device_bjc*) pdev)->ptype == BJC800 ? \
382     BJC_BJC800_VERSIONSTR : BJC_BJC600_VERSIONSTR)
383 
384 #define bjcthickpaper(l) \
385     (bjcparams.mediaWeight_isSet && bjcparams.mediaWeight > l)
386 #define bjc600thickpaper() bjcthickpaper(BJC600_MEDIAWEIGHT_THICKLIMIT)
387 #define bjc800thickpaper() bjcthickpaper(BJC800_MEDIAWEIGHT_THICKLIMIT)
388 
389 /* The basic structure for all printers. Note the presence of the cmyk, depth
390    and correct fields even if soem are not used by all printers. */
391 
392 #define prn_colour_device_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page, cmyk, correct)\
393     prn_device_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page), cmyk, depth /* default */, correct
394 
395 /* Note: the computation of color_info values here must match */
396 /* the computation in the cdj_set_bpp procedure below. */
397 
398 #define prn_hp_colour_device(dtype, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correct)\
399     prn_colour_device_body(dtype, procs, dev_name,\
400     DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, x_dpi, y_dpi, 0, 0, 0, 0,\
401     (bpp == 32 ? 4 : (bpp == 1 || bpp == 8) ? 1 : 3), bpp,\
402     (bpp >= 8 ? 255 : 1), (bpp >= 8 ? 255 : bpp > 1 ? 1 : 0),\
403     (bpp >= 8 ? 256 : 2), (bpp >= 8 ? 256 : bpp > 1 ? 2 : 0),\
404     print_page, 0 /* cmyk */, correct)
405 
406 #define prn_cmyk_colour_device(dtype, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correct)\
407     prn_colour_device_body(dtype, procs, dev_name,\
408     DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, x_dpi, y_dpi, 0, 0, 0, 0,\
409     ((bpp == 1 || bpp == 4) ? 1 : 4), bpp,\
410     (bpp > 8 ? 255 : 1), (1 << (bpp >> 2)) - 1, /* max_gray, max_color */\
411     (bpp > 8 ? 256 : 2), (bpp > 8 ? 256 : bpp > 1 ? 2 : 0),\
412     print_page, 1 /* cmyk */, correct)
413 
414 #define bjc_device(dtype, p, d, x, y, b, pp, c) \
415     prn_cmyk_colour_device(dtype, p, d, x, y, b, pp, c)
416 
417 #define cdj_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, correction, shingling, depletion)\
418 { prn_hp_colour_device(gx_device_cdj, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correction),\
419     shingling,\
420     depletion\
421 }
422 
423 #define pjxl_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, printqual, rendertype)\
424 { prn_hp_colour_device(gx_device_pjxl, procs, dev_name, x_dpi, y_dpi, bpp, print_page, 0), \
425     printqual,\
426     rendertype\
427 }
428 
429 #define pj_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page)\
430 { prn_hp_colour_device(gx_device_pj, procs, dev_name, x_dpi, y_dpi, bpp, print_page, 0) }
431 
432 #define bjc600_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, t, mf, mt, mws, mw, pq, dt, cc, pc, mp) \
433 { bjc_device(gx_device_bjc600, procs, dev_name, x_dpi, y_dpi, bpp, print_page, 0),\
434     t, 0., { mf, mt, mws, mw, pq, dt, cc, pc, mp }\
435 }
436 #define bjc800_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, t, mf, mt, mws, mw, pq, dt, cc, pc) \
437 { bjc_device(gx_device_bjc800, procs, dev_name, x_dpi, y_dpi, bpp, print_page, 0),\
438     t, 0., { mf, mt, mws, mw, pq, dt, cc, pc }\
439 }
440 
441 #define hp_colour_procs(proc_colour_open, proc_get_params, proc_put_params) {\
442 	proc_colour_open,\
443 	gx_default_get_initial_matrix,\
444 	gx_default_sync_output,\
445 	gdev_prn_output_page,\
446 	gdev_prn_close,\
447 	gdev_pcl_map_rgb_color,\
448 	gdev_pcl_map_color_rgb,\
449 	NULL,	/* fill_rectangle */\
450 	NULL,	/* tile_rectangle */\
451 	NULL,	/* copy_mono */\
452 	NULL,	/* copy_color */\
453 	NULL,	/* draw_line */\
454 	gx_default_get_bits,\
455 	proc_get_params,\
456 	proc_put_params\
457 }
458 
459 #define cmyk_colour_procs(proc_colour_open, proc_get_params, proc_put_params) {\
460 	proc_colour_open,\
461 	gx_default_get_initial_matrix,\
462 	gx_default_sync_output,\
463 	gdev_prn_output_page,\
464 	gdev_prn_close,\
465 	NULL /* map_rgb_color */,\
466 	NULL /* map_color_rgb */,\
467 	NULL /* fill_rectangle */,\
468 	NULL /* tile_rectangle */,\
469 	NULL /* copy_mono */,\
470 	NULL /* copy_color */,\
471 	NULL /* draw_line */,\
472 	gx_default_get_bits,\
473 	proc_get_params,\
474 	proc_put_params,\
475         gdev_cmyk_map_cmyk_color,\
476 	NULL,	/* get_xfont_procs */\
477 	NULL,	/* get_xfont_device */\
478 	NULL,	/* map_rgb_alpha_color */\
479 	NULL,	/* get_page_device */\
480 	NULL,	/* get_alpha_bits */\
481 	NULL,	/* copy_alpha */\
482 	NULL,	/* get_band */\
483 	NULL,	/* copy_rop */\
484 	NULL,	/* fill_path */\
485 	NULL,	/* stroke_path */\
486 	NULL,	/* fill_mask */\
487 	NULL,	/* fill_trapezoid */\
488 	NULL,	/* fill_parallelogram */\
489 	NULL,	/* fill_triangle */\
490 	NULL,	/* draw_thin_line */\
491 	NULL,	/* begin_image */\
492 	NULL,	/* image_data */\
493 	NULL,	/* end_image */\
494 	NULL,	/* strip_tile_rectangle */\
495 	NULL,	/* strip_copy_rop */\
496 	NULL,	/* get_clipping_box */\
497 	NULL,	/* begin_typed_image */\
498 	NULL,	/* get_bits_rectangle */\
499 	NULL,	/* map_color_rgb_alpha */\
500 	NULL,	/* create_compositor */\
501 	NULL,	/* get_hardware_params */\
502 	NULL,	/* text_begin */\
503 	NULL,	/* finish_copydevice */\
504 	NULL,	/* begin_transparency_group */\
505 	NULL,	/* end_transparency_group */\
506 	NULL,	/* begin_transparency_mask */\
507 	NULL,	/* end_transparency_mask */\
508 	NULL,	/* discard_transparency_layer */\
509 	NULL,	/* get_color_mapping_procs */\
510 	NULL,	/* get_color_comp_index */\
511 	gdev_cmyk_map_cmyk_color,	/* encode_color */\
512 	gdev_cmyk_map_color_cmyk	/* decode_color */\
513 }
514 
515 private gx_device_procs cdj500_procs =
516 hp_colour_procs(dj500c_open, cdj_get_params, cdj_put_params);
517 
518 private gx_device_procs cdj550_procs =
519 hp_colour_procs(dj550c_open, cdj_get_params, cdj_put_params);
520 
521 #ifdef USE_CDJ550_CMYK
522 private gx_device_procs cdj550cmyk_procs =
523 cmyk_colour_procs(dj550c_open, cdj_get_params, cdj_put_params);
524 #endif
525 
526 private gx_device_procs dnj650c_procs =
527 hp_colour_procs(dnj650c_open, cdj_get_params, cdj_put_params);
528 
529 private gx_device_procs lj4dith_procs =
530 hp_colour_procs(lj4dith_open, cdj_get_params, cdj_put_params);
531 
532 private gx_device_procs pj_procs =
533 hp_colour_procs(pj_open, gdev_prn_get_params, pj_put_params);
534 
535 private gx_device_procs pjxl_procs =
536 hp_colour_procs(pjxl_open, pjxl_get_params, pjxl_put_params);
537 
538 private gx_device_procs pjxl300_procs =
539 hp_colour_procs(pjxl300_open, pjxl_get_params, pjxl_put_params);
540 
541 private gx_device_procs bjc_procs =
542 cmyk_colour_procs(bjc_open, bjc_get_params, bjc_put_params);
543 
544 private gx_device_procs escp_procs =
545 hp_colour_procs(escp_open, ep_get_params, ep_put_params);
546 
547 gx_device_cdj far_data gs_cdjmono_device =
548 cdj_device(cdj500_procs, "cdjmono", 300, 300, 1,
549 	   dj500c_print_page, 4, 0, 1);
550 
551 gx_device_cdj far_data gs_cdeskjet_device =
552 cdj_device(cdj500_procs, "cdeskjet", 300, 300, 3,
553 	   dj500c_print_page, 4, 2, 1);
554 
555 gx_device_cdj far_data gs_cdjcolor_device =
556 cdj_device(cdj500_procs, "cdjcolor", 300, 300, 24,
557 	   dj500c_print_page, 4, 2, 1);
558 
559 gx_device_cdj far_data gs_cdj500_device =
560 cdj_device(cdj500_procs, "cdj500", 300, 300, BITSPERPIXEL,
561 	   dj500c_print_page, 4, 2, 1);
562 
563 gx_device_cdj far_data gs_cdj550_device =
564 cdj_device(cdj550_procs, "cdj550", 300, 300, BITSPERPIXEL,
565 	   dj550c_print_page, 0, 2, 1);
566 
567 #ifdef USE_CDJ550_CMYK
568 gx_device_cdj far_data gs_cdj550cmyk_device = {
569     prn_cmyk_colour_device(cdj550cmyk_procs, "cdj550cmyk", 300, 300,
570         BITSPERPIXEL, dj550c_print_page, 0), 2, 1
571 };
572 #endif
573 
574 gx_device_pj far_data gs_declj250_device =
575 pj_device(pj_procs, "declj250", 180, 180, BITSPERPIXEL,
576 	  declj250_print_page);
577 
578 gx_device_cdj far_data gs_dnj650c_device =
579 cdj_device(dnj650c_procs, "dnj650c", 300, 300, BITSPERPIXEL,
580 	   dnj650c_print_page, 0, 2, 1);
581 
582 gx_device_cdj far_data gs_lj4dith_device =
583 cdj_device(lj4dith_procs, "lj4dith", 600, 600, 8,
584 	   lj4dith_print_page, 4, 0, 1);
585 
586 gx_device_pj far_data gs_pj_device =
587 pj_device(pj_procs, "pj", 180, 180, BITSPERPIXEL,
588 	  pj_print_page);
589 
590 gx_device_pjxl far_data gs_pjxl_device =
591 pjxl_device(pjxl_procs, "pjxl", 180, 180, BITSPERPIXEL,
592 	    pjxl_print_page, 0, 0);
593 
594 gx_device_pjxl far_data gs_pjxl300_device =
595 pjxl_device(pjxl300_procs, "pjxl300", 300, 300, BITSPERPIXEL,
596 	    pjxl300_print_page, 0, 0);
597 
598 gx_device_cdj far_data gs_escp_device =
599 cdj_device(escp_procs, "escp", 360, 360, 8,
600 	   escp_print_page, 0, 0, 1);
601 
602 gx_device_cdj far_data gs_escpc_device =
603 cdj_device(escp_procs, "escpc", 360, 360, 24,
604 	   escp_print_page, 0, 0, 1);
605 
606 /* Args of bjc drivers are manualFeed, mediaType, printQuality, printColor,
607    mediaWeight_isSet, mediaWeight, (monochromePrint) */
608 
609 gx_device_bjc600 far_data gs_bjc600_device =
610     bjc600_device(
611 	bjc_procs,
612         BJC_BJC600,
613         BJC600_DEFAULT_RESOLUTION,
614         BJC600_DEFAULT_RESOLUTION,
615         BJC600_DEFAULT_BITSPERPIXEL,
616 	bjc_print_page,
617         BJC600,
618 	BJC600_DEFAULT_MANUALFEED,
619 	BJC600_DEFAULT_MEDIATYPE,
620 	BJC600_DEFAULT_SETMEDIAWEIGHT,
621 	BJC600_DEFAULT_MEDIAWEIGHT,
622 	BJC600_DEFAULT_PRINTQUALITY,
623 	BJC600_DEFAULT_DITHERINGTYPE,
624 	BJC600_DEFAULT_COLORCOMPONENTS,
625 	BJC600_DEFAULT_PRINTCOLORS,
626 	BJC600_DEFAULT_MONOCHROMEPRINT);
627 
628 gx_device_bjc800 far_data gs_bjc800_device =
629     bjc800_device(
630         bjc_procs,
631         BJC_BJC800,
632         BJC800_DEFAULT_RESOLUTION,
633         BJC800_DEFAULT_RESOLUTION,
634         BJC800_DEFAULT_BITSPERPIXEL,
635 	bjc_print_page,
636         BJC800,
637 	BJC800_DEFAULT_MANUALFEED,
638 	BJC800_DEFAULT_MEDIATYPE,
639 	BJC800_DEFAULT_SETMEDIAWEIGHT,
640 	BJC800_DEFAULT_MEDIAWEIGHT,
641 	BJC800_DEFAULT_PRINTQUALITY,
642 	BJC800_DEFAULT_DITHERINGTYPE,
643 	BJC600_DEFAULT_COLORCOMPONENTS,
644 	BJC800_DEFAULT_PRINTCOLORS);
645 
646 /* Forward references */
647 private int gdev_pcl_mode1compress(const byte *, const byte *, byte *);
648 private int hp_colour_open(gx_device *, int);
649 private int hp_colour_print_page(gx_device_printer *, FILE *, int);
650 private int cdj_put_param_int(gs_param_list *, gs_param_name, int *, int, int, int);
651 private uint gdev_prn_rasterwidth(const gx_device_printer *, int);
652 private int cdj_put_param_bpp(gx_device *, gs_param_list *, int, int, int);
653 private int cdj_set_bpp(gx_device *, int, int);
654 private void cdj_expand_line(word *, int, short, int, int);
655 private int bjc_fscmyk(byte**, byte*[4][4], int**, int, int);
656 
657 /* String parameters manipulation */
658 
659 typedef struct {
660     const char* p_name;
661     int p_value;
662 } stringParamDescription;
663 
664 private const byte* paramValueToString(const stringParamDescription*, int);
665 private int paramStringValue(const stringParamDescription*,
666     const byte*, int, int*);
667 
668 private int put_param_string(gs_param_list*, const byte*,
669     gs_param_string*, const stringParamDescription*, int *, int);
670 private int get_param_string(gs_param_list*, const byte*,
671     gs_param_string*, const stringParamDescription*, int, bool, int);
672 
673 /* Open the printer and set up the margins. */
674 private int
dj500c_open(gx_device * pdev)675 dj500c_open(gx_device *pdev)
676 { return hp_colour_open(pdev, DJ500C);
677 }
678 
679 private int
dj550c_open(gx_device * pdev)680 dj550c_open(gx_device *pdev)
681 {  return hp_colour_open(pdev, DJ550C);
682 }
683 
684 private int
dnj650c_open(gx_device * pdev)685 dnj650c_open(gx_device *pdev)
686 { return hp_colour_open(pdev, DNJ650C);
687 }
688 
689 private int
lj4dith_open(gx_device * pdev)690 lj4dith_open(gx_device *pdev)
691 { return hp_colour_open(pdev, LJ4DITH);
692 }
693 
694 private int
pjxl300_open(gx_device * pdev)695 pjxl300_open(gx_device *pdev)
696 { return hp_colour_open(pdev, PJXL300);
697 }
698 
699 private int
pj_open(gx_device * pdev)700 pj_open(gx_device *pdev)
701 { return hp_colour_open(pdev, PJ180);
702 }
703 
704 private int
pjxl_open(gx_device * pdev)705 pjxl_open(gx_device *pdev)
706 { return hp_colour_open(pdev, PJXL180);
707 }
708 
709 private int
escp_open(gx_device * pdev)710 escp_open(gx_device *pdev)
711 { return hp_colour_open(pdev, ESC_P);
712 }
713 
714 private int
bjc_open(gx_device * pdev)715 bjc_open(gx_device *pdev)
716 {  return hp_colour_open(pdev, bjc->ptype);
717 }
718 
719 private int
hp_colour_open(gx_device * pdev,int ptype)720 hp_colour_open(gx_device *pdev, int ptype)
721 {	/* Change the margins if necessary. */
722   static const float dj_a4[4] = { DESKJET_MARGINS_A4 };
723   static const float dj_letter[4] = { DESKJET_MARGINS_LETTER };
724   static const float lj4_all[4] = { LJET4_MARGINS };
725   static const float pj_all[4] = { PAINTJET_MARGINS };
726   static const float dnj_all[4] = { DESIGNJET_MARGINS };
727   static const float ep_a4[4] = { ESC_P_MARGINS_A4 };
728   static const float ep_letter[4] = { ESC_P_MARGINS_LETTER };
729 
730   static float bjc_a3[4] = { BJC_MARGINS_A3 };		/* Not const! */
731   static float bjc_letter[4] = { BJC_MARGINS_LETTER };  /* Not const! */
732   static float bjc_a4[4] = { BJC_MARGINS_A4 };		/* Not const! */
733 
734   const float *m = (float *) 0;
735 
736   /* Set up colour params if put_params has not already done so */
737   if (pdev->color_info.num_components == 0)
738     {	int code = cdj_set_bpp(pdev, pdev->color_info.depth,
739 	    pdev->color_info.num_components);
740 	if ( code < 0 )
741 	  return code;
742     }
743 
744   switch (ptype) {
745   case DJ500C:
746   case DJ550C:
747     m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? dj_a4 :
748 	 dj_letter);
749     break;
750   case DNJ650C:
751     m = dnj_all;
752     break;
753   case LJ4DITH:
754     m = lj4_all;
755     break;
756   case PJ180:
757   case PJXL300:
758   case PJXL180:
759     m = pj_all;
760     break;
761   case ESC_P:
762     m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? ep_a4 :
763 	 ep_letter);
764     break;
765   case BJC600:
766   case BJC800:
767     switch (gdev_pcl_paper_size(pdev)) {
768 	case PAPER_SIZE_LEGAL:
769 	case PAPER_SIZE_LETTER:
770 	    m = bjc_letter;
771 	    break;
772 
773 	case PAPER_SIZE_A0:
774 	case PAPER_SIZE_A1:
775 	case PAPER_SIZE_A3:
776 	    m = bjc_a3;
777 	    break;
778 
779 	default:
780 	    m = bjc_a4;
781     }
782 
783 #ifndef USE_FIXED_MARGINS
784     if (ptype == BJC800) {
785 	((float *) m)[1] = (float)BJC_HARD_LOWER_LIMIT;
786     }
787 #endif
788 
789     bjc->printLimit = m[3];		/* The real hardware limit. */
790 
791 #ifdef BJC_DEFAULT_CENTEREDAREA
792     if (m[3] < m[1]) {
793 	((float *) m)[3] = m[1];  	/* Top margin = bottom one. */
794     } else {
795 	((float *) m)[1] = m[3];  	/* Bottom margin = top one. */
796     }
797 #endif
798 
799     break;
800 
801     /*NOTREACHED*/
802 
803     /*
804      * The margins must be set so that the resulting page length will be
805      * expressed exactly as a multiple of tenthes of inches.
806      *
807      */
808 
809     /**/ {
810 	float *bjcm = (float *) m;
811 
812 	byte pdimen = (byte)
813 	    (pdev->height / pdev->y_pixels_per_inch * 10.
814 	     - bjcm[3] * 10. - bjcm[1] * 10. + .5) + 1;
815 	do {
816 	    --pdimen;
817 	    bjcm[1] = pdev->height / pdev->y_pixels_per_inch
818 	        - bjcm[3] - (float) pdimen / 10.;
819 	} while (bjcm[1] < BJC_LOWER_LIMIT);
820     }
821 
822     break;
823   }
824   gx_device_set_margins(pdev, m, true);
825   return gdev_prn_open(pdev);
826 }
827 
828 /* Added parameters for DeskJet 5xxC */
829 
830 /* Get parameters.  In addition to the standard and printer
831  * parameters, we supply shingling and depletion parameters,
832  * and control over the bits-per-pixel used in output rendering */
833 private int
cdj_get_params(gx_device * pdev,gs_param_list * plist)834 cdj_get_params(gx_device *pdev, gs_param_list *plist)
835 {	int code = gdev_prn_get_params(pdev, plist);
836 	if ( code < 0 ||
837 	    (code = param_write_int(plist, "BlackCorrect", (int *)&cdj->correction)) < 0 ||
838 	    (code = param_write_int(plist, "Shingling", &cdj->shingling)) < 0 ||
839 	    (code = param_write_int(plist, "Depletion", &cdj->depletion)) < 0
840 	   )
841 	  return code;
842 
843 	return code;
844 }
845 
846 /* Put parameters. */
847 private int
cdj_put_params(gx_device * pdev,gs_param_list * plist)848 cdj_put_params(gx_device *pdev, gs_param_list *plist)
849 {	int correction = cdj->correction;
850 	int shingling = cdj->shingling;
851 	int depletion = cdj->depletion;
852 	int bpp = 0;
853 	int code = 0;
854 
855 	code = cdj_put_param_int(plist, "BlackCorrect", &correction, 0, 9, code);
856 	code = cdj_put_param_int(plist, "Shingling", &shingling, 0, 2, code);
857 	code = cdj_put_param_int(plist, "Depletion", &depletion, 1, 3, code);
858 	code = cdj_put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, code);
859 
860 	if ( code < 0 )
861 	  return code;
862 	code = cdj_put_param_bpp(pdev, plist, bpp, bpp, 0);
863 	if ( code < 0 )
864 	  return code;
865 
866 	cdj->correction = correction;
867 	cdj->shingling = shingling;
868 	cdj->depletion = depletion;
869 	return 0;
870 }
871 
872 /* Added parameters for PaintJet XL and PaintJet XL300 */
873 
874 /* Get parameters.  In addition to the standard and printer
875  * parameters, we supply print_quality and render_type
876  * parameters, together with bpp control. */
877 private int
pjxl_get_params(gx_device * pdev,gs_param_list * plist)878 pjxl_get_params(gx_device *pdev, gs_param_list *plist)
879 {	int code = gdev_prn_get_params(pdev, plist);
880 	if ( code < 0 ||
881 	    (code = param_write_int(plist, "PrintQuality", &pjxl->printqual)) < 0 ||
882 	    (code = param_write_int(plist, "RenderType", &pjxl->rendertype)) < 0
883 	   )
884 	  return code;
885 
886 	return code;
887 }
888 
889 /* Put parameters. */
890 private int
pjxl_put_params(gx_device * pdev,gs_param_list * plist)891 pjxl_put_params(gx_device *pdev, gs_param_list *plist)
892 {	int printqual = pjxl->printqual;
893 	int rendertype = pjxl->rendertype;
894 	int bpp = 0, real_bpp = 0;
895 	int code = 0;
896 
897 	code = cdj_put_param_int(plist, "PrintQuality", &printqual, -1, 1, code);
898 	code = cdj_put_param_int(plist, "RenderType", &rendertype, 0, 10, code);
899 	code = cdj_put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, code);
900 
901 	if ( code < 0 )
902 	  return code;
903 	real_bpp = bpp;
904 	if ( rendertype > 0 )
905 	  {	/* If printer is doing the dithering, we must have a
906 		 * true-colour mode, ie. 16 or 24 bits per pixel */
907 		if ( bpp > 0 && bpp < 16 )
908 		  real_bpp = 24;
909 	  }
910 	code = cdj_put_param_bpp(pdev, plist, bpp, real_bpp, 0);
911 	if ( code < 0 )
912 	  return code;
913 
914 	pjxl->printqual = printqual;
915 	pjxl->rendertype = rendertype;
916 	return 0;
917 }
918 
919 /* Added parameters for PaintJet */
920 
921 /* Put parameters.  In addition to the standard and printer */
922 /* parameters, we allow control of the bits-per-pixel */
923 private int
pj_put_params(gx_device * pdev,gs_param_list * plist)924 pj_put_params(gx_device *pdev, gs_param_list *plist)
925 {	int bpp = 0;
926 	int code = cdj_put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, 0);
927 
928 	if ( code < 0 )
929 	  return code;
930 	return cdj_put_param_bpp(pdev, plist, bpp, bpp, 0);
931 }
932 
933 private stringParamDescription bjc_processColorsStrings[] = {
934     { "DeviceGray",		1 },
935     { "DeviceRGB",		3 },
936     { "DeviceCMYK",		4 },
937     { 0 }
938 };
939 
940 private stringParamDescription bjc_mediaTypeStrings[] = {
941     { "PlainPaper",		BJC_MEDIA_PLAINPAPER },
942     { "CoatedPaper",		BJC_MEDIA_COATEDPAPER },
943     { "TransparencyFilm",	BJC_MEDIA_TRANSPARENCYFILM },
944     { "Envelope",		BJC_MEDIA_ENVELOPE },
945     { "Card",			BJC_MEDIA_CARD},
946     { "Other",		        BJC_MEDIA_OTHER },
947     { 0 }
948 };
949 
950 private stringParamDescription bjc600_printQualityStrings[] = {
951     { "Normal",	0 },
952     { "High",	1 },
953     { "Draft",  2 },
954     { 0 }
955 };
956 
957 private stringParamDescription bjc800_printQualityStrings[] = {
958     { "Normal",		0 },
959     { "High",		1 },
960     { "Low",    	3 },
961     { "Draft",		4 },
962     { 0 },
963 };
964 
965 private stringParamDescription bjc_ditheringTypeStrings[] = {
966     { "None",			BJC_DITHER_NONE },
967     { "Floyd-Steinberg",	BJC_DITHER_FS },
968     { 0 }
969 };
970 
971 private int
bjc_get_params(gx_device * pdev,gs_param_list * plist)972 bjc_get_params(gx_device *pdev, gs_param_list *plist)
973 {
974     int code = gdev_prn_get_params(pdev, plist);
975     int ncode;
976 
977     gs_param_string pmedia;
978     gs_param_string pquality;
979     gs_param_string dithering;
980 
981     if (code < 0) return_error(code);
982 
983     if ((ncode = param_write_bool(plist, BJC_OPTION_MANUALFEED,
984 	&bjcparams.manualFeed)) < 0) {
985 	code = ncode;
986     }
987 
988     code = get_param_string(plist, (unsigned char *)BJC_OPTION_MEDIATYPE, &pmedia,
989         bjc_mediaTypeStrings, bjcparams.mediaType, true, code);
990 
991     code = get_param_string(plist, (unsigned char *)BJC_OPTION_PRINTQUALITY, &pquality,
992         (bjc->ptype == BJC800 ? bjc800_printQualityStrings :
993 	bjc600_printQualityStrings), bjcparams.printQuality,
994 	true, code);
995 
996     code = get_param_string(plist, (unsigned char *)BJC_OPTION_DITHERINGTYPE, &dithering,
997         bjc_ditheringTypeStrings, bjcparams.ditheringType, true, code);
998 
999     if ((ncode = param_write_int(plist, BJC_OPTION_PRINTCOLORS,
1000 	&bjcparams.printColors)) < 0) {
1001 	code = ncode;
1002     }
1003 
1004     if ((ncode = (bjcparams.mediaWeight_isSet ?
1005 	param_write_int(plist, BJC_OPTION_MEDIAWEIGHT,
1006 	    &bjcparams.mediaWeight) :
1007 	param_write_null(plist, BJC_OPTION_MEDIAWEIGHT))) < 0) {
1008 	code = ncode;
1009     }
1010 
1011     if (bjc->ptype != BJC800) {
1012 	if ((ncode = param_write_bool(plist, BJC_OPTION_MONOCHROMEPRINT,
1013 	    &bjc600params.monochromePrint)) < 0) {
1014 	    code = ncode;
1015 	}
1016     }
1017 
1018     /**/ {
1019 	float version;
1020 	gs_param_string versionString;
1021 
1022 	bool bTrue = true;
1023 
1024 	version = bjcversion(pdev);
1025 	versionString.data = (byte *)bjcversionstring(pdev);
1026 
1027 	versionString.size = strlen((char *)versionString.data);
1028 	versionString.persistent = true;
1029 
1030 	if ((ncode = param_write_float(plist, BJC_DEVINFO_VERSION,
1031 		&version)) < 0) {
1032 	    code = ncode;
1033 	}
1034 	if ((ncode = param_write_string(plist, BJC_DEVINFO_VERSIONSTRING,
1035 	    &versionString)) < 0) {
1036 	    code = ncode;
1037 	}
1038 
1039 	if ((ncode = param_write_bool(plist, BJC_DEVINFO_OUTPUTFACEUP,
1040 	    &bTrue)) < 0) {
1041 	    code = ncode;
1042  	}
1043     }
1044 
1045     return code;
1046 }
1047 
1048 /* Put properties for the bjc drivers. */
1049 
1050 private int
bjc_put_params(gx_device * pdev,gs_param_list * plist)1051 bjc_put_params(gx_device *pdev, gs_param_list *plist)
1052 {
1053     int bpp = 0, ccomps = 0;
1054 
1055     int code = 0;
1056     int ncode;
1057 
1058     bool aBool = true;
1059 
1060     const char* oname = (const char*) 0;
1061 
1062     bjc600_params new600Params;
1063     bjc800_params new800Params;
1064 
1065     bjc_params* params;
1066 
1067     gs_param_string pprocesscolors;
1068     gs_param_string pmedia;
1069     gs_param_string pquality;
1070 
1071     gs_param_float_array hwra;
1072 
1073     if (bjc->ptype != BJC800) {
1074 	new600Params = bjc600params;
1075 	params = (bjc_params*) &new600Params;
1076     } else {
1077 	new800Params = bjc800params;
1078 	params = (bjc_params*) &new800Params;
1079     }
1080 
1081     if ((code = cdj_put_param_int(plist, "BitsPerPixel",
1082 	&bpp, 1, 32, code)) != 1) {
1083         bpp = pdev->color_info.depth;
1084     }
1085 
1086     if ((code = put_param_string(plist, (unsigned char *)"ProcessColorModel",
1087 	&pprocesscolors, bjc_processColorsStrings, &ccomps, code)) != 1) {
1088         ccomps = pdev->color_info.num_components;
1089     }
1090 
1091     if ((ncode = param_read_bool(plist, oname = BJC_OPTION_MANUALFEED,
1092 	&params->manualFeed)) < 0) {
1093 	param_signal_error(plist, oname, code = ncode);
1094     }
1095 
1096     code = put_param_string(plist, (unsigned char *)BJC_OPTION_MEDIATYPE, &pmedia,
1097         bjc_mediaTypeStrings, &params->mediaType, code);
1098 
1099     code = cdj_put_param_int(plist, BJC_OPTION_PRINTCOLORS,
1100 	&params->printColors, 0, 15, code);
1101 
1102     code = put_param_string(plist, (unsigned char *)BJC_OPTION_PRINTQUALITY, &pquality,
1103 	(bjc->ptype == BJC800 ? bjc800_printQualityStrings :
1104 	bjc600_printQualityStrings), &params->printQuality, code);
1105 
1106     switch (ncode = param_read_int(plist,
1107 	oname = BJC_OPTION_MEDIAWEIGHT, &params->mediaWeight)) {
1108 	case 0:
1109 	    if (params->mediaWeight <= 0) {
1110 		ncode = gs_error_rangecheck;
1111 	    } else {
1112 		params->mediaWeight_isSet = 1;
1113 		break;
1114 	    }
1115 	    goto mwe;
1116 
1117 	default:
1118 	    if ((ncode = param_read_null(plist, oname)) == 0) {
1119 		params->mediaWeight_isSet = 0;
1120 		break;
1121 	    }
1122 mwe:   	    param_signal_error(plist, oname, code = ncode);
1123 
1124 	case 1:
1125 	    break;
1126     }
1127 
1128     if (bjc->ptype != BJC800) {
1129 	bjc600_params* params600 = (bjc600_params*) params;
1130 	if ((ncode = param_read_bool(plist,
1131 	    oname = BJC_OPTION_MONOCHROMEPRINT,
1132 	    &params600->monochromePrint)) < 0) {
1133 	    param_signal_error(plist, oname, code = ncode);
1134 	}
1135     }
1136 
1137     if ((ncode = cdj_param_check_float(plist, BJC_DEVINFO_VERSION,
1138 	bjcversion(pdev), true)) < 0) {
1139 	code = ncode;
1140     }
1141     if ((ncode = cdj_param_check_string(plist, BJC_DEVINFO_VERSIONSTRING,
1142 	bjcversionstring(pdev), true)) < 0) {
1143 	code = ncode;
1144     }
1145 
1146     if ((ncode = param_read_bool(plist, oname = BJC_DEVINFO_OUTPUTFACEUP,
1147 	&aBool)) < 0) {
1148 	param_signal_error(plist, oname, code = ncode);
1149     } else if (aBool != true) {
1150 	param_signal_error(plist, oname, code = ncode = gs_error_rangecheck);
1151     }
1152 
1153     /* Check for invalid resolution. The array macros are taken from
1154        gsdparam.c and modified to use oname, ncode and code instead
1155        of param_name, code and ecode respectively. */
1156 
1157     BEGIN_ARRAY_PARAM(param_read_float_array, "HWResolution", hwra, 2, hwre)
1158 	if ( hwra.data[0] <= 0 || hwra.data[1] <= 0 ||
1159 	     hwra.data[0] != hwra.data[1] )
1160 	    ncode = gs_error_rangecheck;
1161 	else {
1162 #ifdef BJC_STRICT
1163 	    if (hwra.data[0] != BJC_RESOLUTION_LOW &&
1164 		hwra.data[0] != BJC_RESOLUTION_NORMAL &&
1165 		hwra.data[0] != BJC_RESOLUTION_HIGH) {
1166 		ncode = gs_error_rangecheck;
1167 	    }
1168 #else
1169 	    /* A small hack for checking resolution without logarithms. */
1170 
1171 	    /**/ {
1172 		int n;
1173 
1174 		for (n = 0; n < 8 * sizeof(n) / BJC_RESOLUTION_BASE; ++n) {
1175 		    float res = (float)(BJC_RESOLUTION_BASE * (1 << n));
1176 
1177 		    if (res == hwra.data[0]) break;
1178 
1179 		    if (res > hwra.data[0]) {
1180 			ncode = gs_error_rangecheck;
1181 		    }
1182 		}
1183 
1184 		if (n == 8 * sizeof(n)) {
1185 		    ncode = gs_error_rangecheck;
1186 		}
1187 	    }
1188 #endif
1189 	    if (ncode < 0) {
1190 		code = ncode;
1191 	    } else {
1192 		break;
1193 	    }
1194 	}
1195     END_PARAM(hwra, hwre)
1196 
1197     if ((ncode = cdj_put_param_bpp(pdev, plist, bpp, bpp, ccomps)) < 0) {
1198 	code = ncode;
1199     }
1200 
1201     if (code < 0)
1202 	return code;
1203 
1204     if (bpp == 1) {
1205 	params->ditheringType = BJC_DITHER_NONE;
1206     }
1207 
1208     /* Write values that did change */
1209 
1210     if (bjc->ptype != BJC800) {
1211 	bjc600params = new600Params;
1212     } else {
1213 	bjc800params = new800Params;
1214     }
1215 
1216     return code;
1217 }
1218 
1219 /* ------ Internal routines ------ */
1220 
1221 /* The DeskJet500C can compress (mode 9) */
1222 private int
dj500c_print_page(gx_device_printer * pdev,FILE * prn_stream)1223 dj500c_print_page(gx_device_printer * pdev, FILE * prn_stream)
1224 {
1225   return hp_colour_print_page(pdev, prn_stream, DJ500C);
1226 }
1227 
1228 /* The DeskJet550C can compress (mode 9) */
1229 private int
dj550c_print_page(gx_device_printer * pdev,FILE * prn_stream)1230 dj550c_print_page(gx_device_printer * pdev, FILE * prn_stream)
1231 {
1232   return hp_colour_print_page(pdev, prn_stream, DJ550C);
1233 }
1234 
1235 /* The DesignJet650C can compress (mode 1) */
1236 private int
dnj650c_print_page(gx_device_printer * pdev,FILE * prn_stream)1237 dnj650c_print_page(gx_device_printer * pdev, FILE * prn_stream)
1238 {
1239   return hp_colour_print_page(pdev, prn_stream, DNJ650C);
1240 }
1241 
1242 private int
lj4dith_print_page(gx_device_printer * pdev,FILE * prn_stream)1243 lj4dith_print_page(gx_device_printer * pdev, FILE * prn_stream)
1244 {
1245   return hp_colour_print_page(pdev, prn_stream, LJ4DITH);
1246 }
1247 
1248 /* The PJXL300 can compress (modes 2 & 3) */
1249 private int
pjxl300_print_page(gx_device_printer * pdev,FILE * prn_stream)1250 pjxl300_print_page(gx_device_printer * pdev, FILE * prn_stream)
1251 { int ret_code;
1252   /* Ensure we're operating in PCL mode */
1253   fputs("\033%-12345X@PJL enter language = PCL\n", prn_stream);
1254   ret_code = hp_colour_print_page(pdev, prn_stream, PJXL300);
1255   /* Reenter switch-configured language */
1256   fputs("\033%-12345X", prn_stream);
1257   return ret_code;
1258 }
1259 
1260 /* The PaintJet XL can compress (modes 2 & 3) */
1261 private int
pjxl_print_page(gx_device_printer * pdev,FILE * prn_stream)1262 pjxl_print_page(gx_device_printer * pdev, FILE * prn_stream)
1263 {
1264   return hp_colour_print_page(pdev, prn_stream, PJXL180);
1265 }
1266 
1267 /* The PaintJet can compress (mode 1) */
1268 private int
pj_print_page(gx_device_printer * pdev,FILE * prn_stream)1269 pj_print_page(gx_device_printer * pdev, FILE * prn_stream)
1270 {
1271   return hp_colour_print_page(pdev, prn_stream, PJ180);
1272 }
1273 
1274 /* The LJ250 can compress (mode 1) */
1275 private int
declj250_print_page(gx_device_printer * pdev,FILE * prn_stream)1276 declj250_print_page(gx_device_printer * pdev, FILE * prn_stream)
1277 { int ret_code;
1278   fputs("\033%8", prn_stream);	/* Enter PCL emulation mode */
1279   ret_code = hp_colour_print_page(pdev, prn_stream, DECLJ250);
1280   fputs("\033%@", prn_stream);	/* Exit PCL emulation mode */
1281   return ret_code;
1282 }
1283 
1284 /* The BJC-600 cannot compress w/o raster image commands. */
1285 private int
escp_print_page(gx_device_printer * pdev,FILE * prn_stream)1286 escp_print_page(gx_device_printer * pdev, FILE * prn_stream)
1287 {
1288   return hp_colour_print_page(pdev, prn_stream, ESC_P);
1289 }
1290 
1291 /* The BJC-600 can compress w/ raster image commands. */
1292 private int
bjc_print_page(gx_device_printer * pdev,FILE * prn_stream)1293 bjc_print_page(gx_device_printer * pdev, FILE * prn_stream)
1294 {
1295   return hp_colour_print_page(pdev, prn_stream, bjc->ptype);
1296 }
1297 
1298 /* MACROS FOR DITHERING (we use macros for compact source and faster code) */
1299 /* Floyd-Steinberg dithering. Often results in a dramatic improvement in
1300  * subjective image quality, but can also produce dramatic increases in
1301  * amount of printer data generated and actual printing time!! Mode 9 2D
1302  * compression is still useful for fairly flat colour or blank areas but its
1303  * compression is much less effective in areas where the dithering has
1304  * effectively randomised the dot distribution. */
1305 
1306 #define SHIFT ((I * 8) - 13)
1307 #define RSHIFT ((I * 8) - 16)
1308 #define RANDOM (((rand() << RSHIFT) % (MAXVALUE / 2))  - MAXVALUE / 4);
1309 #define MINVALUE  0
1310 #define MAXVALUE  (255 << SHIFT)
1311 #define THRESHOLD (128 << SHIFT)
1312 #define C 8
1313 
1314 #define FSdither(inP, out, errP, Err, Bit, Offset, Element)\
1315 	oldErr = Err;\
1316 	Err = (errP[Element] + ((Err * 7 + C) >> 4) + ((int)inP[Element] << SHIFT));\
1317 	if (Err > THRESHOLD) {\
1318 	  out |= Bit;\
1319 	  Err -= MAXVALUE;\
1320 	}\
1321 	errP[Element + Offset] += ((Err * 3 + C) >> 4);\
1322 	errP[Element] = ((Err * 5 + oldErr + C) >> 4);
1323 
1324 /* Here we rely on compiler optimisation to remove lines of the form
1325  * (if (1 >= 4) {...}, ie. the constant boolean expressions */
1326 
1327 /* The original code is in the #else part. Since by default NEW_DITHER
1328    is not defined, the old code is used. No enhancement is visible for the
1329    bjc600 drivers with the new code, anyway :-( */
1330 
1331 #ifdef NEW_DITHER
1332 
1333 #define FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr, cP, mP, yP, kP, n)\
1334 {\
1335     if (scan == 0) {       /* going_up */\
1336       for (i = 0; i < plane_size; i++) {\
1337 	byte c, y, m, k, bitmask;\
1338 	int oldErr;\
1339 	bitmask = 0x80;\
1340 	for (c = m = y = k = 0; bitmask != 0; bitmask >>= 1) {\
1341 	  if (n >= 4) {\
1342 	      FSdither(dp, k, ep, kErr, bitmask, -n, 0);\
1343 	  }\
1344 	  if (n >= 3) {\
1345 	      FSdither(dp, c, ep, cErr, bitmask, -n, n - 3);\
1346 	      FSdither(dp, m, ep, mErr, bitmask, -n, n - 2);\
1347 	  }\
1348 	  FSdither(dp, y, ep, yErr, bitmask, -n, n - 1);\
1349 	  dp += n, ep += n;\
1350 	}\
1351 	if (n >= 4)\
1352 	  *kP++ = k;\
1353 	if (n >= 3) {\
1354 	  *cP++ = c;\
1355           *mP++ = m;\
1356 	}\
1357 	*yP++ = y;\
1358       }\
1359     } else {		/* going_down */\
1360       for (i = 0; i < plane_size; i++) {\
1361 	byte c, y, m, k, bitmask;\
1362 	int oldErr;\
1363 	bitmask = 0x01;\
1364 	for (c = m = y = k = 0; bitmask != 0; bitmask <<= 1) {\
1365           dp -= n, ep -= n;\
1366 	  FSdither(dp, y, ep, yErr, bitmask, n, n - 1);\
1367 	  if (n >= 3) {\
1368 	    FSdither(dp, m, ep, mErr, bitmask, n, n - 2);\
1369 	    FSdither(dp, c, ep, cErr, bitmask, n, n - 3);\
1370 	  }\
1371 	  if (n >= 4) {\
1372 	    FSdither(dp, k, ep, kErr, bitmask, n, 0);\
1373 	  }\
1374 	}\
1375 	*--yP = y;\
1376 	if (n >= 3)\
1377 	  { *--mP = m;\
1378 	    *--cP = c;\
1379 	  }\
1380 	if (n >= 4)\
1381 	  *--kP = k;\
1382       }\
1383     }\
1384 }
1385 
1386 #else
1387 
1388 #define FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr, cP, mP, yP, kP, n)\
1389 {\
1390     if (scan == 0) {       /* going_up */\
1391       for (i = 0; i < plane_size; i++) {\
1392 	byte c, y, m, k, bitmask;\
1393 	int oldErr;\
1394 	bitmask = 0x80;\
1395 	for (c = m = y = k = 0; bitmask != 0; bitmask >>= 1) {\
1396 	  if (n >= 4) {\
1397 	    if (*dp) {\
1398 	      FSdither(dp, k, ep, kErr, bitmask, -n, 0);\
1399 	      cErr = mErr = yErr = 0;\
1400 	    } else {\
1401 	      FSdither(dp, c, ep, cErr, bitmask, -n, n - 3);\
1402 	      FSdither(dp, m, ep, mErr, bitmask, -n, n - 2);\
1403 	      FSdither(dp, y, ep, yErr, bitmask, -n, n - 1);\
1404 	    }\
1405 	  } else {\
1406 	    if (n >= 3) {\
1407 	      FSdither(dp, c, ep, cErr, bitmask, -n, n - 3);\
1408 	      FSdither(dp, m, ep, mErr, bitmask, -n, n - 2);\
1409 	    }\
1410 	    FSdither(dp, y, ep, yErr, bitmask, -n, n - 1);\
1411 	  }\
1412 	  dp += n, ep += n;\
1413 	}\
1414 	if (n >= 4)\
1415 	  *kP++ = k;\
1416 	if (n >= 3) {\
1417 	  *cP++ = c;\
1418           *mP++ = m;\
1419 	}\
1420 	*yP++ = y;\
1421       }\
1422     } else {		/* going_down */\
1423       for (i = 0; i < plane_size; i++) {\
1424 	byte c, y, m, k, bitmask;\
1425 	int oldErr;\
1426 	bitmask = 0x01;\
1427 	for (c = m = y = k = 0; bitmask != 0; bitmask <<= 1) {\
1428           dp -= n, ep -= n;\
1429 	  if (n >= 4) {\
1430             if (*dp) {\
1431 	      FSdither(dp, k, ep, kErr, bitmask, n, 0);\
1432 	      cErr = mErr = yErr = 0;\
1433 	    } else {\
1434 	      FSdither(dp, y, ep, yErr, bitmask, n, n - 1);\
1435 	      FSdither(dp, m, ep, mErr, bitmask, n, n - 2);\
1436 	      FSdither(dp, c, ep, cErr, bitmask, n, n - 3);\
1437 	    }\
1438 	  } else {\
1439 	    FSdither(dp, y, ep, yErr, bitmask, n, n - 1);\
1440 	    if (n >= 3) {\
1441 	      FSdither(dp, m, ep, mErr, bitmask, n, n - 2);\
1442 	      FSdither(dp, c, ep, cErr, bitmask, n, n - 3);\
1443 	    }\
1444 	  }\
1445 	}\
1446 	*--yP = y;\
1447 	if (n >= 3)\
1448 	  { *--mP = m;\
1449 	    *--cP = c;\
1450 	  }\
1451 	if (n >= 4)\
1452 	  *--kP = k;\
1453       }\
1454     }\
1455 }
1456 
1457 #endif
1458 
1459 /* END MACROS FOR DITHERING */
1460 
1461 #define CPbit(inP, out, Bit, Element)\
1462   if (inP[Element]) {\
1463     out |= Bit;\
1464   }
1465 
1466 #define COPYline(scan, i, j, plane_size, cP, mP, yP, kP, n)\
1467 {\
1468     if (scan == 0) {       /* going_up */\
1469       for (i = 0; i < plane_size; i++) {\
1470 	byte c, y, m, k, bitmask;\
1471 	bitmask = 0x80;\
1472 	for (c = m = y = k = 0; bitmask != 0; bitmask >>= 1) {\
1473 	  if (n >= 4) {\
1474 	    CPbit(dp, k, bitmask, 0);\
1475 	  } \
1476           if (n >= 3) {\
1477 	    CPbit(dp, c, bitmask, n - 3);\
1478 	    CPbit(dp, m, bitmask, n - 2);\
1479 	  }\
1480 	  CPbit(dp, y, bitmask, n - 1);\
1481 	  dp += n, ep += n;\
1482 	}\
1483 	if (n >= 4)\
1484 	  *kP++ = k;\
1485 	if (n >= 3) {\
1486 	  *cP++ = c;\
1487           *mP++ = m;\
1488 	}\
1489 	*yP++ = y;\
1490       }\
1491     } else {		/* going_down */\
1492       for (i = 0; i < plane_size; i++) {\
1493 	byte c, y, m, k, bitmask;\
1494 	bitmask = 0x01;\
1495 	for (c = m = y = k = 0; bitmask != 0; bitmask <<= 1) {\
1496           dp -= n, ep -= n;\
1497 	  if (n >= 4) {\
1498             CPbit(dp, k, bitmask, 0);\
1499 	  }\
1500 	  if (n >= 3) {\
1501 	    CPbit(dp, m, bitmask, n - 2);\
1502 	    CPbit(dp, c, bitmask, n - 3);\
1503 	  }\
1504 	  CPbit(dp, y, bitmask, n - 1);\
1505 	}\
1506 	*--yP = y;\
1507 	if (n >= 3)\
1508 	  { *--mP = m;\
1509 	    *--cP = c;\
1510 	  }\
1511 	if (n >= 4)\
1512 	  *--kP = k;\
1513       }\
1514     }\
1515 }
1516 
1517 /* Some convenient shorthand .. */
1518 #define x_dpi        (pdev->x_pixels_per_inch)
1519 #define y_dpi        (pdev->y_pixels_per_inch)
1520 #define CONFIG_16BIT "\033*v6W\000\003\000\005\006\005"
1521 #define CONFIG_24BIT "\033*v6W\000\003\000\010\010\010"
1522 
1523 /* To calculate buffer size as next greater multiple of both parameter and W */
1524 #define calc_buffsize(a, b) (((((a) + ((b) * W) - 1) / ((b) * W))) * W)
1525 
1526 
1527 /*
1528  * Miscellaneous functions for Canon BJC-600 printers in raster command mode.
1529  */
1530 #define fputshort(n, f) fputc((n)%256,f);fputc((n)/256,f)
1531 
1532 private int
bjc_cmd(byte cmd,int argsize,byte * arg,gx_device_printer * pdev,FILE * f)1533 bjc_cmd(byte cmd, int argsize, byte* arg, gx_device_printer* pdev,
1534     FILE* f)
1535 {
1536   fputs("\033(", f);
1537   putc(cmd, f);
1538   fputshort(argsize, f);
1539   fwrite(arg, sizeof(byte), argsize, f);
1540 
1541   return 0;
1542 }
1543 
1544 
1545 private int
bjc_raster_cmd_sub(char c,int rastsize,byte * data,FILE * f)1546 bjc_raster_cmd_sub(char c, int rastsize, byte* data, FILE* f)
1547 {
1548   fputs("\033(A", f);
1549   fputshort(rastsize + 1, f);
1550   putc(c, f);
1551   fwrite(data, sizeof(byte), rastsize, f);
1552   putc('\015', f);
1553 
1554   return 0;
1555 }
1556 
1557 private int
bjc_raster_cmd(int c_id,int rastsize,byte * data,gx_device_printer * pdev,FILE * f)1558 bjc_raster_cmd(int c_id, int rastsize, byte* data, gx_device_printer* pdev,
1559     FILE* f)
1560 {
1561     if (bjcparams.printColors == BJC_COLOR_ALLBLACK) {
1562 	bjc_raster_cmd_sub('K', rastsize, data, f);
1563     } else if (pdev->color_info.num_components == 1) {
1564 	if (bjcparams.printColors & BJC_COLOR_BLACK) {
1565 	    bjc_raster_cmd_sub('K', rastsize, data, f);
1566 	} else {
1567 	    if (bjcparams.printColors & BJC_COLOR_YELLOW)
1568 		bjc_raster_cmd_sub('Y', rastsize, data, f);
1569 	    if (bjcparams.printColors & BJC_COLOR_MAGENTA)
1570 		bjc_raster_cmd_sub('M', rastsize, data, f);
1571 	    if (bjcparams.printColors & BJC_COLOR_CYAN)
1572 		bjc_raster_cmd_sub('C', rastsize, data, f);
1573 	}
1574     }else {			/* Color decomposition */
1575 	private byte ymckCodes[] = {
1576 	    BJC_COLOR_YELLOW,
1577 	    BJC_COLOR_MAGENTA,
1578 	    BJC_COLOR_CYAN,
1579 	    BJC_COLOR_BLACK,
1580 	};
1581 
1582 	if (bjcparams.printColors & (int) ymckCodes[c_id]) {
1583 	    bjc_raster_cmd_sub("YMCK"[c_id], rastsize, data, f);
1584 	}
1585     }
1586 
1587     return 0;
1588 }
1589 
1590 private int
bjc_init_page(gx_device_printer * pdev,FILE * f)1591 bjc_init_page(gx_device_printer* pdev, FILE* f)
1592 {
1593     byte pagemargins[3], resolution[4], paperloading[2];
1594 
1595     /* Compute page margins. */
1596 
1597     pagemargins[0] = (byte) ((float) pdev->height / pdev->y_pixels_per_inch
1598         * 10 + .5);
1599     pagemargins[1] = (byte) 1;
1600     pagemargins[2] = (byte) ((pdev->width / pdev->x_pixels_per_inch * 10) -
1601         pdev->HWMargins[0] / 7.2 - pdev->HWMargins[2] / 7.2 + .5);
1602 
1603     /* Cheat to keep margins into bounds (while waiting to have the right
1604        margins for big papers. */
1605 
1606     switch (bjc->ptype) {
1607 	case BJC800:
1608 	    if (pagemargins[2] > 114) pagemargins[2] = 114;
1609 	    break;
1610 
1611 	default:
1612 	    if (pagemargins[2] > 80) pagemargins[2] = 80;
1613 	    break;
1614     }
1615 
1616     /* Initialize resolution argument. */
1617 
1618     resolution[0] = (byte) ((int)pdev->y_pixels_per_inch / 256);
1619     resolution[1] = (byte) ((int)pdev->y_pixels_per_inch % 256);
1620     resolution[2] = (byte) ((int)pdev->x_pixels_per_inch / 256);
1621     resolution[3] = (byte) ((int)pdev->x_pixels_per_inch % 256);
1622 
1623     /* Initialize paper loading argument. */
1624 
1625     paperloading[0] = 0x10 + ((1 - bjcparams.manualFeed) << 2);
1626     paperloading[1] = bjcparams.mediaType << 4;
1627 
1628     /* Reinitialize printer in raster mode. */
1629 
1630     fputs("\033[K", f);
1631     fputshort(2, f);
1632     fputc(0x00, f);
1633     fputc(0x0f, f);
1634 
1635     /* Set page mode on (ignore data at end of page) */
1636 
1637     bjc_cmd('a', 1, (byte*) "\001", pdev, f);
1638 
1639     /* Set page margins */
1640 
1641     bjc_cmd('g', 3, pagemargins, pdev, f);
1642 
1643     /* Set compression on (this is PackBits compression a la TIFF/Mac) */
1644 
1645     bjc_cmd('b', 1, (byte*) "\001", pdev, f);
1646 
1647     /* Set paper loading. */
1648 
1649     bjc_cmd('l', 2, paperloading, pdev, f);
1650 
1651     /* Set printing method. */
1652 
1653 #ifndef BJC_INIT_800_AS_600
1654     if (bjc->ptype == BJC800) {
1655 #else
1656     if (0) {
1657 #endif
1658 	byte printmode[2];
1659 
1660 	printmode[0] = bjcparams.printQuality;
1661 
1662 	/* Modes not used are 3 (CN, Color Normal) and 2 (TP+ (?)) */
1663 
1664 	switch (bjcparams.printQuality) {
1665 	    case BJC_QUALITY_DRAFT:
1666 	        printmode[0] = 4;			/* Draft */
1667 		break;
1668 	}
1669 
1670 	printmode[1] = (bjcparams.mediaType >= BJC_MEDIA_ENVELOPE ? 1 :
1671 	    bjc800thickpaper());
1672 
1673 	bjc_cmd('c', 2, printmode, pdev, f);
1674     } else /* BJC600 */ {
1675 	byte printmeth[3];
1676 
1677 	printmeth[0] = 0x10 + ((1 - bjcparams.manualFeed) << 2);
1678 	printmeth[1] = (bjcparams.mediaType << 4) + bjcparams.printQuality;
1679 	printmeth[2] = (bjcparams.printQuality == BJC_QUALITY_HIGH ?
1680 	    0x10 : 0) + (bjcparams.mediaType >= BJC_MEDIA_ENVELOPE ? 1 :
1681 	         bjc600thickpaper());
1682 
1683     	bjc_cmd('c', 3, printmeth, pdev, f);
1684     }
1685 
1686     /* Set raster resolution */
1687 
1688     bjc_cmd('d', 4, resolution, pdev, f);
1689 
1690     return 0;
1691 }
1692 
1693 private int
1694 bjc_v_skip(int n, gx_device_printer* pdev, FILE* f)
1695 {
1696     if (n) {
1697 	fputs("\033(e", f);
1698 	putc(2, f);
1699 	putc(0, f);
1700 	putc(n / 256, f);
1701 	putc(n % 256, f);
1702     }
1703 
1704     return 0;
1705 }
1706 
1707 private int
1708 bjc_finish_page(gx_device_printer* pdev, FILE* f)
1709 {
1710     bjc_cmd('a', 1, (byte*) "\000", pdev, f);
1711     bjc_cmd('b', 1, (byte*) "\000", pdev, f);
1712     fputc('\014', f);
1713     fputs("\033@", f);
1714 
1715     return 0;
1716 }
1717 
1718 /* 1D runlength compression for BJC-600
1719  * this code is borrowed from gdevpcl.c:gdev_pcl_mode2compress.
1720  */
1721 private int
1722 bjc_compress(const byte *row, const byte *end_row, byte *compressed)
1723 {
1724   register const byte *exam = row;
1725   register byte *cptr = compressed; /* output pointer into compressed bytes */
1726 
1727 
1728   while ( exam < end_row ) {
1729     /* Search ahead in the input looking for a run */
1730     /* of at least 4 identical bytes. */
1731     const byte *compr = exam;
1732     const byte *end_dis;
1733     const byte *next;
1734     register byte test, test2;
1735 
1736     test = *exam;
1737     while ( exam < end_row ) {
1738       test2 = *++exam;
1739       if ( test == test2 )
1740 	  break;
1741       test = test2;
1742     }
1743 
1744 
1745     /* Find out how long the run is */
1746     end_dis = exam - 1;
1747     if ( exam == end_row ) { /* no run */
1748       next = --end_row;
1749     } else {
1750 
1751       next = exam + 1;
1752       while ( next < end_row && *next == test ) next++;
1753     }
1754 
1755 
1756     /* Now [compr..end_dis) should be encoded as dissimilar, */
1757     /* and [end_dis..next) should be encoded as similar. */
1758     /* Note that either of these ranges may be empty. */
1759 
1760 
1761     for ( ; ; ) {	/* Encode up to 128 dissimilar bytes */
1762       uint count = end_dis - compr; /* uint for faster switch */
1763       switch ( count ) { /* Use memcpy only if it's worthwhile. */
1764       case 6: cptr[6] = compr[5];
1765       case 5: cptr[5] = compr[4];
1766       case 4: cptr[4] = compr[3];
1767       case 3: cptr[3] = compr[2];
1768       case 2: cptr[2] = compr[1];
1769       case 1: cptr[1] = compr[0];
1770 	*cptr = count - 1;
1771 	cptr += count + 1;
1772       case 0: /* all done */
1773 	break;
1774       default:
1775 	if ( count > 128 ) count = 128;
1776 	*cptr++ = count - 1;
1777 	memcpy(cptr, compr, count);
1778 	cptr += count, compr += count;
1779 	continue;
1780       }
1781       break;
1782     }
1783 
1784 
1785     {	/* Encode up to 128 similar bytes. */
1786       /* Note that count may be <0 at end of row. */
1787       int count = next - end_dis;
1788       if (next < end_row || test != 0)
1789 	while ( count > 0 ) {
1790 
1791 	  int this = (count > 128 ? 128 : count);
1792 	  *cptr++ = 257 - this;
1793 	  *cptr++ = (byte)test;
1794 	  count -= this;
1795 	}
1796       exam = next;
1797     }
1798   }
1799   return cptr - compressed;
1800 }
1801 
1802 /*
1803  * For the ESC/P mode, resolution is fixed as 360dpi and we must transform
1804  * image data to serialized data.
1805  */
1806 private word *ep_storage;
1807 private uint ep_storage_size_words;
1808 private byte *ep_raster_buf[4][BJC_HEAD_ROWS], *ep_print_buf;
1809 private int ep_num_comps, ep_plane_size, img_rows=BJC_HEAD_ROWS;
1810 
1811 
1812 #define row_bytes (img_rows / 8)
1813 #define row_words (row_bytes / sizeof(word))
1814 #define min_rows (32)		/* for optimization of text image printing */
1815 
1816 
1817 private int
1818 ep_print_image(FILE *prn_stream, char cmd, byte *data, int size)
1819 {
1820   static int ln_idx=0, vskip1=0, vskip2=0, real_rows;
1821   int i;
1822   static const char color[4] = {4,1,2,0};
1823 
1824 
1825   switch (cmd) {
1826   case 3:			/* Black */
1827   case 2:			/* Cyan */
1828   case 1:			/* Magenta */
1829   case 0:			/* Yellow */
1830     memcpy(ep_raster_buf[((int) cmd)][ln_idx+vskip2], data, size);
1831     return 0;
1832   case 'B':			/* blank line skip */
1833     if (!ln_idx) {
1834       vskip1 += size;
1835     } else if (size >= img_rows - (ln_idx+vskip2) || ln_idx+vskip2 >= min_rows) {
1836       /* The 'I' cmd must precede 'B' cmd! */
1837       vskip2 += size;
1838       ep_print_image(prn_stream, 'F', 0, 0); /* flush and reset status */
1839     } else {
1840       vskip2 += size;
1841     }
1842     return 0;
1843   case 'I':			/* Increment index */
1844     ln_idx += vskip2 + 1;
1845     vskip2 = 0;
1846     if (ln_idx < img_rows) return 0;
1847     /* if ep_raster_buf filled up, then fall through here and flush buffer */
1848   case 'F':			/* flush print buffer */
1849     if (!ln_idx) return 0;	/* The end of the page. */
1850 
1851 
1852     /* before print the image, perform vertical skip. */
1853     while (vskip1 >= (255*2)) {
1854       fputs("\033J\377", prn_stream); /* n/180in. feeding */
1855       vskip1 -= (255*2);
1856     }
1857     if (vskip1 > 255) {
1858       fputs("\033J\200", prn_stream);
1859       vskip1 -= 256;
1860     }
1861     if (vskip1) {
1862       /* n/360in. feeding */
1863       fputs("\033|J", prn_stream); putc(0, prn_stream); putc(vskip1, prn_stream);
1864     }
1865 
1866 
1867     /* Optimize the number of nozzles to be used. */
1868     if (ln_idx > 56) {		/* use 64 nozzles */
1869       real_rows = 64;
1870     } else if (ln_idx > 48) {	/* use 56 nozzles */
1871       real_rows = 56;
1872     } else if (ln_idx > 32) {	/* use 48 nozzles */
1873       real_rows = 48;
1874     } else {			/* use 32 nozzles */
1875       real_rows = 32;
1876     }
1877 
1878 
1879     for (i = 0; i < ep_num_comps; i++) {
1880       int lnum, hskip, print_size, img_rows;
1881       byte *p0, *p1, *p2, *p3;
1882       byte *inp, *inbuf, *outp, *outbuf;
1883 
1884 
1885       img_rows = real_rows;	/* Note that this img_rows is not the one that
1886 				 * defined out of this function. */
1887       outbuf = ep_print_buf;
1888 
1889 
1890       /* Transpose raster image for serial printer image */
1891       for (lnum=0; lnum < img_rows; lnum+=8, outbuf++) {
1892 	inbuf = inp = ep_raster_buf[i][lnum];
1893 	for (outp = outbuf; inp < inbuf+ep_plane_size; inp++, outp += img_rows) {
1894 	  memflip8x8(inp, ep_plane_size, outp, row_bytes);
1895 	}
1896       }
1897 
1898 
1899       /* Set color */
1900       if (ep_num_comps == 1) {
1901 	/* Don't set color (to enable user setting). */
1902 	putc('\015', prn_stream);
1903       } else {
1904 	/* set color to one of CMYK. */
1905 	fputs("\015\033r", prn_stream);
1906 	putc(color[i], prn_stream);
1907       }
1908 
1909 
1910       *(outp = ep_print_buf + ep_plane_size * img_rows) = 1; /* sentinel */
1911 
1912 
1913       p0 = p3 = ep_print_buf;
1914 
1915 
1916       /* print image p0 to p1 and h skip p1 to p2 if p2<outp,
1917        * then make p0=p2 and continue */
1918       while (p0 < outp) {
1919 	static const word zeros[8] = {0,0,0,0,0,0,0,0};
1920 
1921 
1922 	if (p3 < outp) {
1923 	  /* p1 is the head of running zeros. */
1924 	  /* note that h skip unit is 1/180inch */
1925 	  for (p1 = p3; !memcmp(p3, zeros, row_bytes*2); p3 += row_bytes*2);
1926 	  /* p2 is the head of non zero image. */
1927 	  p2 = p3;
1928 	redo:
1929 	  for (p3 += row_bytes; memcmp(p3, zeros, row_bytes); p3 += row_bytes);
1930 	  if (p3 < outp && memcmp(p3+row_bytes, zeros, row_bytes)) goto redo;
1931 	} else p1 = p2 = outp;
1932 
1933 
1934 	if (p0 < p1) {	/* print the image between p0 and p1 */
1935 	  print_size = ((p1 < outp) ? p1 : outp) - p0;
1936 	  fputs("\033|B", prn_stream); putc(img_rows, prn_stream);
1937 	  fputshort(print_size, prn_stream);
1938 	  fwrite(p0, sizeof(byte), print_size, prn_stream);
1939 	}
1940 	if (p1 < p2) {	/* skip running zeros from p1 to p2 */
1941 	  hskip = (((p2 < outp) ? p2 : outp) - p1) / row_bytes / 2;
1942 	  fputs("\033\\", prn_stream);
1943 	  fputshort(hskip, prn_stream);
1944 	}
1945 	p0 = p2;
1946       }
1947     }
1948     return ep_print_image(prn_stream, 'R', 0, vskip2 + ln_idx);
1949   case 'R':			/* Reset status */
1950     ln_idx = 0;
1951     vskip1 = size;
1952     vskip2 = 0;
1953     memset(ep_storage, 0, ep_storage_size_words * W);
1954     return 0;
1955   default:			/* This should not happen */
1956     errprintf("ep_print_image: illegal command character `%c'.\n", cmd);
1957     return 1;
1958   }
1959 
1960 
1961   /* NOT REACHED */
1962 }
1963 
1964 
1965 /* Send the page to the printer.  Compress each scan line. */
1966 private int
1967 hp_colour_print_page(gx_device_printer * pdev, FILE * prn_stream, int ptype)
1968 {
1969   uint raster_width = gdev_prn_rasterwidth(pdev, 1);
1970 /*  int line_size = gdev_prn_rasterwidth(pdev, 0); */
1971   int line_size = gdev_prn_raster(pdev);
1972   int line_size_words = (line_size + W - 1) / W;
1973   int paper_size = gdev_pcl_paper_size((gx_device *)pdev);
1974   int num_comps = pdev->color_info.num_components;
1975   int bits_per_pixel = pdev->color_info.depth;
1976   int storage_bpp = bits_per_pixel;
1977   int expanded_bpp = bits_per_pixel;
1978   int plane_size, databuff_size;
1979   int combined_escapes = 1;
1980   int errbuff_size = 0;
1981   int outbuff_size = 0;
1982   int compression = 0;
1983   int scan = 0;
1984   int *errors[2];
1985   const char *cid_string = (const char*) 0;
1986   byte *data[4], *plane_data[4][4], *out_data;
1987   byte *out_row, *out_row_alt;
1988   word *storage;
1989   uint storage_size_words;
1990 
1991   /* Tricks and cheats ... */
1992   switch (ptype) {
1993   case DJ550C:
1994     if (num_comps == 3 && !cprn_device->cmyk)
1995       num_comps = 4;                      /* 4-component printing */
1996     break;
1997   case ESC_P:
1998     if (bits_per_pixel == 24)	/* prefer 3-component printing for bpp=24. */
1999       num_comps = 3;
2000     else
2001       if (num_comps != 1)
2002         num_comps = 4;
2003     break;
2004   case PJXL300:
2005   case PJXL180:
2006     if (pjxl->rendertype > 0) {
2007       if (bits_per_pixel < 16)
2008 	pjxl->rendertype = 0;
2009       else {
2010 	/* Control codes for CID sequence */
2011 	cid_string = (bits_per_pixel == 16) ? CONFIG_16BIT : CONFIG_24BIT;
2012 	/* Pretend we're a monobit device so we send the data out unchanged */
2013 	bits_per_pixel = storage_bpp = expanded_bpp = 1;
2014 	num_comps = 1;
2015       }
2016     }
2017     break;
2018   }
2019 
2020   if (cprn_device->cmyk <= 0) {
2021       if (storage_bpp == 8 && num_comps >= 3)
2022 	  bits_per_pixel = expanded_bpp = 3;	/* Only 3 bits of each byte used */
2023   }
2024 
2025   plane_size = calc_buffsize(line_size, storage_bpp);
2026   ep_plane_size = plane_size;
2027 
2028   if (bits_per_pixel == 1) {		/* Data printed direct from i/p */
2029     databuff_size = 0;			/* so no data buffer required, */
2030     outbuff_size = plane_size * 4;	/* but need separate output buffers */
2031   }
2032 
2033   if (bits_per_pixel > 4) {		/* Error buffer for FS dithering */
2034     storage_bpp = expanded_bpp =
2035       num_comps * 8;			/* 8, 24 or 32 bits */
2036 
2037     if (cprn_device->cmyk > 0) {	/* Use CMYK dithering algorithm. */
2038 	errbuff_size = 4 * (5 + 1 + 1 + line_size + 1 + 2) * I;
2039     } else {			/* Use original (RGB) dithering. */
2040 	errbuff_size =			/* 4n extra values for line ends */
2041 	    calc_buffsize((plane_size * expanded_bpp + num_comps * 4) * I, 1);
2042     }
2043   }
2044 
2045   databuff_size = plane_size * storage_bpp;
2046 
2047   storage_size_words = ((plane_size + plane_size) * num_comps +
2048 			databuff_size + errbuff_size + outbuff_size) / W;
2049 
2050   storage = (ulong *) gs_malloc(pdev->memory, storage_size_words, W, "hp_colour_print_page");
2051   ep_storage_size_words = (plane_size * (num_comps + 1)) / W * img_rows
2052       + 16;			/* Redundant space for sentinel and aligning. */
2053   ep_storage = (word *) gs_malloc(pdev->memory, ep_storage_size_words, W, "ep_print_buffer");
2054 
2055   /*
2056    * The principal data pointers are stored as pairs of values, with
2057    * the selection being made by the 'scan' variable. The function of the
2058    * scan variable is overloaded, as it controls both the alternating
2059    * raster scan direction used in the Floyd-Steinberg dithering and also
2060    * the buffer alternation required for line-difference compression.
2061    *
2062    * Thus, the number of pointers required is as follows:
2063    *
2064    *   errors:      2  (scan direction only)
2065    *   data:        4  (scan direction and alternating buffers)
2066    *   plane_data:  4  (scan direction and alternating buffers)
2067    */
2068 
2069   if (storage == 0 || ep_storage == 0) /* can't allocate working area */
2070     return_error(gs_error_VMerror);
2071   else {
2072     int i, j;
2073     byte *p = out_data = out_row = (byte *)storage;
2074     byte *ep_p = (byte *)ep_storage;
2075     data[0] = data[1] = data[2] = p;
2076     data[3] = p + databuff_size;
2077     out_row_alt = out_row + plane_size * 2;
2078     if (bits_per_pixel > 1) {
2079       p += databuff_size;
2080     }
2081     if (bits_per_pixel > 4) {
2082       errors[0] = (int *)p + num_comps * 2;
2083       errors[1] = errors[0] + databuff_size;
2084       p += errbuff_size;
2085     }
2086     for (i = 0; i < num_comps; i++) {
2087       plane_data[0][i] = plane_data[2][i] = p;
2088       p += plane_size;
2089     }
2090     for (i = 0; i < num_comps; i++) {
2091       plane_data[1][i] = p;
2092       plane_data[3][i] = p + plane_size;
2093       p += plane_size;
2094     }
2095     if (bits_per_pixel == 1) {
2096       out_data = out_row = p;	  /* size is outbuff_size * 4 */
2097       out_row_alt = out_row + plane_size * 2;
2098       data[1] += databuff_size;   /* coincides with plane_data pointers */
2099       data[3] += databuff_size;
2100     }
2101     for (i = 0; i < num_comps; i++) {
2102       for (j = 0; j < img_rows; j++) {
2103 	ep_raster_buf[i][j] = ep_p;
2104 	ep_p += plane_size;
2105       }
2106       /* Make a sentinel and align to word size.  */
2107       ep_print_buf = (byte *)((word)(ep_p + sizeof(word)) & ~(sizeof(word)-1));
2108     }
2109     ep_num_comps = num_comps;
2110   }
2111 
2112   /* Initialize printer. */
2113   if (ptype == BJC600 || ptype == BJC800) {
2114     bjc_init_page(pdev, prn_stream);
2115   } else {
2116       if (ptype == LJ4DITH)  {
2117 	  fputs("\033*rB", prn_stream);
2118       } else {
2119 	  fputs("\033*rbC", prn_stream);                   /* End raster graphics */
2120       }
2121       fprintf(prn_stream, "\033*t%dR", (int)x_dpi);
2122   /* Set resolution */
2123   }
2124 
2125   /* Clear temp storage */
2126   memset(storage, 0, storage_size_words * W);
2127 
2128 #define DOFFSET (dev_t_margin(pdev) - DESKJET_PRINT_LIMIT)	/* Print position */
2129 #define POFFSET (dev_t_margin(pdev) - PAINTJET_PRINT_LIMIT)
2130 #define EOFFSET (dev_t_margin(pdev) - ESC_P_PRINT_LIMIT)
2131 #define BOFFSET (dev_t_margin(pdev) - bjc->printLimit)
2132   switch (ptype) {
2133   case LJ4DITH:
2134     /* Page size, orientation, top margin & perforation skip */
2135     fprintf(prn_stream, "\033&l26A\033&l0o0e0L\033*r0F" );
2136     fprintf(prn_stream, "\033*p0x0Y" ); /* These Offsets are hacked ! */
2137     fprintf(prn_stream, "\033&u600D\033*r1A" );
2138     /* Select data compression */
2139     compression = 3;
2140     combined_escapes = 0;
2141     break;
2142   case DJ500C:
2143   case DJ550C:
2144     /* Page size, orientation, top margin & perforation skip */
2145     fprintf(prn_stream, "\033&l%daolE", paper_size);
2146     /* Set depletion and shingling levels */
2147     fprintf(prn_stream, "\033*o%dd%dQ", cdj->depletion, cdj->shingling);
2148     /* Move to top left of printed area */
2149     fprintf(prn_stream, "\033*p%dY", (int)(300 * DOFFSET));
2150     /* Set number of planes ((-)1 is mono, (-)3 is (cmy)rgb, -4 is cmyk),
2151      * and raster width, then start raster graphics */
2152     fprintf(prn_stream, "\033*r%ds-%du0A", raster_width, num_comps);
2153     /* Select data compression */
2154     compression = 9;
2155     break;
2156   case DNJ650C:
2157     if (pdev->x_pixels_per_inch == 600) {
2158         /* set resolution to 600dpi 1st through PJL command */
2159         fprintf(prn_stream,"\033%%-12345X@PJL SET RESOLUTION = 600\n");
2160     }
2161     fprintf (prn_stream, "\033%%0B"); /* Enter HPGL/2 mode */
2162     fprintf (prn_stream, "BP5,1"); /* Turn off autorotation */
2163     fprintf (prn_stream, "PS%d,%d",
2164 	     (int)((pdev->height/pdev->y_pixels_per_inch)*1016),
2165 	     (int)((pdev->width/pdev->x_pixels_per_inch)*1016)); /* Set length/width of page */
2166     fprintf (prn_stream, "PU"); /* Pen up */
2167     fprintf (prn_stream, "PA%d,%d", 0, 0); /* Move pen to upper-left */
2168     fprintf (prn_stream, "\033%%1A"); /* Enter HP-RTL mode */
2169     fprintf (prn_stream, "\033&a1N"); /* No negative motion - allow plotting
2170 						while receiving */
2171     if (pdev->x_pixels_per_inch == 600)
2172         fprintf (prn_stream, "\033*t600R"); /* request 600dpi via HP RTL */
2173     { static const char temp[] = {
2174         033, '*', 'v', '6', 'W',
2175 	000 /* color model */,
2176 	000 /* pixel encoding mode */,
2177 	003 /* number of bits per index */,
2178 	010 /* bits red */,
2179 	010 /* bits green */,
2180 	010 /* bits blue */
2181       };
2182       fwrite (temp, 1, sizeof(temp), prn_stream);
2183     }
2184 
2185     /* Set raster width */
2186     fprintf(prn_stream, "\033*r%dS", raster_width);
2187     /* Start raster graphics */
2188     fprintf(prn_stream, "\033*r1A");
2189 
2190     /* Select data compression */
2191     compression = 1;
2192     /* No combined escapes for raster transfers */
2193     combined_escapes = 0;
2194     break;
2195   case PJXL300:
2196     /* Page size, orientation, top margin & perforation skip */
2197     fprintf(prn_stream, "\033&l%daolE", paper_size);
2198     /* Set no-negative-motion mode, for faster (unbuffered) printing */
2199     fprintf(prn_stream, "\033&a1N");
2200     /* Set print quality */
2201     fprintf(prn_stream, "\033*o%dQ", pjxl->printqual);
2202     /* Move to top left of printed area */
2203     fprintf(prn_stream, "\033*p%dY", (int)(300 * POFFSET));
2204     /* Configure colour setup */
2205     if (pjxl->rendertype > 0) {
2206       /* Set render type */
2207       fprintf(prn_stream, "\033*t%dJ", pjxl->rendertype);
2208       /* Configure image data */
2209       fputs(cid_string, prn_stream);
2210       /* Set raster width, then start raster graphics */
2211       fprintf(prn_stream, "\033*r%ds1A", raster_width);
2212     } else {
2213       /* Set number of planes (1 is mono, 3 is rgb),
2214        * and raster width, then start raster graphics */
2215       fprintf(prn_stream, "\033*r%ds-%du0A", raster_width, num_comps);
2216     }
2217     /* No combined escapes for raster transfers */
2218     combined_escapes = 0;
2219     break;
2220   case PJXL180:
2221     /* Page size, orientation, top margin & perforation skip */
2222     fprintf(prn_stream, "\033&l%daolE", paper_size);
2223     /* Set print quality */
2224     fprintf(prn_stream, "\033*o%dQ", pjxl->printqual);
2225     /* Move to top left of printed area */
2226     fprintf(prn_stream, "\033*p%dY", (int)(180 * POFFSET));
2227     /* Configure colour setup */
2228     if (pjxl->rendertype > 0) {
2229       /* Set render type */
2230       fprintf(prn_stream, "\033*t%dJ", pjxl->rendertype);
2231       /* Configure image data */
2232       fputs(cid_string, prn_stream);
2233       /* Set raster width, then start raster graphics */
2234       fprintf(prn_stream, "\033*r%ds1A", raster_width);
2235     } else {
2236       /* Set number of planes (1 is mono, 3 is rgb),
2237        * and raster width, then start raster graphics */
2238       fprintf(prn_stream, "\033*r%ds%du0A", raster_width, num_comps);
2239     }
2240     break;
2241   case PJ180:
2242   case DECLJ250:
2243     /* Disable perforation skip */
2244     fprintf(prn_stream, "\033&lL");
2245     /* Move to top left of printed area */
2246     fprintf(prn_stream, "\033&a%dV", (int)(720 * POFFSET));
2247     /* Set number of planes (1 is mono, 3 is rgb),
2248      * and raster width, then start raster graphics */
2249     fprintf(prn_stream, "\033*r%ds%du0A", raster_width, num_comps);
2250     if (ptype == DECLJ250) {
2251       /* No combined escapes for raster transfers */
2252       combined_escapes = 0;
2253       /* From here on, we're a standard Paintjet .. */
2254       ptype = PJ180;
2255     }
2256     /* Select data compression */
2257     compression = 1;
2258     break;
2259   case ESC_P:
2260     /* Move to top left of printed area (must be modified for large movement(YK))*/
2261     if ((int)(EOFFSET*360)) fprintf(prn_stream, "\033|J%c%c", 0, (int)(360*EOFFSET));
2262     combined_escapes = 0;
2263     break;
2264   case BJC600:
2265   case BJC800:
2266     /* Move to top left of printed area */
2267     bjc_v_skip((int)(pdev->HWResolution[1] * BOFFSET), pdev, prn_stream);
2268     combined_escapes = 0;
2269     compression = 2;		/* BJC600 uses the same method as mode 2 compression */
2270     break;
2271   }
2272 
2273   /* Unfortunately, the Paintjet XL300 PCL interpreter introduces a
2274    * version of the PCL language which is different to all earlier HP
2275    * colour and mono inkjets, in that it loses the very useful ability
2276    * to use combined escape sequences with the raster transfer
2277    * commands. In this respect, it is incompatible even with the older
2278    * 180 dpi PaintJet and PaintJet XL printers!  Another regrettable
2279    * omission is that 'mode 9' compression is not supported, as this
2280    * mode can give both computational and PCL file size advantages. */
2281 
2282   if (combined_escapes) {
2283     /* From now on, all escape commands start with \033*b, so we
2284      * combine them (if the printer supports this). */
2285     fputs("\033*b", prn_stream);
2286      /* Set compression if the mode has been defined. */
2287     if (compression)
2288       fprintf(prn_stream, "%dm", compression);
2289   }
2290   else if (ptype == BJC600 || ptype == BJC800)
2291       ;				/* Currently, nothing to do. */
2292   else
2293     if (compression)
2294       fprintf(prn_stream, "\033*b%dM", compression);
2295 
2296   /* Send each scan line in turn */
2297   {
2298     int cErr, mErr, yErr, kErr;
2299     int this_pass, lnum, i;
2300     int start_rows;
2301     int lend, num_blank_lines = 0;
2302 
2303     word rmask = ~(word) 0 << ((-pdev->width * storage_bpp) & (W * 8 - 1));
2304 
2305     lend = pdev->height -
2306 	(int)((dev_t_margin(pdev) + dev_b_margin(pdev)) * y_dpi);
2307 
2308     switch (ptype) {
2309 	case BJC600:
2310 	case BJC800:
2311 	    start_rows = BJC_HEAD_ROWS;
2312 	    break;
2313 
2314 	/* Inhibit blank line printing for RGB-only printers, since in
2315 	 * this case 'blank' means black!  Also disabled for XL300 due to
2316 	 * an obscure bug in the printer's firmware */
2317 
2318 	case PJ180:
2319 	case PJXL180:
2320 	case PJXL300:
2321 	    start_rows = -1;
2322 	    break;
2323 
2324 	default:
2325 	    start_rows = (num_comps == 1) ? HEAD_ROWS_MONO - 1 :
2326 		HEAD_ROWS_COLOUR - 1;
2327 	    break;
2328     }
2329 
2330     cErr = mErr = yErr = kErr = 0;
2331 
2332     if (bits_per_pixel > 4) { /* Randomly seed initial error buffer */
2333       if (cprn_device->cmyk > 0 && expanded_bpp == 32) {
2334 	  bjc_fscmyk(data, plane_data, errors, plane_size, -1);
2335       } else {
2336 	  int *ep = errors[0];
2337 	  for (i = 0; i < databuff_size; i++) {
2338 	      *ep++ = RANDOM;
2339 	  }
2340       }
2341     }
2342 
2343     this_pass = start_rows;
2344     for (lnum = 0; lnum < lend; lnum++) {
2345       word *data_words = (word *)data[scan];
2346       register word *end_data = data_words + line_size_words;
2347 
2348       gdev_prn_copy_scan_lines(pdev, lnum, data[scan], line_size);
2349 
2350       /* Mask off 1-bits beyond the line width. */
2351       end_data[-1] &= rmask;
2352 
2353       /* Remove trailing 0s. */
2354       while (end_data > data_words && end_data[-1] == 0)
2355 	end_data--;
2356       if (ptype != DNJ650C)	/* DesignJet can't skip blank lines ? ? */
2357 	if (end_data == data_words) {	/* Blank line */
2358 	  num_blank_lines++;
2359 	  continue;
2360 	}
2361       /* Skip blank lines if any */
2362       if (num_blank_lines > 0) {
2363 	if (ptype == ESC_P) {
2364 	  ep_print_image(prn_stream, 'B', 0, num_blank_lines);
2365 	} else if (ptype == BJC600 || ptype == BJC800) {
2366 	    bjc_v_skip(num_blank_lines, pdev, prn_stream);
2367 	} else if (num_blank_lines < this_pass) {
2368 	  /* Moving down from current position
2369 	   * causes head motion on the DeskJets, so
2370 	   * if the number of lines is within the
2371 	   * current pass of the print head, we're
2372 	   * better off printing blanks. */
2373 	  this_pass -= num_blank_lines;
2374 	  if (combined_escapes) {
2375 	    fputc('y', prn_stream);   /* Clear current and seed rows */
2376 	    for (; num_blank_lines; num_blank_lines--)
2377 	      fputc('w', prn_stream);
2378 	  } else {
2379 #if 0
2380 /**************** The following code has been proposed ****************/
2381 /**************** as a replacement: ****************/
2382 	    fputs("\033*b1Y", prn_stream);   /* Clear current and seed rows */
2383 	    if ( num_blank_lines > 1 )
2384 	      fprintf(prn_stream, "\033*b%dY", num_blank_lines - 1);
2385 	    num_blank_lines = 0;
2386 #else
2387 	    fputs("\033*bY", prn_stream);   /* Clear current and seed rows */
2388 	    if (ptype == DNJ650C) {
2389 	      fprintf (prn_stream, "\033*b%dY", num_blank_lines);
2390 	      num_blank_lines = 0;
2391 	    }
2392 	    else {
2393 	      for (; num_blank_lines; num_blank_lines--)
2394 	        fputs("\033*bW", prn_stream);
2395 	    }
2396 #endif
2397 	  }
2398 	} else {
2399 	  if (combined_escapes)
2400 	    fprintf(prn_stream, "%dy", num_blank_lines);
2401 	  else
2402 	    fprintf(prn_stream, "\033*b%dY", num_blank_lines);
2403 	}
2404 	memset(plane_data[1 - scan][0], 0, plane_size * num_comps);
2405 	num_blank_lines = 0;
2406 	this_pass = start_rows;
2407       }
2408       {			/* Printing non-blank lines */
2409 	register byte *kP = plane_data[scan + 2][3];
2410 	register byte *cP = plane_data[scan + 2][2];
2411 	register byte *mP = plane_data[scan + 2][1];
2412 	register byte *yP = plane_data[scan + 2][0];
2413 	register byte *dp = data[scan + 2];
2414 	register int *ep = errors[scan];
2415 	int zero_row_count;
2416 	int i, j;
2417 	byte *odp;
2418 
2419 	if (this_pass)
2420 	  this_pass--;
2421 	else
2422 	  this_pass = start_rows;
2423 
2424 	if (expanded_bpp > bits_per_pixel) {  /* Expand line if required */
2425 	    cdj_expand_line(data_words, line_size,
2426 		cprn_device->cmyk,
2427 	        bits_per_pixel, expanded_bpp);
2428 	}
2429 
2430 	/* In colour modes, we have some bit-shuffling to do before
2431 	 * we can print the data; in FS mode we also have the
2432 	 * dithering to take care of. */
2433 	switch (expanded_bpp) {    /* Can be 1, 3, 8, 24 or 32 */
2434 	case 3:
2435 	  /* Transpose the data to get pixel planes. */
2436 	  for (i = 0, odp = plane_data[scan][0]; i < databuff_size;
2437 	       i += 8, odp++) {	/* The following is for 16-bit
2438 				 * machines */
2439 #define spread3(c)\
2440     { 0, c, c*0x100, c*0x101, c*0x10000L, c*0x10001L, c*0x10100L, c*0x10101L }
2441 	    static ulong spr40[8] = spread3(0x40);
2442 	    static ulong spr08[8] = spread3(8);
2443 	    static ulong spr02[8] = spread3(2);
2444 	    register byte *dp = data[scan] + i;
2445 	    register ulong pword =
2446 	    (spr40[dp[0]] << 1) +
2447 	    (spr40[dp[1]]) +
2448 	    (spr40[dp[2]] >> 1) +
2449 	    (spr08[dp[3]] << 1) +
2450 	    (spr08[dp[4]]) +
2451 	    (spr08[dp[5]] >> 1) +
2452 	    (spr02[dp[6]]) +
2453 	    (spr02[dp[7]] >> 1);
2454 	    odp[0] = (byte) (pword >> 16);
2455 	    odp[plane_size] = (byte) (pword >> 8);
2456 	    odp[plane_size * 2] = (byte) (pword);
2457 	  }
2458 	  break;
2459 
2460 	case 8:
2461 	  switch (ptype) {
2462 	      case BJC600:
2463 	      case BJC800:
2464 	          if (bjcparams.ditheringType == BJC_DITHER_NONE) {
2465 		      COPYline(scan, i, j, plane_size, cP, mP, yP, kP, 1);
2466 		      break;
2467 		  }
2468 
2469 	      default:
2470 		  FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr,
2471 			  cP, mP, yP, kP, 1);
2472 	  }
2473 	  break;
2474 	case 24:
2475 	  FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr,
2476 		  cP, mP, yP, kP, 3);
2477 	  break;
2478 	case 32:
2479 	  if (cprn_device->cmyk > 0) {
2480 	      bjc_fscmyk(data, plane_data, errors, plane_size, scan);
2481 	  } else {
2482 	      FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr,
2483 		      cP, mP, yP, kP, 4);
2484 	  }
2485 	  break;
2486 
2487 	} /* switch(expanded_bpp) */
2488 
2489 	/* Make sure all black is in the k plane */
2490 
2491 	if (num_comps == 4 && (cprn_device->cmyk <= 0 || expanded_bpp != 32)) {
2492 	    register word *kp = (word *)plane_data[scan][3];
2493 	    register word *cp = (word *)plane_data[scan][2];
2494 	    register word *mp = (word *)plane_data[scan][1];
2495 	    register word *yp = (word *)plane_data[scan][0];
2496 	    if (bits_per_pixel > 4) {  /* Done as 4 planes */
2497 		for (i = 0; i < plane_size / W; i++) {
2498 		    word bits = *cp & *mp & *yp;
2499 		    *kp++ |= bits;
2500  		    bits = ~bits;
2501 		    *cp++ &= bits;
2502 		    *mp++ &= bits;
2503 		    *yp++ &= bits;
2504 		}
2505 	    } else {  /* This has really been done as 3 planes */
2506 		for (i = 0; i < plane_size / W; i++) {
2507 		    word bits = *cp & *mp & *yp;
2508 		    *kp++ = bits;
2509 		    bits = ~bits;
2510 		    *cp++ &= bits;
2511 		    *mp++ &= bits;
2512 		    *yp++ &= bits;
2513 		}
2514 	    }
2515 	}
2516 
2517 	/* Transfer raster graphics in the order (K), C, M, Y */
2518 
2519 	for (zero_row_count = 0, i = num_comps - 1; i >= 0; i--) {
2520 	  int output_plane = 1;
2521 	  int out_count = 0;
2522 
2523 	  switch (ptype) {
2524 	  case DJ500C:    /* Always compress using mode 9 */
2525 	  case DJ550C:
2526 	    out_count = gdev_pcl_mode9compress(plane_size,
2527 					       plane_data[scan][i],
2528 					       plane_data[1 - scan][i],
2529 					       out_data);
2530 
2531 	    /* This optimisation allows early termination of the
2532 	     * row, but this doesn't work correctly in an alternating
2533 	     * mode 2 / mode 3 regime, so we only use it with mode 9
2534 	     * compression */
2535            if (out_count == 0)
2536              { output_plane = 0;      /* No further output for this plane */
2537                if (i == 0)
2538                  fputc('w', prn_stream);
2539                else
2540                  zero_row_count++;
2541              }
2542            else
2543              { for (; zero_row_count; zero_row_count--)
2544                  fputc('v', prn_stream);
2545              }
2546 	    break;
2547 	  case PJ180:
2548 	  case DNJ650C:
2549 	    if (num_comps > 1)
2550 	      { word *wp = (word *)plane_data[scan][i];
2551 		for (j = 0; j < plane_size / W; j++, wp++)
2552 		  *wp = ~*wp;
2553 	      }
2554 	    out_count = gdev_pcl_mode1compress((const byte *)
2555 					       plane_data[scan][i],
2556 					       (const byte *)
2557 					       plane_data[scan][i] + plane_size - 1,
2558 					       out_data);
2559 	    break;
2560 	  case PJXL180:    /* Need to invert data as CMY not supported */
2561 	    if (num_comps > 1)
2562 	      { word *wp = (word *)plane_data[scan][i];
2563 		for (j = 0; j < plane_size / W; j++, wp++)
2564 		  *wp = ~*wp;
2565 	      }
2566 	    /* fall through .. */
2567 	  case PJXL300:     /* Compression modes 2 and 3 are both
2568 			     * available.  Try both and see which one
2569 			     * produces the least output data. */
2570 	  case LJ4DITH:
2571 	    { const byte *plane = plane_data[scan][i];
2572 	      byte *prev_plane = plane_data[1 - scan][i];
2573 	      const word *row = (word *)plane;
2574 	      const word *end_row = row + plane_size/W;
2575 	      int count2 = gdev_pcl_mode2compress(row, end_row, out_row_alt);
2576 	      int count3 = gdev_pcl_mode3compress(plane_size, plane, prev_plane, out_row);
2577 	      int penalty = combined_escapes ? strlen("#m") : strlen("\033*b#M");
2578 	      int penalty2 = (compression == 2 ? 0 : penalty);
2579 	      int penalty3 = (compression == 3 ? 0 : penalty);
2580 
2581 	      if (count3 + penalty3 < count2 + penalty2)
2582 		{ if ( compression != 3 ) {
2583 		    if (combined_escapes)
2584 		      fputs("3m", prn_stream);
2585 		    else
2586 		      fputs("\033*b3M", prn_stream);
2587 		    compression = 3;
2588 		  }
2589 		  out_data = out_row;
2590 		  out_count = count3;
2591 		}
2592 	      else
2593 		{ if ( compression != 2 ) {
2594 		    if (combined_escapes)
2595 		      fputs("2m", prn_stream);
2596 		    else
2597 		      fputs("\033*b2M", prn_stream);
2598 		    compression = 2;
2599 		  }
2600 		  out_data = out_row_alt;
2601 		  out_count = count2;
2602 		}
2603 	    }
2604 	    break;
2605 	  case BJC600:
2606 	  case BJC800:
2607 	    { const byte *plane = (byte *)plane_data[scan][i];
2608 	      int count2 = bjc_compress(plane, plane + plane_size, out_row_alt);
2609 
2610  	      out_data = out_row_alt;
2611 	      out_count = count2;
2612 	    }
2613 	    break;
2614 	  }
2615 	  if (output_plane) {
2616 	    if (combined_escapes)
2617 	      fprintf(prn_stream, "%d%c", out_count, "wvvv"[i]);
2618 	    else if (ptype == BJC600 || ptype == BJC800) {
2619 	      if (out_count)
2620 		  bjc_raster_cmd(num_comps == 1 ? 3 : i,
2621 				out_count, out_data, pdev, prn_stream);
2622 	      if (i == 0) bjc_v_skip(1, pdev, prn_stream);
2623 	    } else if (ptype == ESC_P)
2624 		ep_print_image(prn_stream, (char)i, plane_data[scan][i], plane_size);
2625 	    else
2626 	      fprintf(prn_stream, "\033*b%d%c", out_count, "WVVV"[i]);
2627 	    if (ptype < ESC_P)
2628 	      fwrite(out_data, sizeof(byte), out_count, prn_stream);
2629 	  }
2630 
2631 	} /* Transfer Raster Graphics ... */
2632 	if (ptype == ESC_P)
2633 	    ep_print_image(prn_stream, 'I', 0, 0); /* increment line index */
2634 	scan = 1 - scan;          /* toggle scan direction */
2635       }	  /* Printing non-blank lines */
2636     }     /* for lnum ... */
2637   }       /* send each scan line in turn */
2638 
2639   if (combined_escapes)
2640     fputs("0M", prn_stream);
2641 
2642   /* end raster graphics */
2643   if (ptype == BJC600 || ptype == BJC800) {
2644     bjc_finish_page(pdev, prn_stream);
2645   }
2646   else if (ptype != ESC_P)
2647     fputs("\033*rbC\033E", prn_stream);
2648 
2649   /* eject page */
2650   if (ptype == PJ180)
2651     fputc('\f', prn_stream);
2652   else if (ptype == DNJ650C)
2653     fputs ("\033*rC\033%0BPG;", prn_stream);
2654   else if (ptype == BJC600 || ptype == BJC800)
2655       ;				/* Already done */
2656   else if (ptype == ESC_P) {
2657     ep_print_image(prn_stream, 'F', 0, 0); /* flush print buffer */
2658     fputs("\014\033@", prn_stream);	/* reset after eject page */
2659   } else
2660     fputs("\033&l0H", prn_stream);
2661 
2662   /* free temporary storage */
2663   gs_free(pdev->memory, (char *) ep_storage, ep_storage_size_words, W, "ep_print_buffer");
2664   gs_free(pdev->memory, (char *) storage, storage_size_words, W, "hp_colour_print_page");
2665 
2666   return 0;
2667 }
2668 
2669 /*
2670  * Row compression for the H-P PaintJet.
2671  * Compresses data from row up to end_row, storing the result
2672  * starting at compressed.  Returns the number of bytes stored.
2673  * The compressed format consists of a byte N followed by a
2674  * data byte that is to be repeated N+1 times.
2675  * In the worst case, the `compressed' representation is
2676  * twice as large as the input.
2677  * We complement the bytes at the same time, because
2678  * we accumulated the image in complemented form.
2679  */
2680 private int
2681 gdev_pcl_mode1compress(const byte *row, const byte *end_row, byte *compressed)
2682 {	register const byte *in = row;
2683 	register byte *out = compressed;
2684 	while ( in < end_row )
2685            {	byte test = *in++;
2686 		const byte *run = in;
2687 		while ( in < end_row && *in == test ) in++;
2688 		/* Note that in - run + 1 is the repetition count. */
2689 		while ( in - run > 255 )
2690                    {	*out++ = 255;
2691 			*out++ = test;
2692 			run += 256;
2693                    }
2694 		*out++ = in - run;
2695 		*out++ = test;
2696            }
2697 	return out - compressed;
2698 }
2699 
2700 /*
2701  * Map a CMYK color to a color index. We just use depth / 4 bits per color
2702  * to produce the color index.
2703  *
2704  * Important note: CMYK values are stored in the order K, C, M, Y because of
2705  * the way the HP drivers work.
2706  *
2707  */
2708 
2709 #define gx_color_value_to_bits(cv, b) \
2710     ((cv) >> (gx_color_value_bits - (b)))
2711 #define gx_bits_to_color_value(cv, b) \
2712     ((cv) << (gx_color_value_bits - (b)))
2713 
2714 #define gx_cmyk_value_bits(c, m, y, k, b) \
2715     ((gx_color_value_to_bits((k), (b)) << (3 * (b))) | \
2716      (gx_color_value_to_bits((c), (b)) << (2 * (b))) | \
2717      (gx_color_value_to_bits((m), (b)) << (b)) | \
2718      (gx_color_value_to_bits((y), (b))))
2719 
2720 #define gx_value_cmyk_bits(v, c, m, y, k, b) \
2721     (k) = gx_bits_to_color_value(((v) >> (3 * (b))) & ((1 << (b)) - 1), (b)), \
2722     (c) = gx_bits_to_color_value(((v) >> (2 * (b))) & ((1 << (b)) - 1), (b)), \
2723     (m) = gx_bits_to_color_value(((v) >> (b)) & ((1 << (b)) - 1), (b)), \
2724     (y) = gx_bits_to_color_value((v) & ((1 << (b)) - 1), (b))
2725 
2726 private gx_color_index
2727 gdev_cmyk_map_cmyk_color(gx_device* pdev, const gx_color_value cv[])
2728 {
2729     gx_color_value cyan, magenta, yellow, black;
2730     gx_color_index color;
2731     cyan = cv[0]; magenta = cv[1]; yellow = cv[2]; black = cv[3];
2732     switch (pdev->color_info.depth) {
2733 	case 1:
2734 	   color = (cyan | magenta | yellow | black) > gx_max_color_value / 2 ?
2735 	       (gx_color_index) 1 : (gx_color_index) 0;
2736 	   break;
2737 
2738 	default: {
2739 	    int nbits = pdev->color_info.depth;
2740 
2741 	    color = gx_cmyk_value_bits(cyan, magenta, yellow, black,
2742 	        nbits >> 2);
2743 	 }
2744    }
2745 
2746    return color;
2747 }
2748 
2749 /* Mapping of RGB colors to gray values. */
2750 
2751 private gx_color_index
2752 gdev_cmyk_map_rgb_color(gx_device *pdev, const gx_color_value cv[])
2753 {
2754     gx_color_value r, g, b;
2755     r = cv[0]; g = cv[1]; b = cv[2];
2756     if (gx_color_value_to_byte(r & g & b) == 0xff) {
2757         return (gx_color_index) 0;	/* White */
2758     } else {
2759         gx_color_value c = gx_max_color_value - r;
2760         gx_color_value m = gx_max_color_value - g;
2761         gx_color_value y = gx_max_color_value - b;
2762 
2763         switch (pdev->color_info.depth) {
2764         case 1:
2765             return (c | m | y) > gx_max_color_value / 2 ?
2766                 (gx_color_index) 1 : (gx_color_index) 0;
2767             /*NOTREACHED*/
2768             break;
2769 
2770         case 8:
2771             return ((ulong) c * lum_red_weight * 10
2772                     + (ulong) m * lum_green_weight * 10
2773                     + (ulong) y * lum_blue_weight * 10)
2774                         >> (gx_color_value_bits + 2);
2775             /*NOTREACHED*/
2776             break;
2777         }
2778     }
2779 
2780     return (gx_color_index) 0;	/* This should never happen. */
2781 }
2782 
2783 /* Mapping of CMYK colors. */
2784 
2785 private int
2786 gdev_cmyk_map_color_cmyk(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
2787 {
2788     switch (pdev->color_info.depth) {
2789 	case 1:
2790 	   prgb[0] = gx_max_color_value * (1 - color);
2791 	   break;
2792 
2793 	case 8:
2794 	   if (pdev->color_info.num_components == 1) {
2795 	       gx_color_value value = (gx_color_value) color ^ 0xff;
2796 
2797 	       prgb[0] = (value << 8) + value;
2798 
2799 	       break;
2800 	   }
2801 
2802 	default: {
2803 	    unsigned long bcyan, bmagenta, byellow, black;
2804 	    int nbits = pdev->color_info.depth;
2805 
2806 	    gx_value_cmyk_bits(color, bcyan, bmagenta, byellow, black,
2807 	        nbits >> 2);
2808 
2809 	    prgb[0] = bcyan;
2810 	    prgb[1] = bmagenta;
2811 	    prgb[2] = byellow;
2812 	    prgb[3] = black;
2813 	}
2814     }
2815 
2816     return 0;
2817 }
2818 
2819 /*
2820  * Map a r-g-b color to a color index.
2821  * We complement the colours, since we're using cmy anyway, and
2822  * because the buffering routines expect white to be zero.
2823  * Includes colour balancing, following HP recommendations, to try
2824  * and correct the greenish cast resulting from an equal mix of the
2825  * c, m, y, inks by reducing the cyan component to give a truer black.
2826  */
2827 
2828 /* Simple black generation/under-color removal with BG(k) = UG(k) = k. YA. */
2829 
2830 #define bg_and_ucr(c, c_v, m, m_v, y, y_v, k) \
2831     do { \
2832        register byte cv = c_v, mv = m_v, yv = y_v, kv; \
2833  \
2834         kv = (cv > mv ? mv : cv); \
2835 	kv = (yv > k ? k : y); \
2836         y = yv - kv; m = mv - kv; c = cv -kv; k = kv; \
2837    } while (0)
2838 
2839 private gx_color_index
2840 gdev_pcl_map_rgb_color(gx_device *pdev, const gx_color_value cv[])
2841 {
2842   gx_color_value r, g, b;
2843   r = cv[0]; g = cv[1]; b = cv[2];
2844   if (gx_color_value_to_byte(r & g & b) == 0xff)
2845     return (gx_color_index)0;         /* white */
2846   else {
2847     int correction = cprn_device->correction;
2848     gx_color_value c = gx_max_color_value - r;
2849     gx_color_value m = gx_max_color_value - g;
2850     gx_color_value y = gx_max_color_value - b;
2851 
2852     /* Colour correction for better blacks when using the colour ink
2853      * cartridge (on the DeskJet 500C only). We reduce the cyan component
2854      * by some fraction (eg. 4/5) to correct the slightly greenish cast
2855      * resulting from an equal mix of the three inks */
2856     if (correction) {
2857       ulong maxval, minval, range;
2858 
2859       maxval = c >= m ? (c >= y ? c : y) : (m >= y ? m : y);
2860       if (maxval > 0) {
2861 	minval = c <= m ? (c <= y ? c : y) : (m <= y? m : y);
2862 	range = maxval - minval;
2863 
2864 #define shift (gx_color_value_bits - 12)
2865 	c = ((c >> shift) * (range + (maxval * correction))) /
2866 	  ((maxval * (correction + 1)) >> shift);
2867       }
2868     }
2869 
2870     switch (pdev->color_info.depth) {
2871     case 1:
2872       return ((c | m | y) > gx_max_color_value / 2 ?
2873 	      (gx_color_index)1 : (gx_color_index)0);
2874     case 8:
2875       if (pdev->color_info.num_components >= 3)
2876 #define gx_color_value_to_1bit(cv) ((cv) >> (gx_color_value_bits - 1))
2877 	return (gx_color_value_to_1bit(c) +
2878 		(gx_color_value_to_1bit(m) << 1) +
2879 		(gx_color_value_to_1bit(y) << 2));
2880       else
2881 #define red_weight 306
2882 #define green_weight 601
2883 #define blue_weight 117
2884 	return ((((ulong)c * red_weight +
2885 		  (ulong)m * green_weight +
2886 		  (ulong)y * blue_weight)
2887 		 >> (gx_color_value_bits + 2)));
2888     case 16:
2889 #define gx_color_value_to_5bits(cv) ((cv) >> (gx_color_value_bits - 5))
2890 #define gx_color_value_to_6bits(cv) ((cv) >> (gx_color_value_bits - 6))
2891       return (gx_color_value_to_5bits(y) +
2892 	      (gx_color_value_to_6bits(m) << 5) +
2893 	      (gx_color_value_to_5bits(c) << 11));
2894     case 24:
2895       return (gx_color_value_to_byte(y) +
2896 	      (gx_color_value_to_byte(m) << 8) +
2897 	      ((ulong)gx_color_value_to_byte(c) << 16));
2898     case 32:
2899       { return ((c == m && c == y) ? ((ulong)gx_color_value_to_byte(c) << 24)
2900      : (gx_color_value_to_byte(y) +
2901         (gx_color_value_to_byte(m) << 8) +
2902         ((ulong)gx_color_value_to_byte(c) << 16)));
2903       }
2904     }
2905   }
2906   return (gx_color_index)0;   /* This never happens */
2907 }
2908 
2909 /* Map a color index to a r-g-b color. */
2910 private int
2911 gdev_pcl_map_color_rgb(gx_device *pdev, gx_color_index color,
2912 			    gx_color_value prgb[3])
2913 {
2914   /* For the moment, we simply ignore any black correction */
2915   switch (pdev->color_info.depth) {
2916   case 1:
2917     prgb[0] = prgb[1] = prgb[2] = -((gx_color_value)color ^ 1);
2918     break;
2919   case 8:
2920       if (pdev->color_info.num_components >= 3)
2921 	{ gx_color_value c = (gx_color_value)color ^ 7;
2922 	  prgb[0] = -(c & 1);
2923 	  prgb[1] = -((c >> 1) & 1);
2924 	  prgb[2] = -(c >> 2);
2925 	}
2926       else
2927 	{ gx_color_value value = (gx_color_value)color ^ 0xff;
2928 	  prgb[0] = prgb[1] = prgb[2] = (value << 8) + value;
2929 	}
2930     break;
2931   case 16:
2932     { gx_color_value c = (gx_color_value)color ^ 0xffff;
2933       ushort value = c >> 11;
2934       prgb[0] = ((value << 11) + (value << 6) + (value << 1) +
2935 		 (value >> 4)) >> (16 - gx_color_value_bits);
2936       value = (c >> 6) & 0x3f;
2937       prgb[1] = ((value << 10) + (value << 4) + (value >> 2))
2938 	>> (16 - gx_color_value_bits);
2939       value = c & 0x1f;
2940       prgb[2] = ((value << 11) + (value << 6) + (value << 1) +
2941 		 (value >> 4)) >> (16 - gx_color_value_bits);
2942     }
2943     break;
2944   case 24:
2945     { gx_color_index c = color ^ 0xffffff;
2946       prgb[0] = gx_color_value_from_byte((gx_color_value)(c >> 16));
2947       prgb[1] = gx_color_value_from_byte((gx_color_value)((c >> 8) & 0xff));
2948       prgb[2] = gx_color_value_from_byte((gx_color_value)(c & 0xff));
2949     }
2950     break;
2951   case 32:
2952 #define  gx_maxcol gx_color_value_from_byte(gx_color_value_to_byte(gx_max_color_value))
2953     { gx_color_value w = gx_maxcol - gx_color_value_from_byte(color >> 24);
2954       prgb[0] = w - gx_color_value_from_byte((color >> 16) & 0xff);
2955       prgb[1] = w - gx_color_value_from_byte((color >> 8) & 0xff);
2956       prgb[2] = w - gx_color_value_from_byte(color & 0xff);
2957     }
2958     break;
2959   }
2960   return 0;
2961 }
2962 
2963 /*
2964  * Convert and expand scanlines:
2965  *
2966  * For devices with 3 components:
2967  *
2968  *       (a)	16 -> 24 bit   (1-stage)
2969  *       (b)	16 -> 32 bit   (2-stage)
2970  *   or  (c)	24 -> 32 bit   (1-stage)
2971  *
2972  * For devices with 4 components:
2973  *
2974  *       (a)    16 -> 32 bit   (1-stage)
2975  *       (b)     8 -> 32 bit   (2-stage)
2976  *  or   (c)    24 -> 32 bit   (1-stage)
2977  *
2978  */
2979 
2980 private void
2981 cdj_expand_line(word *line, int linesize, short cmyk, int bpp, int ebpp)
2982 {
2983   int endline = linesize;
2984   byte *start = (byte *)line;
2985   register byte *in, *out;
2986 
2987   if (cmyk > 0) {
2988       if (bpp == 8) {
2989 	  in = start + endline;
2990 	  out = start + (endline *=  2);
2991 
2992 	  while (in > start) {
2993 	      register byte b0;
2994 	      register byte bs0, bs1, bs2, bs3;
2995 
2996 	      b0 = *--in;
2997 
2998 	      bs0 = b0 & 0x03;
2999 	      bs1 = (b0 >> 2) & 0x03;
3000 	      bs2 = (b0 >> 4) & 0x03;
3001 	      bs3 = (b0 >> 6) & 0x03;
3002 
3003 	      *--out = (bs0 << 2) + bs0 + (bs1 << 6) + (bs1 << 4);
3004 	      *--out = (bs2 << 2) + bs2 + (bs3 << 6) + (bs3 << 4);
3005 	  }
3006       }
3007 
3008       if (bpp == 24) {
3009 	  endline = (endline + 2) / 3;
3010 
3011 	  in = start + endline * 3;
3012 	  out = start + endline * 4;
3013 
3014 	  while (in > start) {
3015 	      register byte b0, b1, b2;
3016 
3017 	      b0 = *--in;
3018 	      b1 = *--in;
3019 	      b2 = *--in;
3020 
3021 	      *--out = (b0 << 2) + ((b0 >> 4) & 0x03);
3022 	      *--out = ((b1 & 0x0f) << 4) + ((b0 >> 6) << 2)
3023 	          + ((b1 >> 2) & 0x03);
3024 	      *--out = ((b2 & 0x03) << 6) + ((b1 >> 4) << 2) + (b2 & 0x03);
3025 	      *--out = (b2 & 0xfc) + ((b2 >> 6) & 0x03);
3026 	  }
3027       } else if (ebpp == 32) {
3028 	  endline = (endline + 1) / 2;
3029 
3030 	  in = start + endline * 2;
3031 	  out = start + (endline *= 4);
3032 
3033 	  while (in > start) {
3034 	      register byte b0, b1;
3035 
3036 	      b0 = *--in;
3037 	      b1 = *--in;
3038 
3039 	      *--out = (b0 << 4) + ((b0 >> 4) & 0x07);
3040 	      *--out = (b0 & 0xf0) + ((b0 >> 4) & 0xf);
3041 	      *--out = (b1 << 4) + ((b1 >> 4) & 0x0f);
3042 	      *--out = (b1 & 0xf0) + ((b1 >> 4) & 0xf);
3043 	  }
3044       }
3045   } else /* cmyk > 0 */ {
3046       if (bpp == 16)              /* 16 to 24 (cmy) if required */
3047 	  { register byte b0, b1;
3048 	    endline = ((endline + 1) / 2);
3049 	    in = start + endline * 2;
3050 	    out = start + (endline *= 3);
3051 
3052 	    while (in > start)
3053 		{ b0 = *--in;
3054 		  b1 = *--in;
3055 		  *--out = (b0 << 3) + ((b0 >> 2) & 0x7);
3056 		  *--out = (b1 << 5) + ((b0 >> 3)  & 0x1c) + ((b1 >> 1) & 0x3);
3057 		  *--out = (b1 & 0xf8) + (b1 >> 5);
3058 	      }
3059 	}
3060 
3061       if (ebpp == 32)             /* 24/32 (cmy) to 32 (cmyk) if required */
3062 	  { register byte c, m, y;
3063 	    endline = ((endline + 2) / 3);
3064 	    in = start + endline * 3;
3065 	    out = start + endline * 4;
3066 
3067 	    while (in > start)
3068 		{
3069 		  y = *--in;
3070 		  m = *--in;
3071 		  c = *--in;
3072 
3073 		  if (c == y && c == m) {
3074 		      *--out = 0, *--out = 0, *--out = 0;
3075 		      *--out = c;
3076 		  } else {
3077 		      *--out = y, *--out = m, *--out = c;
3078 		      *--out = 0;
3079 		  }
3080 	      }
3081 	}
3082   }
3083 }
3084 
3085 private int
3086 cdj_put_param_int(gs_param_list *plist, gs_param_name pname, int *pvalue,
3087   int minval, int maxval, int ecode)
3088 {	int code, value;
3089 	switch ( code = param_read_int(plist, pname, &value) )
3090 	{
3091 	default:
3092 		return code;
3093 	case 1:
3094 		return ecode;
3095 	case 0:
3096 		if ( value < minval || value > maxval )
3097 		   param_signal_error(plist, pname, gs_error_rangecheck);
3098 		*pvalue = value;
3099 		return (ecode < 0 ? ecode : 1);
3100 	}
3101 }
3102 
3103 private int
3104 cdj_set_bpp(gx_device *pdev, int bpp, int ccomps)
3105 { gx_device_color_info *ci = &pdev->color_info;
3106 
3107   if (ccomps && bpp == 0) {
3108       if (cprn_device->cmyk) {
3109 	  switch (ccomps) {
3110 	      default:
3111 	          return gs_error_rangecheck;
3112 		  /*NOTREACHED*/
3113 		  break;
3114 
3115 	      case 1:
3116 	          bpp = 1;
3117 		  break;
3118 
3119 	      case 3:
3120 		  bpp = 24;
3121 		  break;
3122 
3123 	      case 4:
3124 		  switch (ci->depth) {
3125 		      case 8:
3126 		      case 16:
3127 		      case 24:
3128 		      case 32:
3129 		          break;
3130 
3131 		      default:
3132 			  bpp = cprn_device->default_depth;
3133 			  break;
3134 		  }
3135 		  break;
3136 	  }
3137       }
3138   }
3139 
3140   if (bpp == 0) {
3141       bpp = ci->depth;		/* Use the current setting. */
3142   }
3143 
3144   if (cprn_device->cmyk < 0) {
3145 
3146       /* Reset procedures because we may have been in another mode. */
3147 
3148       dev_proc(pdev, encode_color) = gdev_cmyk_map_cmyk_color;
3149       dev_proc(pdev, map_rgb_color) = NULL;
3150       dev_proc(pdev, decode_color) = gdev_cmyk_map_color_cmyk;
3151 
3152       if (pdev->is_open) gs_closedevice(pdev);
3153   }
3154 
3155   /* Check for valid bpp values */
3156 
3157   switch ( bpp )
3158     {
3159     case 16:
3160     case 32:
3161 	if (cprn_device->cmyk && ccomps && ccomps != 4) goto bppe;
3162 	break;
3163 
3164     case 24:
3165        if (!cprn_device->cmyk || ccomps == 0 || ccomps == 4) {
3166 	   break;
3167        } else if (ccomps == 1) {
3168 	   goto bppe;
3169        } else {
3170 
3171 	   /* 3 components 24 bpp printing for CMYK device. */
3172 
3173 	   cprn_device->cmyk = -1;
3174        }
3175        break;
3176 
3177     case 8:
3178 	if (cprn_device->cmyk) {
3179 	    if (ccomps) {
3180 		if (ccomps == 3) {
3181 		    cprn_device->cmyk = -1;
3182 		    bpp = 3;
3183 		} else if (ccomps != 1 && ccomps != 4) {
3184 		    goto bppe;
3185 		}
3186 	    }
3187 	    if (ccomps != 1) break;
3188 	} else {
3189 	    break;
3190 	}
3191 
3192     case 1:
3193        if (ccomps != 1) goto bppe;
3194 
3195        if (cprn_device->cmyk && bpp != pdev->color_info.depth) {
3196 	   dev_proc(pdev, map_cmyk_color) = NULL;
3197 	   dev_proc(pdev, map_rgb_color) = gdev_cmyk_map_rgb_color;
3198 
3199 	   if (pdev->is_open) {
3200 	       gs_closedevice(pdev);
3201 	   }
3202        }
3203        break;
3204 
3205     case 3:
3206 	if (!cprn_device->cmyk) {
3207 	    break;
3208 	}
3209 
3210     default:
3211 bppe:  return gs_error_rangecheck;
3212     }
3213 
3214 
3215     if (cprn_device->cmyk == -1) {
3216 	dev_proc(pdev, map_cmyk_color) = NULL;
3217 	dev_proc(pdev, map_rgb_color) = gdev_pcl_map_rgb_color;
3218 	dev_proc(pdev, map_color_rgb) = gdev_pcl_map_color_rgb;
3219 
3220 	if (pdev->is_open) {
3221 	    gs_closedevice(pdev);
3222 	}
3223     }
3224 
3225   switch (ccomps) {
3226       case 0:
3227           break;
3228 
3229       case 1:
3230 	  if (bpp != 1 && bpp != 8) goto cce;
3231 	  break;
3232 
3233       case 4:
3234 	  if (cprn_device->cmyk) {
3235 	      if (bpp >= 8) break;
3236 	  }
3237 
3238       case 3:
3239 	  if (bpp == 1 || bpp == 3 || bpp == 8 || bpp == 16
3240 	      || bpp == 24 || bpp == 32) {
3241 	      break;
3242 	  }
3243 
3244 cce:  default: return gs_error_rangecheck;
3245   }
3246 
3247   if (cprn_device->cmyk) {
3248       if (cprn_device->cmyk > 0) {
3249 	  ci->num_components = ccomps ? ccomps : (bpp < 8 ? 1 : 4);
3250       } else {
3251 	  ci->num_components = ccomps ? ccomps : (bpp < 8 ? 1 : 3);
3252       }
3253       if (bpp != 1 && ci->num_components == 1) { /* We do dithered grays. */
3254 	  bpp = bpp < 8 ? 8 : bpp;
3255       }
3256 
3257       ci->max_color = (1 << (bpp >> 2)) - 1;
3258       ci->max_gray = (bpp >= 8 ? 255 : 1);
3259 
3260       if (ci->num_components == 1) {
3261 	  ci->dither_grays = (bpp >= 8 ? 256 : 2);
3262 	  ci->dither_colors = (bpp >= 8 ? 256 : bpp > 1 ? 2 : 0);
3263       } else {
3264 	  ci->dither_grays = (bpp > 8 ? 256 : 2);
3265 	  ci->dither_colors = (bpp > 8 ? 256 : bpp > 1 ? 2 : 0);
3266       }
3267   } else {
3268       ci->num_components = (bpp == 1 || bpp == 8 ? 1 : 3);
3269       ci->max_color = (bpp >= 8 ? 255 : bpp > 1 ? 1 : 0);
3270       ci->max_gray = (bpp >= 8 ? 255 : 1);
3271       ci->dither_grays = (bpp >= 8 ? 256 : 2);
3272       ci->dither_colors = (bpp >= 8 ? 256 : bpp > 1 ? 2 : 0);
3273   }
3274 
3275   ci->depth = ((bpp > 1) && (bpp < 8) ? 8 : bpp);
3276 
3277   return 0;
3278 }
3279 
3280 /* new_bpp == save_bpp or new_bpp == 0 means don't change bpp.
3281    ccomps == 0 means don't change number of color comps.
3282    If new_bpp != 0, it must be the value of the BitsPerPixel element of
3283      the plist; real_bpp may differ from new_bpp.
3284 */
3285 private int
3286 cdj_put_param_bpp(gx_device *pdev, gs_param_list *plist, int new_bpp,
3287   int real_bpp, int ccomps)
3288 {
3289 	if (new_bpp == 0 && ccomps == 0)
3290 	  return gdev_prn_put_params(pdev, plist);
3291 	else
3292 	  {
3293 		gx_device_color_info save_info;
3294 		int save_bpp;
3295 		int code;
3296 
3297 		save_info = pdev->color_info;
3298 		save_bpp = save_info.depth;
3299 #define save_ccomps save_info.num_components
3300 		if ( save_bpp == 8 && save_ccomps == 3 && !cprn_device->cmyk)
3301 		  save_bpp = 3;
3302 		code = cdj_set_bpp(pdev, real_bpp, ccomps);
3303 		if ( code < 0 ) {
3304 		  param_signal_error(plist, "BitsPerPixel", code);
3305 		  param_signal_error(plist, "ProcessColorModel", code);
3306 		  return code;
3307 	        }
3308 		pdev->color_info.depth = new_bpp;  /* cdj_set_bpp maps 3/6 to 8 */
3309 		code = gdev_prn_put_params(pdev, plist);
3310 		if ( code < 0 )
3311 		  {	cdj_set_bpp(pdev, save_bpp, save_ccomps);
3312 			return code;
3313 		  }
3314 		cdj_set_bpp(pdev, real_bpp, ccomps);	/* reset depth if needed */
3315 		if ((cdj->color_info.depth != save_bpp ||
3316 		     (ccomps != 0 && ccomps != save_ccomps))
3317 		    && pdev->is_open )
3318 		  return gs_closedevice(pdev);
3319 		return 0;
3320 #undef save_ccomps
3321 	  }
3322 }
3323 
3324 /* This returns either the number of pixels in a scan line, or the number
3325  * of bytes required to store the line, both clipped to the page margins */
3326 private uint
3327 gdev_prn_rasterwidth(const gx_device_printer *pdev, int pixelcount)
3328 {
3329   ulong raster_width = (ulong)(pdev->width -
3330     pdev->x_pixels_per_inch * (dev_l_margin(pdev) + dev_r_margin(pdev)));
3331   return (pixelcount ?
3332           (uint)raster_width :
3333           (uint)((raster_width * pdev->color_info.depth + 7) >> 3));
3334 }
3335 
3336 /* Functions for manipulation params strings */
3337 
3338 private const byte*
3339 paramValueToString(const stringParamDescription* params, int value)
3340 {
3341 
3342     for (; params->p_name; ++params) {
3343 	if (params->p_value == value) {
3344 	    return (const byte *)params->p_name;
3345 	}
3346     }
3347 
3348     return (const byte*) 0;
3349 }
3350 
3351 private int
3352 paramStringValue(const stringParamDescription* params,
3353     const byte* name, int namelen, int* value)
3354 {
3355 
3356     for (; params->p_name; ++params) {
3357 	if (strncmp(params->p_name, (char *)name, namelen) == 0 &&
3358 	    params->p_name[namelen] == 0) {
3359 	    *value = params->p_value;
3360 	    return 1;
3361 	}
3362     }
3363 
3364     return 0;
3365 }
3366 
3367 private int
3368 put_param_string(gs_param_list* plist,
3369     const byte* pname, gs_param_string* pstring,
3370     const stringParamDescription* params, int *pvalue, int code)
3371 {
3372 
3373     int ncode;
3374 
3375     if ((ncode = param_read_string(plist, (char *)pname, pstring)) < 0) {
3376 	param_signal_error(plist, (char *)pname, code = ncode);
3377     } else if (ncode == 1) {
3378 	pstring->data = 0, pstring->size = 0;
3379     } else {
3380 	int value = 0;
3381 
3382 	if (paramStringValue(params, pstring->data, pstring->size,
3383             &value) == 0) {
3384 	    param_signal_error(plist, (char *)pname, code = gs_error_rangecheck);
3385 	} else {
3386 	    *pvalue = value;
3387 	}
3388     }
3389 
3390     return code;
3391 }
3392 
3393 private int
3394 get_param_string(gs_param_list* plist,
3395     const byte* pname, gs_param_string* pstring,
3396     const stringParamDescription* params, int pvalue, bool persist, int code)
3397 {
3398 
3399     int ncode;
3400 
3401     pstring->data = paramValueToString(params, pvalue);
3402 
3403     if (pstring->data == (byte*) 0) {
3404 	param_signal_error(plist, (char *)pname, ncode = gs_error_unknownerror);
3405     } else {
3406         pstring->size = strlen((char *)pstring->data);
3407 	pstring->persistent = persist;
3408     }
3409 
3410     if ((ncode = param_write_string(plist, (char *)pname, pstring)) < 0) {
3411 	code = ncode;
3412     }
3413 
3414     return code;
3415 }
3416 
3417 /*
3418  * This taken from gsdparam.c. I hope it will be useable directly some day.
3419  *
3420  */
3421 
3422 private int
3423 cdj_param_check_bytes(gs_param_list *plist, gs_param_name pname,
3424 		      const byte *str, uint size, bool is_defined)
3425 {       int code;
3426         gs_param_string new_value;
3427         switch ( code = param_read_string(plist, pname, &new_value) )
3428           {
3429           case 0:
3430                 if ( is_defined && new_value.size == size &&
3431                      !memcmp((const char *)str, (const char *)new_value.data,
3432                              size)
3433                    )
3434                   break;
3435                 code = gs_note_error(gs_error_rangecheck);
3436                 goto e;
3437           default:
3438                 if ( param_read_null(plist, pname) == 0 )
3439                   return 1;
3440 e:              param_signal_error(plist, pname, code);
3441           case 1:
3442                 ;
3443           }
3444         return code;
3445 }
3446 
3447 /* This is original code. */
3448 
3449 private int
3450 cdj_param_check_float(gs_param_list *plist, gs_param_name pname, floatp fval,
3451 		      bool is_defined)
3452 {       int code;
3453         float new_value;
3454         switch ( code = param_read_float(plist, pname, &new_value) )
3455           {
3456           case 0:
3457                 if ( is_defined && new_value == fval)
3458                   break;
3459                 code = gs_note_error(gs_error_rangecheck);
3460                 goto e;
3461           default:
3462                 if ( param_read_null(plist, pname) == 0 )
3463                   return 1;
3464 e:              param_signal_error(plist, pname, code);
3465           case 1:
3466                 ;
3467           }
3468         return code;
3469 }
3470 
3471 /* The following dithering algorithm has been kindly given to me (YA) by
3472  * Klaus-Gunther Hess, I just adapted it for use with the code here. */
3473 
3474 /*
3475 
3476 (From KGH:)
3477 
3478 Just about the features of the code:
3479 
3480     - Stored Color-Values are BYTES in the order C-M-Y-K.
3481       (Indices need to change with gdevcdj.c)
3482 
3483     - There are individual THRESHOLDs and SPOTSIZEs for
3484       the color-components. The following relation should
3485       be maintained:
3486                  SPOTSIZE = 2 * THRESHOLD + 1
3487       (The internal calculation is dedicated for limiting
3488        ink-density at the 720x720DpI-Resolution of the
3489        Epson-Printers, without loss of dynamic color-range)
3490 
3491     - In addition to that there are EMIN & EMAX-Values
3492       for the components. The Values are computed from
3493       the dithering-algorithm and can be replaced by
3494       constants, if neither the implementation nor
3495       THRESHOLD and SPOTSIZE can change.
3496 
3497     - The algorithm is tuned for speed. (K-only, if gray-
3498       levels are detected, with EMIN/EMAX-clipping of
3499       stored CMY-Errors. [Notice: cerr, merr, yerr are
3500       *not* reset to zero! Clearing them would cause
3501       regular patterns & "Halos" to appear!])
3502 
3503 */
3504 
3505 /*
3506  * Macros, that represent the undisturbed dithering-algorithm
3507  *
3508  * FSerror:   compute the desired Value
3509  * FSdecide:  decision based on the value computed by FSerror
3510  * FSdiffuse: distribute remaining error among pixels
3511  */
3512 
3513 #define FSerror(Val,Erow,Ecol) (Val + Erow + ((7 * Ecol)>>4))
3514 
3515 #define FSdecide(Error,Threshold,Spotsize,Pixel,Bit) \
3516          if(Error > Threshold) {\
3517             Pixel |= Bit;\
3518             Error -= Spotsize;\
3519          }
3520 
3521 #define FSdiffuse(Error,Erow,Ecol,Eprev)\
3522          Eprev  += (3 * Error + 8)>>4;\
3523          Erow    = (5 * Error + Ecol + 8)>>4;\
3524          Ecol    = Error;
3525 
3526 /*
3527  * some aliases for values from the device-structure
3528  */
3529 #define DIRECTION    direction[0]
3530 #define CMYK_THRESHOLD(I) threshold[I]
3531 #define SPOTSIZE(I)  spotsize[I]
3532 #define EMIN(I)      emin[I]
3533 #define EMAX(I)      emax[I]
3534 #define NPIXEL       (plane_size * 8)
3535 
3536 #define IDX_C	     1
3537 #define IDX_M	     2
3538 #define IDX_Y	     3
3539 #define IDX_K	     0
3540 
3541 #define ODX_C	     2
3542 #define ODX_M	     1
3543 #define ODX_Y	     0
3544 #define ODX_K	     3
3545 
3546 private int
3547 bjc_fscmyk(byte** inplanes, byte* outplanes[4][4], int** errplanes,
3548     int plane_size, int scan) {
3549 
3550     byte* err = (byte*) errplanes[0];
3551 
3552 /* =========================================================== */
3553    if(scan < 0) { /* scan <   0 -> initialize private buffer */
3554 /* =========================================================== */
3555 
3556       int p,i,v;
3557       int *direction,*threshold,*spotsize,*emin,*emax;
3558       int *errv,*errc;
3559 /*
3560  * allocate the error-buffer
3561  */
3562       /*KGHorig
3563       i = 4 * (5 + 1 + 1 + sd->stc.prt_pixels + 1) * sizeof(errv[0]);
3564       if((sd->stc.err_size < i) || (NULL == sd->stc.err)) {
3565          if(NULL != sd->stc.err)
3566             gs_free(sd->stc.err,sd->stc.err_size,1,"stcm/err");
3567          sd->stc.err_size = i;
3568          sd->stc.err = gs_malloc(sd->stc.err_size,1,"stcm/err");
3569          if(sd->stc.err == NULL) return_error(gs_error_VMerror);
3570       }
3571       */
3572 
3573       direction = (int *) err;
3574       threshold = direction + 4;
3575       spotsize  = threshold + 4;
3576       emin      = spotsize  + 4;
3577       emax      = emin      + 4;
3578       errc      = emax      + 4;
3579       errv      = errc      + 2*4;
3580 /*
3581  * compute initial values
3582  */
3583       DIRECTION = -1;
3584       for(i = 0; i < 4; ++i) {
3585          int j;
3586          float maxv = 1.0;
3587 	 /*KGHorig
3588          if((sd->stc.xfer[i].size < 1) || (sd->stc.xfer[i].data == NULL)) {
3589             maxv = 1.0;
3590          } else {
3591             maxv = 1.0/255.0;
3592             for(j = 0; j < sd->stc.xfer[i].size; ++j)
3593                if(maxv < sd->stc.xfer[i].data[j])
3594 	         maxv = sd->stc.xfer[i].data[j];
3595          }
3596 	 */
3597          CMYK_THRESHOLD(i) = (int)(127.0 / maxv + 0.5);
3598          SPOTSIZE(i)  = ((int) CMYK_THRESHOLD(i)<<1)+1;
3599          j = CMYK_THRESHOLD(i); /* Maximum Error-Value */
3600          errc[3] = 0;
3601          FSdiffuse(CMYK_THRESHOLD(i),errv[0],errc[0],errv[-4]);
3602          FSdiffuse(CMYK_THRESHOLD(i),errv[0],errc[0],errv[-4]);
3603          EMAX(i) = errv[0];
3604          errc[0] = 0;
3605          FSdiffuse((-CMYK_THRESHOLD(i)),errv[0],errc[0],errv[-4]);
3606          FSdiffuse((-CMYK_THRESHOLD(i)),errv[0],errc[0],errv[-4]);
3607          EMIN(i) = errv[0];
3608       }
3609 
3610 #ifdef CDJ_DEBUG_FS
3611       for(i = 0; i < 4; ++i) errprintf(
3612          "CMYK_THRESHOLD(%d)=%5d, spotsize(%d)=%5d, emin(%d)=%5d, emax(%d)=%5d\n",
3613          i,CMYK_THRESHOLD(i),i,SPOTSIZE(i),i,EMIN(i),i,EMAX(i));
3614 #endif
3615 
3616       for(i = 0; i < 4; ++i) errc[i] = 0;
3617 
3618       for(p = 0; p < NPIXEL; ++p) {
3619          for(i = 0; i < 4; ++i) {
3620 	    /*KHGOrig
3621             if(sd->stc.flags & STCDFLAG0) v = 0;
3622 	    */
3623 	    if (0) v = 0;	/* Must provide a default for that. */
3624             else                      v = (rand() % SPOTSIZE(i)) - CMYK_THRESHOLD(i);
3625             FSdiffuse(v,errv[i],errc[i],errv[i-4]);
3626          }
3627          errv += i;
3628       }
3629 
3630 /* =========================================================== */
3631    } else {        /* scan >=  0 -> scanline-processing       */
3632 /* =========================================================== */
3633 
3634       int w,p,dir,thedir;
3635       byte *out[4],pixel[4],bit;
3636       /*KGHorig
3637       int  *width     = outplanes[scan];
3638       */
3639       int  *direction = (int *) err;
3640       int  *threshold = direction + 4;
3641       int  *spotsize  = threshold + 4;
3642       int  *emin      = spotsize  + 4;
3643       int  *emax      = emin      + 4;
3644       int  *errc      = emax      + 4;
3645       int  *errv      = errc      + 2*4;
3646       int   kerr,cerr,merr,yerr;
3647 
3648       byte* in;
3649 
3650       /*KGHorig
3651       if(sd->stc.flags & STCDFLAG1) {
3652       */
3653       if (0) {			/* Eventually will provide a flag for this. */
3654          cerr = merr = yerr = kerr = 0;
3655       } else {
3656          cerr = errc[0];
3657          merr = errc[1];
3658          yerr = errc[2];
3659          kerr = errc[3];
3660       }
3661 
3662       out[0]   = outplanes[scan + 2][ODX_C];
3663       out[1]   = outplanes[scan + 2][ODX_M];
3664       out[2]   = outplanes[scan + 2][ODX_Y];
3665       out[3]   = outplanes[scan + 2][ODX_K];
3666       pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
3667 
3668       if(DIRECTION < 0) { /* scan == 0, run backward */
3669          w      = NPIXEL;
3670 	 in     = inplanes[2] + 4 * (NPIXEL - 1);
3671          errv  += (w-1)<<2;
3672          dir    = -4;
3673 	 /*KGHorig
3674          if(w > 8) for(p = 0; p < 4; ++p) out[p] += (w-1)>>3;
3675 	 */
3676 	 thedir = -1;
3677 	 for (p = 0; p < 4; ++p) {
3678 	     out[p] += plane_size - 1;
3679 	 }
3680       } else {      /* run forward */
3681          w      = 1;
3682 	 in      = inplanes[3] - 4 * NPIXEL;
3683          dir    = 4;
3684 	 thedir = 1;
3685 	 for (p = 0; p < 4; ++p) {
3686 	     out[p] -= plane_size;
3687 	 }
3688       }             /* run backward/forward */
3689 
3690       /*KGHorig
3691       if(0 == (sd->stc.flags & STCDFLAG1)) DIRECTION = -DIRECTION;
3692       */
3693       if (1) DIRECTION = -DIRECTION; /* Scan in other direction. */
3694 
3695       bit = 0x80>>((w-1) & 7);
3696       w   = (w+7)>>3;
3697 
3698       for(p = NPIXEL; p; --p) { /* loop over pixels */
3699 
3700          int cmy = in[IDX_C] | in[IDX_M] | in[IDX_Y];
3701          int kv  = FSerror(in[IDX_K],errv[3],kerr);
3702          int cv;
3703 
3704          FSdecide(kv,CMYK_THRESHOLD(3),SPOTSIZE(3),pixel[3],bit);
3705 
3706          if(cmy) {
3707 
3708             if(pixel[3] & bit) { /* black known to fire */
3709 
3710                FSdiffuse(kv,errv[3],kerr,errv[3-dir]);
3711 
3712                cv  = FSerror(in[IDX_C],errv[0],cerr);
3713                cv -= SPOTSIZE(0);
3714                if ((cv+CMYK_THRESHOLD(0)) < 0) cv = -CMYK_THRESHOLD(0);
3715                FSdiffuse(cv,errv[0],cerr,errv[0-dir]);
3716 
3717                cv  = FSerror(in[IDX_M],errv[1],merr);
3718                cv -= SPOTSIZE(1);
3719                if ((cv+CMYK_THRESHOLD(1)) < 0) cv = -CMYK_THRESHOLD(1);
3720 
3721                FSdiffuse(cv,errv[1],merr,errv[1-dir]);
3722 
3723                cv  = FSerror(in[IDX_Y],errv[2],yerr);
3724                cv -= SPOTSIZE(2);
3725                if ((cv+CMYK_THRESHOLD(2)) < 0) cv = -CMYK_THRESHOLD(2);
3726                FSdiffuse(cv,errv[2],yerr,errv[2-dir]);
3727 
3728             } else {
3729 
3730                cv  = FSerror(in[IDX_C],errv[0],cerr);
3731                FSdecide(cv,CMYK_THRESHOLD(0),SPOTSIZE(0),pixel[0],bit);
3732                FSdiffuse(cv,errv[0],cerr,errv[0-dir]);
3733 
3734                cv  = FSerror(in[IDX_M],errv[1],merr);
3735                FSdecide(cv,CMYK_THRESHOLD(1),SPOTSIZE(1),pixel[1],bit);
3736                FSdiffuse(cv,errv[1],merr,errv[1-dir]);
3737 
3738                cv  = FSerror(in[IDX_Y],errv[2],yerr);
3739                FSdecide(cv,CMYK_THRESHOLD(2),SPOTSIZE(2),pixel[2],bit);
3740                FSdiffuse(cv,errv[2],yerr,errv[2-dir]);
3741 
3742                if(pixel[0] & pixel[1] & pixel[2] & bit) {
3743                   pixel[0] &= ~bit;
3744                   pixel[1] &= ~bit;
3745                   pixel[2] &= ~bit;
3746                   pixel[3] |=  bit;
3747                   kv -= SPOTSIZE(3);
3748                   if ((kv+CMYK_THRESHOLD(3)) < 0) kv = -CMYK_THRESHOLD(0);
3749                   FSdiffuse(kv,errv[3],kerr,errv[3-dir]);
3750                }
3751 	   }
3752 
3753          } else {
3754 
3755             FSdiffuse(kv,errv[3],kerr,errv[3-dir]);
3756 
3757             if(     errv[0] > EMAX(0)) errv[0] = EMAX(0);
3758             else if(errv[0] < EMIN(0)) errv[0] = EMIN(0);
3759 
3760             if(     errv[1] > EMAX(1)) errv[1] = EMAX(1);
3761             else if(errv[1] < EMIN(1)) errv[1] = EMIN(1);
3762 
3763             if(     errv[2] > EMAX(2)) errv[2] = EMAX(2);
3764             else if(errv[2] < EMIN(2)) errv[2] = EMIN(2);
3765 
3766          }
3767 
3768 /*
3769  * Adjust indices
3770  */
3771          bit   = dir > 0 ? (bit>>1) : (bit<<1);
3772          if(bit == 0) {
3773 	    /*KGHorig
3774             if(((*out[0]  = pixel[0]) != 0) && (width[0] < w)) width[0] = w;
3775             if(((*out[1]  = pixel[1]) != 0) && (width[1] < w)) width[1] = w;
3776             if(((*out[2]  = pixel[2]) != 0) && (width[2] < w)) width[2] = w;
3777             if(((*out[3]  = pixel[3]) != 0) && (width[3] < w)) width[3] = w;
3778 	    */
3779 	    *out[0] = pixel[0];
3780 	    *out[1] = pixel[1];
3781 	    *out[2] = pixel[2];
3782 	    *out[3] = pixel[3];
3783             out[0] += thedir; out[1] += thedir;
3784             out[2] += thedir; out[3] += thedir;
3785             pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
3786 
3787             if(dir > 0) bit = 0x80;
3788             else        bit = 0x01;
3789             w    += dir>>2;
3790          }
3791 
3792 	 in += dir;
3793          errv += dir;
3794       }                                         /* loop over pixels */
3795 
3796       /*KGHorig
3797       if(0 == (sd->stc.flags & STCDFLAG1)) {
3798       */
3799       if (1) {
3800          cerr = errc[0] = cerr;
3801          merr = errc[1] = merr;
3802          yerr = errc[2] = yerr;
3803          kerr = errc[3] = kerr;
3804       }
3805 
3806 /* =========================================================== */
3807    }                  /* initialization or scanline-Processing */
3808 /* =========================================================== */
3809 
3810    return 0;
3811 }
3812 
3813