--- /dev/null	Sun May 18 18:53:55 1997
+++ gdevcd8.c	Mon Apr  7 09:06:50 1997
@@ -0,0 +1,2020 @@
+/* gdevcd8.c */
+/* HP 850c, 855c & the like colour printer drivers */
+/* These are currently not in the official distrib.*/
+/* Please report all problems to uli@bonk.ethz.ch
+ */
+
+/* 11.11.96. Initial release of the driver */
+/* 04.05.97  Version 1.1. For added feautures, */
+/* resolved bugs and so forth, please see   */
+/* http://bonk.ethz.ch                      */
+
+/* The current gs hp850 driver is meant to support all hp-color
+   printers with C-RET and asymetrical resolution capabilities.
+   Currently the driver supports only the the hp850, hp855, hp870
+   and hp890 printers with 300x300 dpi color (with and without RET) and
+   600x600dpi b/w. 
+   
+   The driver _must_ be invoked with the following switches:
+   gs -r600 -dBitsPerPixel=32 (see the provided cmd-files as examples)
+   Furthermore, the driver supports the following switches:
+
+   -dPapertype= 0  plain paper [default]
+                1  bond paper
+		2  special paper
+		3  glossy film
+		4  transparency film
+
+   -dQuality=  -1 draft        not recommended
+                0 normal       not recommended
+                1 presentation [default]
+
+   -dRetstatus= 0 C-RET off
+                1 C-RET on [default]
+
+   -dMasterGamma= 3.0 [default]
+
+   When using the driver, be aware that printing in 600dpi involves
+   processing of large amounts of data (> 188MB !). Therefore, the
+   driver is not what you would expect to be a fast driver ;-)
+   This is no problem when printing a full sized color page (because
+   printing itself is slow), but it's really annoying if yoy print only
+   text pages. Maybe I can optimize the code for text-only pages in a
+   later release.
+   For the time beeing, use the cdj550 device with -sBitsPerPixel=3
+   for fast proof-prints. If you simply wanna print 600dpi b/w data,
+   use the cdj550 device with -sBitsPerPixel=8 (or 1).
+   
+   Since the printer itself is slow, it may help to set the
+   process-priority of the gs-process to regular or even less. On a
+   486/100MHZ this is still sufficient to maintain a continuos
+   data-flow.
+   Note to OS/2 users: Simply put the gs-window into the background,
+   or minimize it. Also make sure, that print01.sys is invoked without
+   the /irq switch (great speed improvement under warp4).
+
+   You may use -dQuality=0 or -1, however, this setting interfers in
+   an undocumented way with the output of the dither routine, such
+   that the midtones of colors may look ugly (I have no idea how to
+   overcome this). Anyhow, printing with 600dpi is somewhat senseless
+   if you don't have a high positionig precision of the print-head ;-)
+   Using -dQuality=-1 makes more sense since it saves a lot of ink
+   (but looks ugly).
+
+   The printer default settings compensate for dot-gain by a
+   gamma-function with exponent=3.0.
+   Furthermore, you may tweak the gammavalues independently by setting
+   -dGammaValC, -dGammaValM, -dGammaValY or -dGammaValK (if not set,
+   the values default to MasterGamma).
+
+   If you want to learn more about gamma, see:
+       
+       ftp://ftp.inforamp.net/pub/users/poynton/doc/colour/GammaFAQ.pdf
+       
+       or
+       
+       ftp://ftp.igd.fhg.de/pub/doc/colour/GammaFAQ.pdf
+
+   Have fun!
+
+	Uli
+
+	uli@bonk.ethz.ch
+	http://bonk.ethz.ch
+
+*/
+
+/* Note to *nix users. Depending on how you transfered the files, you might need to 
+   remove some CR-codes used on intel-based machines:
+
+   simply type:  tr -d \\r < gdevcd8.c > gdevcd8.c.new 
+
+/* to compile, include in your makefile something like:
+
+         DEVICE_DEVS4=cdj850.dev
+
+   create a file cdj850.dev with the following line:
+
+         -dev cdj850 -include page -obj gdevcd8.obj gdevpcl.obj
+
+   locate in devs.mak the line:
+
+         cdeskjet_=gdevcdj.$(OBJ) $(HPPCL)
+
+   and create below the line:
+
+         cdeskjet8_=gdevcd8.$(OBJ) $(HPPCL)
+
+   add to the device definitions the following two lines:
+
+        cdj850.dev: $(cdeskjet8_) page.dev
+        $(SETPDEV) cdj850 $(cdeskjet8_)
+
+   and recompile.
+
+*/
+
+
+
+#include "std.h"		/* to stop stdlib.h redefining types */
+#include <stdlib.h>		/* for rand() */
+#include <math.h>
+#include "gdevprn.h"
+#include "gdevpcl.h"
+#include "gsparam.h"
+#include "gsstate.h"
+
+/* Conversion stuff. */
+#include "gxlum.h"
+
+/***
+ 
+  *** The Hp850c driver is based on the dj550 one from George Cameron
+      especially, the compression and dither routines are copied verbatim.
+      1 - cdj850:	HP850 printer
+ *                      uli@homer.geol.chemie.tu-muenchen.de
+ ***/
+
+ /*
+ * This taken from gsdparam.c. I hope it will be useable directly some day.
+ *
+ */
+
+#define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
+  switch ( ncode = pread(plist, (oname = pname), &pa) )\
+  {\
+  case 0:\
+	if ( pa.size != psize )\
+	  code = gs_error_rangecheck;\
+	else { 
+/* The body of the processing code goes here. */
+/* If it succeeds, it should do a 'break'; */
+/* if it fails, it should set ecode and fall through. */
+#define END_PARAM(pa, e)\
+	}\
+	goto e;\
+  default:\
+	code = ncode;\
+e:	param_signal_error(plist, oname, code);\
+  case 1:\
+	pa.data = 0;		/* mark as not filled */\
+  }
+
+#define cdj_param_check_string(plist, pname, str, defined)\
+  cdj_param_check_bytes(plist, pname, (const byte *)str, strlen(str), defined)
+
+/*
+ * Drivers stuff.
+ *
+ */
+#define DESKJET_PRINT_LIMIT  0.04	/* 'real' top margin? */
+/* Margins are left, bottom, right, top. */
+#define DESKJET_MARGINS_LETTER   0.25, 0.50, 0.25, 0.167
+#define DESKJET_MARGINS_A4       0.125, 0.50, 0.143, 0.167
+/* Define bits-per-pixel for generic drivers - default is 24-bit mode */
+#ifndef BITSPERPIXEL
+#  define BITSPERPIXEL 32
+#endif
+
+#define W sizeof(word)
+#define I sizeof(int)
+
+/* Printer types */
+#define DJ850C   1
+
+/* No. of ink jets (used to minimise head movements) */
+#define HEAD_ROWS_MONO 50
+#define HEAD_ROWS_COLOUR 16
+
+/* Colour mapping procedures */
+private dev_proc_map_cmyk_color (gdev_cmyk_map_cmyk_color);
+private dev_proc_map_rgb_color (gdev_cmyk_map_rgb_color);
+private dev_proc_map_color_rgb (gdev_cmyk_map_color_rgb);
+
+private dev_proc_map_rgb_color (gdev_pcl_map_rgb_color);
+private dev_proc_map_color_rgb (gdev_pcl_map_color_rgb);
+
+/* Print-page, parameters and miscellaneous procedures */
+private dev_proc_open_device(dj850c_open);
+
+private dev_proc_get_params(cdj850_get_params);
+private dev_proc_put_params(cdj850_put_params);
+
+private dev_proc_print_page(dj850c_print_page);
+
+/* The device descriptors */
+
+/* The basic structure for all printers. Note the presence of the cmyk, depth
+   and correct fields even if soem are not used by all printers. */
+
+#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)\
+    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
+
+
+
+#define gx_prn_colour_device_common \
+    gx_prn_device_common; \
+    short cmyk;	  	/* 0: not CMYK-capable, > 0: printing CMYK, */ \
+		  	/* < 0 : CMYK-capable, not printing CMYK */ \
+    uint default_depth;	/* Used only for CMYK-capable printers now. */ \
+    uint correction
+
+typedef struct gx_device_cdj850_s gx_device_cdj850;
+struct gx_device_cdj850_s {
+  gx_device_common;
+  gx_prn_colour_device_common;
+  int quality;		    /* -1 draft, 0 normal, 1 best */
+  int papertype;	    /* papertype [0,4] */
+  int retstatus;            /* intensity values per pixel [2,4]*/
+  float mastergamma;        /* Gammavalue applied to all colors */
+  float gammavalc;          /* range to which gamma-correction is
+			       applied to bw values */
+  float gammavalm;          /* amount of gamma correction for bw*/
+  float gammavaly;          /* range to which gamma-correction i
+			       applied to color values */
+  float gammavalk;          /* amount of gamma correction for color */
+  float blackcorrect;          /* amount of gamma correction for color */
+};
+
+typedef struct {
+    gx_device_common;
+    gx_prn_colour_device_common;
+} gx_device_colour_prn;
+
+
+/* Use the cprn_device macro to access generic fields (like cmyk,
+   default_depth and correction), and specific macros for specific
+   devices. */
+#define cprn_device     ((gx_device_colour_prn*) pdev)
+
+#define cdj850    ((gx_device_cdj850 *)pdev)
+
+#define prn_cmyk_colour_device(dtype, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correct)\
+    prn_colour_device_body(dtype, procs, dev_name,\
+    DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, x_dpi, y_dpi, 0, 0, 0, 0,\
+    ((bpp == 1 || bpp == 4) ? 1 : 4), bpp,\
+    (bpp > 8 ? 255 : 1), (1 << (bpp >> 2)) - 1, /* max_gray, max_color */\
+    (bpp > 8 ? 5 : 2), (bpp > 8 ? 5 : bpp > 1 ? 2 : 0),\
+    print_page, 1 /* cmyk */, correct)
+
+
+#define cdj_850_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, correction, quality, papertype, retstatus,mastergamma,gammavalc,gammavalm,gammavaly,gammavalk,blackcorrect)\
+{ prn_cmyk_colour_device(gx_device_cdj850, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correction),\
+    quality,\
+    papertype,\
+    retstatus,\
+    mastergamma,\
+    gammavalc,\
+    gammavalm,\
+    gammavaly,\
+    gammavalk,\
+    blackcorrect\
+}
+
+#define cmyk_colour_procs(proc_colour_open, proc_get_params, proc_put_params) {\
+	proc_colour_open,\
+	gx_default_get_initial_matrix,\
+	gx_default_sync_output,\
+	gdev_prn_output_page,\
+	gdev_prn_close,\
+	NULL /* map_rgb_color */,\
+	gdev_cmyk_map_color_rgb,\
+	NULL /* fill_rectangle */,\
+	NULL /* tile_rectangle */,\
+	NULL /* copy_mono */,\
+	NULL /* copy_color */,\
+	NULL /* draw_line */,\
+	gx_default_get_bits,\
+	proc_get_params,\
+	proc_put_params,\
+        gdev_cmyk_map_cmyk_color\
+}
+
+
+private gx_device_procs cdj850_procs =
+cmyk_colour_procs(dj850c_open, cdj850_get_params, cdj850_put_params);
+
+gx_device_cdj850 far_data gs_cdj850_device =
+cdj_850_device(cdj850_procs, "cdj850", 600, 600, 32, dj850c_print_page, 0, 1, 0, 1, 3.0 , 0.0, 0.0, 0.0, 3.3, 1.0);
+
+/* Forward references */
+private int gdev_pcl_mode9compress(P4(int, const byte *, const byte *, byte *));
+private int hp_colour_open(P2(gx_device *, int));
+private int hp850_colour_print_page(P3(gx_device_printer *, FILE *, int));
+private int near cdj_put_param_int(P6(gs_param_list *, gs_param_name,
+				      int *, int, int, int));
+private int near cdj_put_param_float(P6(gs_param_list *, gs_param_name, float *, float, float, int));
+private int cdj_put_param_bpp(P5(gx_device *, gs_param_list *, int, int, int));
+private int cdj_set_bpp(P3(gx_device *, int, int));
+
+/* String parameters manipulation */
+
+typedef struct {
+    const char* p_name;
+    int p_value;
+} stringParamDescription;
+
+
+/* Open the printer and set up the margins. */
+private int
+dj850c_open(gx_device *pdev)
+{  return hp_colour_open(pdev, DJ850C);
+}
+
+private int
+hp_colour_open(gx_device *pdev, int ptype)
+{	/* Change the margins if necessary. */
+  static const float dj_a4[4] = { DESKJET_MARGINS_A4 };
+  static const float dj_letter[4] = { DESKJET_MARGINS_LETTER };
+
+  const float _ds *m = (float _ds*) 0;
+
+  /* Set up colour params if put_params has not already done so */
+  if (pdev->color_info.num_components == 0)
+    {	int code = cdj_set_bpp(pdev, pdev->color_info.depth,
+	    pdev->color_info.num_components);
+	if ( code < 0 )
+	  return code;
+    }
+
+  switch (ptype) {
+    case DJ850C:
+    m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? dj_a4 :
+	 dj_letter);
+    break;
+ 
+  default:
+  }
+  gx_device_set_margins(pdev, m, true);
+  return gdev_prn_open(pdev);
+}
+
+/* Added parameters for DeskJet 850C */
+private int
+cdj850_get_params(gx_device *pdev, gs_param_list *plist)
+{	
+  int code = gdev_prn_get_params(pdev, plist);
+  if ( code < 0 ||
+       (code = param_write_int(plist, "Quality", &cdj850->quality)) < 0 ||
+       (code = param_write_int(plist, "Papertype", &cdj850->papertype)) < 0 ||
+       (code = param_write_int(plist, "RetStatus",  &cdj850->retstatus)) < 0 ||
+       (code = param_write_float(plist, "MasterGamma", &cdj850->gammavalc)) < 0 ||
+       (code = param_write_float(plist, "GammaValC", &cdj850->gammavalc)) < 0 ||
+       (code = param_write_float(plist, "GammaValM",   &cdj850->gammavalm)) < 0 ||
+       (code = param_write_float(plist, "GammaValY", &cdj850->gammavaly)) < 0 ||
+       (code = param_write_float(plist, "GammaValK", &cdj850->gammavalk)) < 0 ||
+       (code = param_write_float(plist, "BlackCorrect", &cdj850->blackcorrect)) < 0
+       )
+    return code;
+  
+  return code;
+}
+
+private int
+cdj850_put_params(gx_device *pdev, gs_param_list *plist)
+{	
+  int quality = cdj850->quality;
+  int papertype = cdj850->papertype;
+  int retstatus = cdj850->retstatus;
+  float mastergamma = cdj850->mastergamma;
+  float gammavalc = cdj850->gammavalc;
+  float gammavalm = cdj850->gammavalm;	
+  float gammavaly = cdj850->gammavaly;
+  float gammavalk = cdj850->gammavalk;
+  float blackcorrect = cdj850->blackcorrect;
+  int bpp = 0;
+  int code = 0;
+
+  code = cdj_put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, code);
+  code = cdj_put_param_int(plist, "Quality", &quality, 0, 2, code);
+  code = cdj_put_param_int(plist, "Papertype", &papertype, 0, 4, code);
+  code = cdj_put_param_int(plist, "RetStatus", &retstatus, 0, 2, code);
+  code = cdj_put_param_float(plist, "MasterGamma", &mastergamma, 0.1, 9.0, code);
+  code = cdj_put_param_float(plist, "GammaValC", &gammavalc, 0.0 , 9.0, code);
+  code = cdj_put_param_float(plist, "GammaValM", &gammavalm, 0.0 , 9.0, code);
+  code = cdj_put_param_float(plist, "GammaValY", &gammavaly, 0.0 , 9.0, code);
+  code = cdj_put_param_float(plist, "GammaValK", &gammavalk, 0.0 , 9.0, code);
+  code = cdj_put_param_float(plist, "BlackCorrect", &blackcorrect, 0.0 , 9.0, code);
+  
+  
+  if ( code < 0 )
+    return code;
+  code = cdj_put_param_bpp(pdev, plist, bpp, bpp, 0);
+  if ( code < 0 )
+    return code;
+  
+  cdj850->quality = quality;
+  cdj850->papertype = papertype;
+  cdj850->retstatus = retstatus;
+  cdj850->mastergamma = mastergamma;
+  cdj850->gammavalc = gammavalc;
+  cdj850->gammavalm = gammavalm;
+  cdj850->gammavaly = gammavaly;
+  cdj850->gammavalk = gammavalk;
+  cdj850->blackcorrect = blackcorrect;
+  return 0;
+}
+
+/* ------ Internal routines ------ */
+/* The DeskJet850C can compress (mode 9) */
+private int
+dj850c_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{
+  return hp850_colour_print_page(pdev, prn_stream, DJ850C);
+}
+
+/* MACROS FOR DITHERING (we use macros for compact source and faster code) */
+/* Floyd-Steinberg dithering. Often results in a dramatic improvement in
+ * subjective image quality, but can also produce dramatic increases in
+ * amount of printer data generated and actual printing time!! Mode 9 2D
+ * compression is still useful for fairly flat colour or blank areas but its
+ * compression is much less effective in areas where the dithering has
+ * effectively randomised the dot distribution. */
+
+#define RSHIFT ((I * 8) - 16)
+#define RANDOM (((rand() << RSHIFT) % (MAXVALUE / 2))  - MAXVALUE /4);
+#define MINVALUE  0
+#define C 8
+
+#define SHIFT ((I * 8) - 13)
+#define MAXVALUE  (255 << SHIFT)
+#define THRESHOLD (128 << SHIFT)
+
+/* --- needed for the hp850 -- */
+#define SHIFTS ((I * 8) - 14)
+#define SHIFTM ((I * 8) - 13)
+#define SHIFTL ((I * 8) - 12)
+
+#define MAXVALUES  (160 << SHIFTM)
+#define MAXVALUEM  (255 << SHIFTM)
+#define MAXVALUEL  (255 << SHIFTM)
+
+#define THRESHOLDS (128 << SHIFTM)
+#define THRESHOLDM (192 << SHIFTM)
+#define THRESHOLDL (250 << SHIFTM)
+/* --------------------------- */
+
+
+/* the hp850 knows about 4 different color intensities per color */
+#define FSdither8504(inP, outa, outb, errP, Err, Bit, Offset, Element)\
+{\
+	oldErr = Err;\
+	Err = (errP[Element] + ((Err * 7 + C) >> 4) + ((int)inP[Element] << SHIFT));\
+	if ((Err > THRESHOLDS) && Err <= THRESHOLDM) {\
+	  outa |= Bit;\
+	  Err -= MAXVALUES;\
+	}\
+	if ((Err > THRESHOLDM) && Err <= THRESHOLDL) {\
+	  outb |= Bit;\
+	  Err -= MAXVALUEM;\
+	}\
+	if (Err > THRESHOLDL) {\
+          outa |= Bit;\
+	  outb |= Bit;\
+	  Err -= MAXVALUEL;\
+	}\
+	errP[Element + Offset] += ((Err * 3 + C) >> 4);\
+	errP[Element] = ((Err * 5 + oldErr + C) >> 4);\
+}
+
+/* while printing on paper, we only use 3 -intensities */
+#define FSdither8503(inP, outa, outb, errP, Err, Bit, Offset, Element)\
+{\
+	oldErr = Err;\
+	Err = (errP[Element] + ((Err * 7 + C) >> 4) + ((int)inP[Element] << SHIFT));\
+	if ((Err > THRESHOLDS) && Err <= THRESHOLDM) {\
+	  outa |= Bit;\
+	  Err -= MAXVALUES;\
+	}\
+	if (Err > THRESHOLDM) {\
+	  outb |= Bit;\
+	  Err -= MAXVALUEM;\
+	}\
+	errP[Element + Offset] += ((Err * 3 + C) >> 4);\
+	errP[Element] = ((Err * 5 + oldErr + C) >> 4);\
+}
+
+#define FSdither(inP, out, errP, Err, Bit, Offset, Element)\
+{\
+	oldErr = Err;\
+	Err = (errP[Element] + ((Err * 7 + C) >> 4) + ((int)inP[Element] << SHIFT));\
+	if (Err > THRESHOLD) {\
+	  out |= Bit;\
+	  Err -= MAXVALUE;\
+	}\
+	errP[Element + Offset] += ((Err * 3 + C) >> 4);\
+	errP[Element] = ((Err * 5 + oldErr + C) >> 4);\
+}
+
+/* The hp850c has 600dpi black and 300 dpi color. Therefore, we need
+   an adapted dither algorythm */
+#define FSDlinebw(scan, i, plane_size, kErr, kP, n)\
+{\
+    if (scan == 0) {       /* going_up */\
+      for (i = 0; i < plane_size; i++) {\
+	byte k, bitmask;\
+	int oldErr;\
+	bitmask = 0x80;\
+	for (k = 0; bitmask != 0; bitmask >>= 1) {\
+	     FSdither(dp, k, ep, kErr, bitmask, -n, 0);\
+             dp += n, ep += n;\
+	}\
+	*kP++ = k;\
+      }\
+    } else {		/* going_down */\
+       for (i = 0; i < plane_size; i++) {\
+	   byte k, bitmask;\
+	   int oldErr;\
+	   bitmask = 0x01;\
+	   for (k = 0; bitmask != 0; bitmask <<= 1) {\
+               dp -= n, ep -= n;\
+               FSdither(dp, k, ep, kErr, bitmask, n, 0);\
+          	  }\
+        *--kP = k;\
+       }\
+   }\
+}
+
+/* Since bw has already been dithered for the hp850c, we need
+   an adapted dither algorythm */
+#define FSDlinec2(scan, i, plane_size, cErr, mErr, yErr, cPa, mPa, yPa, n, dp, ep)\
+{\
+    if (scan == 0) {       /* going_up */\
+      for (i = 0; i < plane_size; i++) {\
+	byte ca, ya, ma, bitmask;\
+	int oldErr;\
+	bitmask = 0x80;\
+	ca = ya = ma = 0;\
+	for (ca =0; bitmask != 0; bitmask >>= 1) {\
+	      FSdither(dp, ca, ep, cErr, bitmask, -4, n - 3);\
+	      FSdither(dp, ma, ep, mErr, bitmask, -4, n - 2);\
+	      FSdither(dp, ya, ep, yErr, bitmask, -4, n - 1);\
+              dp += n, ep += 4;\
+	}\
+        *cPa++ = ca;\
+        *mPa++ = ma;\
+	*yPa++ = ya;\
+      }\
+    } else {		/* going_down */\
+      for (i = 0; i < plane_size; i++) {\
+	byte ca, ya, ma, bitmask;\
+	int oldErr;\
+	bitmask = 0x01;\
+        ca = ya = ma = 0;\
+	for (ca=0; bitmask != 0; bitmask <<= 1) {\
+          dp -= n, ep -= 4;\
+          FSdither(dp, ya, ep, yErr, bitmask, 4, n - 1);\
+          FSdither(dp, ma, ep, mErr, bitmask, 4, n - 2);\
+          FSdither(dp, ca, ep, cErr, bitmask, 4, n - 3);\
+	}\
+	*--yPa = ya;\
+        *--mPa = ma;\
+        *--cPa = ca;\
+      }\
+   }\
+}
+
+/* The hp850c knows about 4 intensity levels per color. Once more, we need
+   an adapted dither algorythm */
+#define FSDlinec4(scan, i, plane_size, cErr, mErr, yErr, cPa, mPa, yPa, cPb, mPb, yPb, n, dp, ep)\
+{\
+    if (scan == 0) {       /* going_up */\
+      for (i = 0; i < plane_size; i++) {\
+	byte ca, ya, ma, cb, yb, mb, bitmask;\
+	int oldErr;\
+	bitmask = 0x80;\
+	ca = ya = ma = cb = yb = mb = 0;\
+	for (ca =0; bitmask != 0; bitmask >>= 1) {\
+	      FSdither8504(dp, ca, cb, ep, cErr, bitmask, -4, n - 3);\
+	      FSdither8504(dp, ma, mb, ep, mErr, bitmask, -4, n - 2);\
+	      FSdither8504(dp, ya, yb, ep, yErr, bitmask, -4, n - 1);\
+              dp += n, ep += 4;\
+	}\
+        *cPa++ = ca;\
+        *mPa++ = ma;\
+	*yPa++ = ya;\
+        *cPb++ = cb;\
+        *mPb++ = mb;\
+	*yPb++ = yb;\
+      }\
+    } else {		/* going_down */\
+      for (i = 0; i < plane_size; i++) {\
+	byte ca, cb, ya, yb, ma, mb, bitmask;\
+	int oldErr;\
+	bitmask = 0x01;\
+        ca = ya = ma = cb = yb = mb = 0;\
+	for (ca=0; bitmask != 0; bitmask <<= 1) {\
+          dp -= n, ep -= 4;\
+          FSdither8504(dp, ya, yb, ep, yErr, bitmask, 4, n - 1);\
+          FSdither8504(dp, ma, mb, ep, mErr, bitmask, 4, n - 2);\
+          FSdither8504(dp, ca, cb, ep, cErr, bitmask, 4, n - 3);\
+	}\
+	*--yPa = ya;\
+        *--mPa = ma;\
+        *--cPa = ca;\
+        *--yPb = yb;\
+        *--mPb = mb;\
+        *--cPb = cb;\
+      }\
+   }\
+}
+
+/* On ordinary paper, we'll only use 3 intensities with the hp850  */
+#define FSDlinec3(scan, i, plane_size, cErr, mErr, yErr, cPa, mPa, yPa, cPb, mPb, yPb, n, dp, ep)\
+{\
+    if (scan == 0) {       /* going_up */\
+      for (i = 0; i < plane_size; i++) {\
+	byte ca, ya, ma, cb, yb, mb, bitmask;\
+	int oldErr;\
+	bitmask = 0x80;\
+	ca = ya = ma = cb = yb = mb = 0;\
+	for (ca =0; bitmask != 0; bitmask >>= 1) {\
+	      FSdither8503(dp, ca, cb, ep, cErr, bitmask, -4, n - 3);\
+	      FSdither8503(dp, ma, mb, ep, mErr, bitmask, -4, n - 2);\
+	      FSdither8503(dp, ya, yb, ep, yErr, bitmask, -4, n - 1);\
+              dp += n, ep += 4;\
+	}\
+        *cPa++ = ca;\
+        *mPa++ = ma;\
+	*yPa++ = ya;\
+        *cPb++ = cb;\
+        *mPb++ = mb;\
+	*yPb++ = yb;\
+      }\
+    } else {		/* going_down */\
+      for (i = 0; i < plane_size; i++) {\
+	byte ca, cb, ya, yb, ma, mb, bitmask;\
+	int oldErr;\
+	bitmask = 0x01;\
+        ca = ya = ma = cb = yb = mb = 0;\
+	for (ca=0; bitmask != 0; bitmask <<= 1) {\
+          dp -= n, ep -= 4;\
+          FSdither8503(dp, ya, yb, ep, yErr, bitmask, 4, n - 1);\
+          FSdither8503(dp, ma, mb, ep, mErr, bitmask, 4, n - 2);\
+          FSdither8503(dp, ca, cb, ep, cErr, bitmask, 4, n - 3);\
+	}\
+	*--yPa = ya;\
+        *--mPa = ma;\
+        *--cPa = ca;\
+        *--yPb = yb;\
+        *--mPb = mb;\
+        *--cPb = cb;\
+      }\
+   }\
+}
+
+/* Some convenient shorthand .. */
+#define x_dpi        (pdev->x_pixels_per_inch)
+#define y_dpi        (pdev->y_pixels_per_inch)
+
+/* To calculate buffer size as next greater multiple of both parameter and W */
+#define calc_buffsize(a, b) (((((a) + ((b) * W) - 1) / ((b) * W))) * W)
+
+
+/* Here comes the hp850 output routine -------------------- */
+private int
+hp850_colour_print_page(gx_device_printer * pdev, FILE * prn_stream, int ptype)
+{
+  int rescale_byte_wise (P4(int bytecount, byte * inbytea, byte * inbyteb,
+			byte * outbyte));
+  void separate_colors (P8(int bytecount, byte * inbyte, byte * kvalues,
+		       byte * cvalues, byte * mvalues,
+		       byte * yvalues, byte * kcorrect, int ggg));
+  void do_gamma (P3(float mastergamma, float gammaval, byte * values));
+  void do_black_correction (P2(float kvalue,  byte * kcorrect));
+  void save_color (P3(int length, byte * plane_data, byte * plane_datab));
+  int line_size = gdev_prn_raster(pdev);
+  int line_size_words = (line_size + W - 1) / W;
+  int paper_size = gdev_pcl_paper_size((gx_device *)pdev);
+  int num_comps = pdev->color_info.num_components;
+  int bits_per_pixel = pdev->color_info.depth;
+  int storage_bpp = bits_per_pixel;
+  int expanded_bpp = bits_per_pixel;
+  int plane_size, databuff_size, plane_length;
+  int errbuff_size = 0;
+  int outbuff_size = 0;
+  int compression = 0;
+  int scan = 0;
+  int cscan = 0;
+  int is_two_pass = 0 ;
+  int *errors[2], *errorsc[2];
+  int zero_row_count; 
+  byte *data[4], *plane_data[4][4], *out_data, *out_datac;
+  byte *datac[4], *plane_datac[4][8];
+  byte cvalues[256], mvalues[256], yvalues[256], kvalues[256], kcorrect[256];
+  word *storage, *storagec, *storagee;
+  uint storage_size_words; 
+
+int ggg = 1;
+
+  /* prepare the bw lookup table */
+  do_gamma(cdj850->mastergamma, cdj850->gammavalk, kvalues);
+  /* prepare the color lookup table */
+  do_gamma(cdj850->mastergamma, cdj850->gammavalc, cvalues);
+  do_gamma(cdj850->mastergamma, cdj850->gammavalm, mvalues);
+  do_gamma(cdj850->mastergamma, cdj850->gammavaly, yvalues);
+  /* prepare the black correction table for the unbunt mask */
+  do_black_correction(cdj850->blackcorrect, kcorrect);
+     
+  num_comps = 4;                      /* 4-component printing */
+
+  plane_size = calc_buffsize(line_size, storage_bpp);
+  
+  if (bits_per_pixel > 4) {		/* Error buffer for FS dithering */
+    storage_bpp = expanded_bpp =  num_comps * 8;	/*  32 bits */
+    errbuff_size =			/* 4n extra values for line ends */
+      calc_buffsize((plane_size * expanded_bpp + num_comps * 4) * I, 1);
+  }
+  
+  databuff_size = plane_size * storage_bpp;
+  
+  storage_size_words = ((plane_size + plane_size ) * num_comps +
+			databuff_size + errbuff_size + outbuff_size) / W;
+  /* Since we need 600 and 300 dpi, we set up several buffers:
+     storage contains the data as copied from gs, as well as the
+     plane-data and the out_row buffer.
+     storagec will contain the rescaled color data. It also contains the
+     plane_data for the color-planes - these are needed by the
+     compression routine, but would be overwritten by the
+     b/w-dithering. The color planes allow for overwriting the
+     color-data by the error-data. Since we might use the
+     2bpp feature of the hp850 someday, it is sized like storage.
+     storagee contains the errors from b/w fs-dithering */
+
+  storage = (ulong *) gs_malloc(storage_size_words, W, "hp850_colour_print_page");
+  
+  storagee = (ulong *) gs_malloc(storage_size_words, W, "p850_colour_print_page");
+
+  storagec = (ulong *) gs_malloc(storage_size_words, W, "hp850_colour_print_page");
+ 
+  /*
+   * The principal data pointers are stored as pairs of values, with
+   * the selection being made by the 'scan' variable. The function of the
+   * scan variable is overloaded, as it controls both the alternating
+   * raster scan direction used in the Floyd-Steinberg dithering and also
+   * the buffer alternation required for line-difference compression.
+   *
+   * Thus, the number of pointers required is as follows:
+   * 
+   *   errors:      2  b/w dithering erros (scan direction only)
+   *   errorsc:     2  color dithering errors (scan direction only)
+   *   data:        4  600dpi data (scan direction and alternating buffers)
+   *   datac:       4  300dpi data (scan direction and alternating buffers)
+   *   plane_data:  4  b/w-planes (scan direction and alternating buffers)
+   *   plane_datac: 8  color-planes (scan direction and alternating buffers)
+   */
+  
+  /* if we can't allocate working area */ 
+  if (storage == 0 || storagec == 0 || storagee == 0) 
+    return_error(gs_error_VMerror);
+  else {
+    int i;
+    byte *p = out_data = (byte *)storage;
+    byte *pc = out_datac = (byte *) storagec;
+    byte *pe = (byte *) storagee;
+    data[0] = data[1] = data[2] = p;
+    datac[0] = datac[1] = datac[2] = pc;
+    data[3] = p + databuff_size;
+    datac[3] = pc + (int) (databuff_size/2);
+    if (bits_per_pixel > 1) {
+      p += databuff_size;
+      pc += (int) (databuff_size/2);
+      pe += databuff_size;
+    }
+
+    if (bits_per_pixel > 4) {
+      errors[0] = (int *)pe + num_comps * 2;
+      errors[1] = errors[0] + databuff_size;
+      errorsc[0] = (int *)pc + num_comps * 2;
+      errorsc[1] = errorsc[0] + (int) (databuff_size/2);
+      p += errbuff_size;
+      pc += (int) (errbuff_size/2);
+      pe += errbuff_size;
+    }
+
+    for (i = 0; i < num_comps; i++) {
+     plane_data[0][i] = plane_data[2][i] = p; 
+     p += plane_size;
+     pe += plane_size;
+    }
+
+    for (i = 0; i < num_comps; i++) {
+      plane_data[1][i] = p;
+      plane_data[3][i] = p + plane_size;
+      p += plane_size;
+      pe += plane_size;
+    }
+    
+    /* Pointer of the color output planes. They are initialised separatley
+       because the color_planes will hold 2 planes per color */
+    for (i = 0; i < 2 * num_comps; i++) {
+      plane_datac[0][i] = plane_datac[2][i] = pc; 
+      pc += (int) (plane_size/2);
+    }
+
+    for (i = 0; i < 2*num_comps; i++) {
+      plane_datac[1][i] = pc;
+      plane_datac[3][i] = pc + (int) (plane_size/2);
+      pc += (int) (plane_size/2);
+    }
+    
+  }
+  
+  /* Clear temp storage */
+  memset(storage, 0, storage_size_words * W);
+  memset(storagec, 0, storage_size_words * W);
+  memset(storagee, 0, storage_size_words * W);
+
+#define DOFFSET (dev_t_margin(pdev) - DESKJET_PRINT_LIMIT) /* Print position */
+
+  /* Start Raster mode */
+  {
+      int laenge = 26 ;
+      struct hp850 
+      {
+	unsigned int a1:8 ;
+	unsigned int a2:8 ;
+	unsigned int a3:8;
+	unsigned int a4:8;
+	unsigned int a5:8;
+	unsigned int a6:8;
+	unsigned int a7:8;
+	unsigned int a8:8;
+	unsigned int a9:8;
+	unsigned int a10:8;
+	unsigned int a11:8;
+	unsigned int a12:8;
+	unsigned int a13:8;
+	unsigned int a14:8;
+	unsigned int a15:8;
+	unsigned int a16:8;
+	unsigned int a17:8;
+	unsigned int a18:8;
+	unsigned int a19:8;
+	unsigned int a20:8;
+	unsigned int a21:8;
+	unsigned int a22:8;
+	unsigned int a23:8;
+	unsigned int a24:8;
+	unsigned int a25:8;
+	unsigned int a26:8;
+      } p;
+     
+      /* declare config-data */
+      p.a1  = 0x02;  /* format */
+      p.a2  = 0x04;  /* number of components */
+      /* black */
+      p.a3  = 0x02;  /* MSB x resolution */
+      p.a4  = 0x58;  /* LSB x resolution */
+      p.a5  = 0x02;  /* MSB y resolution */
+      p.a6  = 0x58;  /* LSB y resolution */
+      p.a7  = 0x00;  /* MSB intensity levels */
+      p.a8  = 0x02;  /* LSB intensity levels */
+      
+      /* cyan */
+      p.a9  = 0x01;  /* MSB x resolution */
+      p.a10 = 0x2c;  /* LSB x resolution */
+      p.a11 = 0x01;  /* MSB y resolution */
+      p.a12 = 0x2c;  /* LSB y resolution */
+      p.a13 = 0x00;  /* MSB intensity levels */
+      p.a14 = 0x02;  /* LSB intensity levels */
+      
+      /* magenta */
+      p.a15 = 0x01;  /* MSB x resolution */
+      p.a16 = 0x2c;  /* LSB x resolution */
+      p.a17 = 0x01;  /* MSB y resolution */
+      p.a18 = 0x2c;  /* LSB y resolution */
+      p.a19 = 0x00;  /* MSB intensity levels */
+      p.a20 = 0x02;  /* LSB intensity levels */
+      
+      /* yellow */
+      p.a21 = 0x01;  /* MSB x resolution */
+      p.a22 = 0x2c;  /* LSB x resolution */
+      p.a23 = 0x01;  /* MSB y resolution */
+      p.a24 = 0x2c;  /* LSB y resolution */
+      p.a25 = 0x00;  /* MSB intensity levels */
+      p.a26 = 0x02;  /* LSB intensity levels */
+
+      /* Be sure that cRET is turned off when printing in draft-mode */
+      if (cdj850->quality < 0)
+	cdj850->retstatus = 0;
+      
+      if ((cdj850->retstatus > 0) && (cdj850->papertype > 2)) {
+	p.a14 = 0x04; /* Intensity levels cyan */
+	p.a20 = 0x04; /* Intensity levels magenta */ 
+	p.a26 = 0x04; /* Intensity levels yellow */
+      } 
+      if ((cdj850->retstatus > 0) && (cdj850->papertype <= 2)) {
+	p.a14 = 0x03; /* Intensity levels cyan */
+	p.a20 = 0x03; /* Intensity levels magenta */ 
+	p.a26 = 0x03; /* Intensity levels yellow */
+
+	/* cdj850->gammavalc = 2.2 ; */ /* Adjust for the lager Dot-Gain */
+	/* cdj850->gammavalm = 2.2 ; */ /* when using C-RET */
+	/* cdj850->gammavaly = 2.2 ; */
+      } 
+
+      fputs("\033*rbC", prn_stream);    /* End raster graphics */
+      fputs("\033E", prn_stream); /* Reset */
+      /* Page size, orientation, top margin & perforation skip */
+      fprintf(prn_stream, "\033&l%daolE", paper_size);
+
+      /* Print Quality, -1 = draft, 0 = normal, 1 = presentation */
+      fprintf(prn_stream, "\033*o%dM", cdj850->quality);
+      /* Media Type,0 = plain paper, 1 = bond paper, 2 = special
+	 paper, 3 = glossy film, 4 = transparency film */
+      fprintf(prn_stream, "\033&l%dM", cdj850->papertype);
+
+      /* Move to top left of printed area */
+      fprintf(prn_stream, "\033*p%dY", (int)(300 * DOFFSET));
+     
+      /* This will start and configure the raster-mode */
+      fprintf(prn_stream, "\033*g%dW",laenge); /* The new configure
+						  raster data comand */
+      fwrite(&p,sizeof(byte),laenge,prn_stream); /* Transmit config
+						    data */
+    /* Select data compression */
+    compression = 9;
+  }
+
+  /* From now on, all escape commands start with \033*b, so we
+   * combine them (if the printer supports this). */
+  fputs("\033*b", prn_stream);
+  /* Set compression if the mode has been defined. */
+  if (compression)
+    fprintf(prn_stream, "%dm", compression);
+  
+  /* Send each scan line in turn */
+  {
+    int cErr, mErr, yErr, kErr;
+    int cErrc, mErrc, yErrc, kErrc;
+    int lnum, i;
+    int lend, this_pass;
+    int start_rows;
+    int num_blank_lines = 0;
+
+    word rmask = ~(word) 0 << ((-pdev->width * storage_bpp) & (W * 8 - 1));
+    lend = pdev->height - (dev_t_margin(pdev) + dev_b_margin(pdev)) * y_dpi;
+
+    start_rows = (num_comps == 1) ? HEAD_ROWS_MONO - 1 :  
+      HEAD_ROWS_COLOUR - 1;
+    this_pass = start_rows;
+
+    cErr = mErr = yErr = kErr = 0;
+    cErrc= mErrc = yErrc = kErrc = 0;
+
+    if (bits_per_pixel > 4) { /* Randomly seed initial error buffer */
+      int *ep = errors[0];
+      int *epc = errorsc[0];
+      for (i = 0; i < databuff_size; i++) { /* 600dpi planes */
+	*ep++ = RANDOM;
+      }
+      for (i = 0; i < databuff_size/2; i++) { /* 600dpi planes */
+	*epc++ = RANDOM;
+      }
+    }
+
+    for (zero_row_count=0, lnum = 0; lnum < lend; lnum+=1) { 
+      word *data_words = (word *)data[scan];
+      register word *end_data = data_words + line_size_words;
+      int out_count = 0;
+      
+      gdev_prn_copy_scan_lines(pdev, lnum, data[scan], line_size);
+
+      /* Mask off 1-bits beyond the line width. */
+      end_data[-1] &= rmask;
+
+      /* Remove trailing 0s. */
+      while (end_data > data_words && end_data[-1] == 0)
+	end_data--;
+      if (end_data == data_words) {	/* Blank line */
+	  num_blank_lines++;
+	  continue;
+      }
+
+      /* Skip blank lines if any */
+      if (num_blank_lines > 0) {
+	if (num_blank_lines < this_pass) {
+	  /* Moving down from current position
+	   * causes head motion on the DeskJets, so
+	   * if the number of lines is within the
+	   * current pass of the print head, we're
+	   * better off printing blanks. */
+	  this_pass -= num_blank_lines;
+	  fputc('y', prn_stream);   /* Clear current and seed rows */
+	  for (; (int)(num_blank_lines/2); num_blank_lines--)
+	    fputc('w', prn_stream);
+	} 
+	else {
+	  fprintf(prn_stream, "%dy", (int)(num_blank_lines/2));
+	}
+	memset(plane_data[1 - scan][0], 0, plane_size * num_comps);
+	memset(plane_datac[1 - scan][0], 0, plane_size * num_comps);
+	num_blank_lines = 0;
+	this_pass = start_rows;
+      }
+
+      {			/* Printing non-blank lines */
+	int i;
+	register byte *kP = plane_data[scan + 2][3];
+	register byte *dp = data[scan + 2];
+	register int *ep  = errors[scan];
+	
+	if (this_pass)
+	  this_pass--;
+	else
+	  this_pass = start_rows;
+
+	is_two_pass++;
+
+	/* we need cmyk color separation befor all the rest, since
+	   black may be contained in the color fields. This needs to
+	   be done on all pixel-rows, since even unused color-bytes
+	   might generate black */
+
+	separate_colors (databuff_size, data[scan], kvalues,
+			 cvalues, mvalues, yvalues, kcorrect, ggg); 
+		
+	if (is_two_pass > 1) { /* do it only if needed */
+	  /*
+	    we need to bytewise rescale the color data to 300dpi first,
+	    because the dithering process will disturb the data-field
+	    */
+	  
+	  plane_length = rescale_byte_wise (databuff_size, 
+					    data[scan],
+					    data[1-scan],datac[cscan]);
+	}
+
+	if (is_two_pass < 2) {/* we do the black output only if it is
+				 not done in the color-output */
+	  
+	  /* dithering the black-plane */
+	  FSDlinebw(scan, i, plane_size, kErr, kP, 4); 
+			  
+	  /* Compress the black output data*/
+	  out_count = gdev_pcl_mode9compress(plane_size, 
+					     plane_data[scan][3], 
+					     plane_data[1-scan][3], 
+					     out_data); 
+	  /* and output the black data */
+	  if (out_count) { 
+	    fprintf(prn_stream, "%dv", out_count); 
+	    fwrite(out_data, sizeof(byte), out_count, prn_stream);  
+	  } else { 
+	    fputc('v', prn_stream) ;
+	  } 
+	} /* end of is two_pass < 2 */
+
+	/* since color resolution is only half of the b/w-resolution,
+	   we only output every second row */
+	if (is_two_pass > 1) {
+	  /* Transfer raster graphics in the order C, M, Y, that is
+	     planes 2,1,0 */
+	  plane_length = (int) (plane_size/2);
+	  /* Now for the dithering of the color-planes */
+	  {
+	    byte *cPa = plane_datac[cscan+2][2];
+	    byte *mPa = plane_datac[cscan+2][1];
+	    byte *yPa = plane_datac[cscan+2][0];
+	    byte *cPb = plane_datac[cscan+2][6];
+	    byte *mPb = plane_datac[cscan+2][5];
+	    byte *yPb = plane_datac[cscan+2][4];
+	    register byte *dpc = datac[cscan+2];
+	    register int *epc = errorsc[cscan];
+	    
+	    if ((cdj850->retstatus > 0) && (cdj850->papertype > 2)) 
+	      {
+		FSDlinec4(cscan, i, plane_length, cErrc, mErrc, yErrc, cPa, mPa, yPa, cPb, mPb, yPb, 4, dpc, epc);
+	       FSDlinebw(scan, i, plane_size, kErr, kP, 4); 
+	      } 
+	    if ((cdj850->retstatus > 0) && (cdj850->papertype <=2))
+	      {
+		FSDlinec3(cscan, i, plane_length, cErrc, mErrc, yErrc, cPa, mPa, yPa, cPb, mPb, yPb, 4, dpc, epc); 
+		FSDlinebw(scan, i, plane_size, kErr, kP, 4); 		
+	      }
+	    if (cdj850->retstatus == 0)
+	      {
+		 FSDlinec2(cscan, i, plane_length, cErrc, mErrc, yErrc, cPa, mPa, yPa, 4, dpc, epc);
+		 FSDlinebw(scan, i, plane_size, kErr, kP, 4); 	      
+	      }
+	  }
+
+	  /* the hp-printer needs the output in form KCMY
+	     therefore, we start with the black part. Probably, we
+	     could integrate this into the color part, but I'm not
+	     sure if this inreases readability ;-) */
+
+	  /* Compress the black output data*/
+	  out_count = gdev_pcl_mode9compress(plane_size, 
+					     plane_data[scan][3], 
+					     plane_data[1-scan][3], 
+					     out_data); 
+	  /* and output the black data */
+	  if (out_count) { 
+	    fprintf(prn_stream, "%dv", out_count); 
+	    fwrite(out_data, sizeof(byte), out_count, prn_stream);  
+	  } else { 
+	    fputc('v', prn_stream) ;
+	  } 
+  
+	  /* Now output the color data as cmy */ 	 
+	  for (i = num_comps  - 2; i >= 0; i--) {
+	    int out_count = 0;
+	    
+	    /* output the lower color planes */
+	    out_count = gdev_pcl_mode9compress((int) (plane_size/2),
+					       plane_datac[cscan][i], 
+					       plane_datac[1-cscan][i],
+					       out_datac);
+	    if (out_count) {
+	      if (cdj850->retstatus > 0) {
+		fprintf(prn_stream, "%d%c", out_count, "vvvvv"[i]);
+	      } else {
+		fprintf(prn_stream, "%d%c", out_count, "wvvvv"[i]);
+	      }
+	      fwrite(out_datac, sizeof(byte), out_count, prn_stream);
+	    } else {
+	      if (cdj850->retstatus > 0) {
+		fprintf(prn_stream, "%c","vvvvv"[i]);
+	      } else {
+		fprintf(prn_stream, "%c","wvvvv"[i]);
+	      }
+	    }
+	    
+	    /* output the upper color planes */
+	    if (cdj850->retstatus > 0) {
+	      out_count = gdev_pcl_mode9compress((int) (plane_size/2),
+						 plane_datac[cscan][i+4], 
+						 plane_datac[1-cscan][i+4],
+						 out_datac);
+	      if (out_count) {
+		fprintf(prn_stream, "%d%c", out_count, "wvvvv"[i]);
+		fwrite(out_datac, sizeof(byte), out_count, prn_stream);
+	      } else {
+		fprintf(prn_stream, "%c","wvvvv"[i]);
+	      }
+	    }
+	    	  
+	  } /* End For i = num_comps */
+	  is_two_pass = 0;
+	  cscan = 1 - cscan; 
+	} /* End of is_two_pass */
+	scan = 1 - scan;          /* toggle scan direction */
+      }	  /* End Printing non-blank lines */
+    }    /* End for lnum ... */
+  } /* End send each scan line in turn */
+  fputs("0M", prn_stream); /* Reset compression */
+  fputs("\033*rC\033E", prn_stream); /* End Graphics, Reset */
+  fputs("\033&l0H", prn_stream); /* eject page */
+  gs_free((char *) storage, storage_size_words, W, "hp850_colour_print_page");
+  gs_free((char *) storagec, storage_size_words, W, "hp850_colour_print_page");
+  gs_free((char *) storagee, storage_size_words, W, "hp850_colour_print_page");
+
+  return 0;
+}
+
+/* here we do our own gamma-correction */
+void
+do_gamma(float mastergamma, float gammaval, byte * values)
+{
+  int i;
+  float gamma;
+
+  if (gammaval > 0.0) {
+    gamma = gammaval; 
+  } else {
+    gamma = mastergamma;
+  }
+
+  for (i=0;i<256;i++){
+    values[i] = (byte) (255.0 *
+      (1.0 - pow(((double)(255.0-(float)i)/255.0), (double)(1.0/gamma))));
+  }
+
+  return;
+}
+
+/* here we calculate a lookup-table which is used to compensate the
+   relativ loss of color due to undercolor-removal */
+void 
+do_black_correction(float kvalue, byte * kcorrect)
+{
+  int i;
+  
+    for (i=0;i<256;i++){
+    kcorrect[i] = (byte) (( 255 *
+                    pow(((255-i)/255.0), (1.0/kvalue)))
+                    - (255 - i));
+  }
+
+  return;
+}
+
+/* For Better Performance we use a macro here */
+#define DOUCR(col1, col2, col3, col4)\
+{\
+  /* determine how far we are from the grey axis. This is  */\
+  /* traditionally done by computing MAX(CMY)-MIN(CMY).    */\
+  /* However, if two colors are very similar, we could     */\
+  /* as either CMYRGB and K. Therefore we calculate the    */\
+  /* the distance col1-col2 and col2-col3, and use the     */\
+  /* smaller one.                                          */\
+  a = *col1 - *col2;\
+  b = *col2 - *col3;\
+  if (a >= b) {\
+    grey_distance = 1.0 - (b/255.0);\
+  } else {\
+    grey_distance = 1.0 - (a/255.0);\
+  }\
+  ucr   = (byte) (*col3 * grey_distance); \
+  *col4 = *col4 + ucr;  /* add removed black to black */\
+  /* remove only as much color as black is surviving the   */\
+  /* gamma correction */\
+  ucr   = *(kvalues + ucr);\
+  *col1 = *col1 - ucr ;\
+  *col2 = *col2 - ucr ;\
+  *col3 = *col3 - ucr ;\
+}
+
+/* Since resolution can be different on different planes, we need to
+ do real color separation */
+void
+separate_colors (int bytecount, byte * inbyte, byte * kvalues,
+		      byte * cvalues, byte * mvalues, byte * yvalues,
+		      byte * kcorrect, int ggg) 
+{
+  int i;
+  byte ucr, a, b;
+  byte *black, *cyan, *magenta, *yellow;
+  float grey_distance;
+
+  /* Grey component replacement */
+  for (i=0;i<bytecount;i+=4) {
+    black = inbyte ; /* Assign to black the current address of  inbyte */
+    inbyte++;        /* increment the addres of inbyte pointer */
+    
+    cyan = inbyte;
+    inbyte++;
+    
+    magenta= inbyte;
+    inbyte++;
+    
+    yellow = inbyte;
+    inbyte++;
+    
+    if (*magenta + *yellow + *cyan > 0) { /* if any color at all */
+      /* first, we do the gamma transformation. otherwise most
+	 dark colors will be lost. However, this may affect the
+	 neutrals, but currently I don't have a better solution */
+      *cyan     = *(cvalues + *cyan);
+      *magenta  = *(mvalues + *magenta);
+      *yellow   = *(yvalues + *yellow);
+      
+      /* transform the neutrals into black */
+      if ((*cyan >= *magenta) && (*magenta >= *yellow)){
+	DOUCR(cyan,magenta,yellow,black);
+      }
+      else if ((*cyan >= *yellow) && (*yellow >= *magenta)){
+	DOUCR(cyan,yellow,magenta,black);
+      }
+      else if ((*yellow >= *magenta) && (*magenta >= *cyan)){
+	DOUCR(yellow,magenta,cyan,black);
+      }
+      else if ((*yellow >= *cyan ) && (*cyan >= *magenta)){
+	DOUCR(yellow,cyan,magenta,black);
+      }
+      else if ((*magenta >= *yellow ) && (*yellow >= *cyan)){
+	DOUCR(magenta,yellow,cyan,black);
+      }
+      else if ((*magenta >= *cyan ) && (*cyan >= *yellow)){
+	DOUCR(magenta,cyan,yellow,black);
+      }
+    }
+    /* gamma-correction of black is done at the very end. Otherwise,
+       the added black would escape the correction */
+    *black  = *(kvalues + *black);
+  }
+  return;
+}
+
+
+
+
+/* Since resolution can be different on different planes, we need to
+   rescale the data byte by byte*/
+int
+rescale_byte_wise (int bytecount, byte * inbytea, byte * inbyteb,
+		       byte * outbyte) 
+{
+  register int i,j;
+  int max = bytecount/2;
+  
+  for (i=0;i<max;i+=4) {
+     j = 2 * i;
+
+     /* black */
+     /* *(outbyte + i)     = *(inbytea +j); */
+     /* not needed here */
+     
+     /* cyan */
+     *(outbyte + (i+1)) = ((*(inbytea + (j+1)) + *(inbytea + (j+5))
+			  + *(inbyteb + (j+1)) + *(inbyteb + (j+5)))/4);
+     
+     /* magenta */
+     *(outbyte + (i+2)) = ((*(inbytea + (j+2)) + *(inbytea + (j+6))
+			  + *(inbyteb + (j+2)) + *(inbyteb + (j+6)))/4);
+     
+     /* yellow */
+     *(outbyte + (i+3)) = ((*(inbytea + (j+3)) + *(inbytea + (j+7))
+			  + *(inbyteb + (j+3)) + *(inbyteb + (j+7)))/4);
+  }
+  return max;
+}
+
+/*
+ * Mode 9 2D compression for the HP DeskJets . This mode can give
+ * very good compression ratios, especially if there are areas of flat
+ * colour (or blank areas), and so is 'highly recommended' for colour
+ * printing in particular because of the very large amounts of data which
+ * can be generated
+ */
+private int
+gdev_pcl_mode9compress(int bytecount, const byte * current, const byte
+		       * previous, byte * compressed)
+{
+  register const byte *cur = current;
+  register const byte *prev = previous;
+  register byte *out = compressed;
+  const byte *end = current + bytecount;
+
+  while (cur < end) {		/* Detect a run of unchanged bytes. */
+    const byte *run = cur;
+    register const byte *diff;
+    int offset;
+    while (cur < end && *cur == *prev) {
+      cur++, prev++;
+    }
+    if (cur == end)
+      break;			/* rest of row is unchanged */
+    /* Detect a run of changed bytes. */
+    /* We know that *cur != *prev. */
+    diff = cur;
+    do {
+      prev++;
+      cur++;
+    }
+    while (cur < end && *cur != *prev);
+    /* Now [run..diff) are unchanged, and */
+    /* [diff..cur) are changed. */
+    offset = diff - run;
+    {
+      const byte *stop_test = cur - 4;
+      int dissimilar, similar;
+
+      while (diff < cur) {
+	const byte *compr = diff;
+	const byte *next;	/* end of run */
+	byte value = 0;
+	while (diff <= stop_test &&
+	       ((value = *diff) != diff[1] ||
+		value != diff[2] ||
+		value != diff[3]))
+	  diff++;
+
+	/* Find out how long the run is */
+	if (diff > stop_test)	/* no run */
+	  next = diff = cur;
+	else {
+	  next = diff + 4;
+	  while (next < cur && *next == value)
+	    next++;
+	}
+
+#define MAXOFFSETU 15
+#define MAXCOUNTU 7
+	/* output 'dissimilar' bytes, uncompressed */
+	if ((dissimilar = diff - compr)) {
+	  int temp, i;
+
+	  if ((temp = --dissimilar) > MAXCOUNTU)
+	    temp = MAXCOUNTU;
+	  if (offset < MAXOFFSETU)
+	    *out++ = (offset << 3) | (byte) temp;
+	  else {
+	    *out++ = (MAXOFFSETU << 3) | (byte) temp;
+	    offset -= MAXOFFSETU;
+	    while (offset >= 255) {
+	      *out++ = 255;
+	      offset -= 255;
+	    }
+	    *out++ = offset;
+	  }
+	  if (temp == MAXCOUNTU) {
+	    temp = dissimilar - MAXCOUNTU;
+	    while (temp >= 255) {
+	      *out++ = 255;
+	      temp -= 255;
+	    }
+	    *out++ = (byte) temp;
+	  }
+	  for (i = 0; i <= dissimilar; i++)
+	    *out++ = *compr++;
+	  offset = 0;
+	}			/* end uncompressed */
+#define MAXOFFSETC 3
+#define MAXCOUNTC 31
+	/* output 'similar' bytes, run-length encoded */
+	if ((similar = next - diff)) {
+	  int temp;
+
+	  if ((temp = (similar -= 2)) > MAXCOUNTC)
+	    temp = MAXCOUNTC;
+	  if (offset < MAXOFFSETC)
+	    *out++ = 0x80 | (offset << 5) | (byte) temp;
+	  else {
+	    *out++ = 0x80 | (MAXOFFSETC << 5) | (byte) temp;
+	    offset -= MAXOFFSETC;
+	    while (offset >= 255) {
+	      *out++ = 255;
+	      offset -= 255;
+	    }
+	    *out++ = offset;
+	  }
+	  if (temp == MAXCOUNTC) {
+	    temp = similar - MAXCOUNTC;
+	    while (temp >= 255) {
+	      *out++ = 255;
+	      temp -= 255;
+	    }
+	    *out++ = (byte) temp;
+	  }
+	  *out++ = value;
+	  offset = 0;
+	}			/* end compressed */
+	diff = next;
+      }
+    }
+  }
+  return out - compressed;
+}
+
+private int near
+cdj_put_param_int(gs_param_list *plist, gs_param_name pname, int *pvalue,
+  int minval, int maxval, int ecode)
+{	int code, value;
+	switch ( code = param_read_int(plist, pname, &value) )
+	{
+	default:
+		return code;
+	case 1:
+		return ecode;
+	case 0:
+		if ( value < minval || value > maxval )
+		   param_signal_error(plist, pname, gs_error_rangecheck);
+		*pvalue = value;
+		return (ecode < 0 ? ecode : 1);
+	}
+}	
+
+private int near
+cdj_put_param_float(gs_param_list *plist, gs_param_name pname, float *pvalue,
+  float minval, float maxval, int ecode)
+{	
+  int code;
+  float value;
+	switch ( code = param_read_float(plist, pname, &value) )
+	{
+	default:
+		return code;
+	case 1:
+		return ecode;
+	case 0:
+		if ( value < minval || value > maxval )
+		   param_signal_error(plist, pname, gs_error_rangecheck);
+		*pvalue = value;
+		return (ecode < 0 ? ecode : 1);
+	}
+}	
+
+private int
+cdj_set_bpp(gx_device *pdev, int bpp, int ccomps)
+{ gx_device_color_info *ci = &pdev->color_info;
+
+  if (ccomps && bpp == 0) {
+      if (cprn_device->cmyk) {
+	  switch (ccomps) {
+	      default:
+	          return gs_error_rangecheck;
+		  /*NOTREACHED*/
+		  break;
+
+	      case 1:
+	          bpp = 1;
+		  break;
+
+	      case 3:
+		  bpp = 24;
+		  break;
+
+	      case 4:
+		  switch (ci->depth) {
+		      case 8:
+		      case 16:
+		      case 24:
+		      case 32:
+		          break;
+
+		      default:
+			  bpp = cprn_device->default_depth;
+			  break;
+		  }
+		  break;
+	  }
+      }
+  }
+
+  if (bpp == 0) {
+      bpp = ci->depth;		/* Use the current setting. */
+  }
+
+  if (cprn_device->cmyk < 0) {
+
+      /* Reset procedures because we may have been in another mode. */
+
+      dev_proc(pdev, map_cmyk_color) = gdev_cmyk_map_cmyk_color;
+      dev_proc(pdev, map_rgb_color) = NULL;
+      dev_proc(pdev, map_color_rgb) = gdev_cmyk_map_color_rgb;
+
+      if (pdev->is_open) gs_closedevice(pdev);
+  }
+
+  /* Check for valid bpp values */
+
+  switch ( bpp )
+    {
+    case 16:
+    case 32:
+	if (cprn_device->cmyk && ccomps && ccomps != 4) goto bppe;
+	break;
+
+    case 24:
+       if (!cprn_device->cmyk || ccomps == 0 || ccomps == 4) {
+	   break;
+       } else if (ccomps == 1) {
+	   goto bppe;
+       } else {
+
+	   /* 3 components 24 bpp printing for CMYK device. */
+
+	   cprn_device->cmyk = -1;
+       }
+       break;
+
+    case 8:
+	if (cprn_device->cmyk) {
+	    if (ccomps) {
+		if (ccomps == 3) {
+		    cprn_device->cmyk = -1;
+		    bpp = 3;
+		} else if (ccomps != 1 && ccomps != 4) {
+		    goto bppe;
+		}
+	    }
+	    if (ccomps != 1) break;
+	} else {
+	    break;
+	}
+
+    case 1:
+       if (ccomps != 1) goto bppe;
+
+       if (cprn_device->cmyk && bpp != pdev->color_info.depth) {
+	   dev_proc(pdev, map_cmyk_color) = NULL;
+	   dev_proc(pdev, map_rgb_color) = gdev_cmyk_map_rgb_color;
+
+	   if (pdev->is_open) {
+	       gs_closedevice(pdev);
+	   }
+       }
+       break;
+
+    case 3:
+	if (!cprn_device->cmyk) {
+	    break;
+	}
+
+    default:
+bppe:  return gs_error_rangecheck;
+    }
+
+
+    if (cprn_device->cmyk == -1) {
+	dev_proc(pdev, map_cmyk_color) = NULL;
+	dev_proc(pdev, map_rgb_color) = gdev_pcl_map_rgb_color;
+	dev_proc(pdev, map_color_rgb) = gdev_pcl_map_color_rgb;
+
+	if (pdev->is_open) {
+	    gs_closedevice(pdev);
+	}
+    }
+
+  switch (ccomps) {
+      case 0:
+          break;
+
+      case 1:
+	  if (bpp != 1 && bpp != 8) goto cce;
+	  break;
+
+      case 4:
+	  if (cprn_device->cmyk) {
+	      if (bpp >= 8) break;
+	  }
+
+      case 3:
+	  if (bpp == 1 || bpp == 3 || bpp == 8 || bpp == 16
+	      || bpp == 24 || bpp == 32) {
+	      break;
+	  }
+
+cce:  default: return gs_error_rangecheck;
+  }
+
+  if (cprn_device->cmyk) {
+      if (cprn_device->cmyk > 0) {
+	  ci->num_components = ccomps ? ccomps : (bpp < 8 ? 1 : 4);
+      } else {
+	  ci->num_components = ccomps ? ccomps : (bpp < 8 ? 1 : 3);
+      }
+      if (bpp != 1 && ci->num_components == 1) { /* We do dithered grays. */
+	  bpp = bpp < 8 ? 8 : bpp;
+      }
+
+      ci->max_color = (1 << (bpp >> 2)) - 1;
+      ci->max_gray = (bpp >= 8 ? 255 : 1);
+
+      if (ci->num_components == 1) {
+	  ci->dither_grays = (bpp >= 8 ? 5 : 2);
+	  ci->dither_colors = (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0);
+      } else {
+	  ci->dither_grays = (bpp > 8 ? 5 : 2);
+	  ci->dither_colors = (bpp > 8 ? 5 : bpp > 1 ? 2 : 0);
+      }
+  } else {
+      ci->num_components = (bpp == 1 || bpp == 8 ? 1 : 3);
+      ci->max_color = (bpp >= 8 ? 255 : bpp > 1 ? 1 : 0);
+      ci->max_gray = (bpp >= 8 ? 255 : 1);
+      ci->dither_grays = (bpp >= 8 ? 5 : 2);
+      ci->dither_colors = (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0);
+  }
+
+  ci->depth = ((bpp > 1) && (bpp < 8) ? 8 : bpp);
+
+  return 0;
+}
+
+/*
+ * Map a CMYK color to a color index. We just use depth / 4 bits per color
+ * to produce the color index.
+ *
+ * Important note: CMYK values are stored in the order K, C, M, Y because of
+ * the way the HP drivers work.
+ *
+ */
+
+#define gx_color_value_to_bits(cv, b) \
+    ((cv) >> (gx_color_value_bits - (b)))
+#define gx_bits_to_color_value(cv, b) \
+    ((cv) << (gx_color_value_bits - (b)))
+
+#define gx_cmyk_value_bits(c, m, y, k, b) \
+    ((gx_color_value_to_bits((k), (b)) << (3 * (b))) | \
+     (gx_color_value_to_bits((c), (b)) << (2 * (b))) | \
+     (gx_color_value_to_bits((m), (b)) << (b)) | \
+     (gx_color_value_to_bits((y), (b))))
+
+#define gx_value_cmyk_bits(v, c, m, y, k, b) \
+    (k) = gx_bits_to_color_value(((v) >> (3 * (b))) & ((1 << (b)) - 1), (b)), \
+    (c) = gx_bits_to_color_value(((v) >> (2 * (b))) & ((1 << (b)) - 1), (b)), \
+    (m) = gx_bits_to_color_value(((v) >> (b)) & ((1 << (b)) - 1), (b)), \
+    (y) = gx_bits_to_color_value((v) & ((1 << (b)) - 1), (b))
+
+private gx_color_index gdev_cmyk_map_cmyk_color(gx_device* pdev,
+    gx_color_value cyan, gx_color_value magenta, gx_color_value yellow,
+    gx_color_value black) {
+
+    gx_color_index color;
+
+    switch (pdev->color_info.depth) {
+	case 1:
+	   color = (cyan | magenta | yellow | black) > gx_max_color_value / 2 ?
+	       (gx_color_index) 1 : (gx_color_index) 0;
+	   break;
+
+	default: {
+	    int nbits = pdev->color_info.depth;
+
+            if (cyan == magenta && magenta == yellow) {
+
+	        /* Convert CMYK to gray -- Red Book 6.2.2 */
+
+	        float bpart = ((float) cyan) * (lum_red_weight / 100.) +
+		    ((float) magenta) * (lum_green_weight / 100.) +
+		    ((float) yellow) * (lum_blue_weight / 100.) +
+		    (float) black;
+
+		cyan = magenta = yellow = (gx_color_index) 0;
+		black = (gx_color_index) (bpart > gx_max_color_value ?
+		    gx_max_color_value : bpart);
+	    }
+
+	    color = gx_cmyk_value_bits(cyan, magenta, yellow, black,
+	        nbits >> 2);
+	 }
+   }
+
+   return color;
+}
+
+/* Mapping of RGB colors to gray values. */
+
+private gx_color_index
+gdev_cmyk_map_rgb_color(gx_device *pdev, gx_color_value r, gx_color_value g, gx_color_value b)
+{
+
+  if (gx_color_value_to_byte(r & g & b) == 0xff) {
+      return (gx_color_index) 0;	/* White */
+  } else {
+      gx_color_value c = gx_max_color_value - r;
+      gx_color_value m = gx_max_color_value - g;
+      gx_color_value y = gx_max_color_value - b;
+
+      switch (pdev->color_info.depth) {
+	  case 1:
+	      return (c | m | y) > gx_max_color_value / 2 ?
+	          (gx_color_index) 1 : (gx_color_index) 0;
+	      /*NOTREACHED*/
+	      break;
+
+	  case 8:
+	      return ((ulong) c * lum_red_weight * 10
+	          + (ulong) m * lum_green_weight * 10
+	          + (ulong) y * lum_blue_weight * 10)
+		  >> (gx_color_value_bits + 2);
+	      /*NOTREACHED*/
+	      break;
+      }
+  }
+
+   return (gx_color_index) 0;	/* This should never happen. */
+}
+
+/* Mapping of CMYK colors. */
+
+private int
+gdev_cmyk_map_color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+    switch (pdev->color_info.depth) {
+	case 1:
+	   prgb[0] = prgb[1] = prgb[2] = gx_max_color_value * (1 - color);
+	   break;
+
+	case 8:
+	   if (pdev->color_info.num_components == 1) {
+	       gx_color_value value = (gx_color_value) color ^ 0xff;
+
+	       prgb[0] = prgb[1] = prgb[2] = (value << 8) + value;
+
+	       break;
+	   }
+
+	default: {
+	    unsigned long bcyan, bmagenta, byellow, black;
+	    int nbits = pdev->color_info.depth;
+
+	    gx_value_cmyk_bits(color, bcyan, bmagenta, byellow, black,
+	        nbits >> 2);
+
+#ifdef USE_ADOBE_CMYK_RGB
+
+	    /* R = 1.0 - min(1.0, C + K), etc. */
+
+	    bcyan += black, bmagenta += black, byellow += black;
+	    prgb[0] = (bcyan > gx_max_color_value ? (gx_color_value) 0 :
+		       gx_max_color_value - bcyan);
+	    prgb[1] = (bmagenta > gx_max_color_value ? (gx_color_value) 0 :
+		       gx_max_color_value - bmagenta);
+	    prgb[2] = (byellow > gx_max_color_value ? (gx_color_value) 0 :
+		       gx_max_color_value - byellow);
+
+#else
+
+	    /* R = (1.0 - C) * (1.0 - K), etc. */
+
+	    prgb[0] = (gx_color_value)
+	      ((ulong)(gx_max_color_value - bcyan) *
+	       (gx_max_color_value - black) / gx_max_color_value);
+	    prgb[1] = (gx_color_value)
+	      ((ulong)(gx_max_color_value - bmagenta) *
+	       (gx_max_color_value - black) / gx_max_color_value);
+	    prgb[2] = (gx_color_value)
+	      ((ulong)(gx_max_color_value - byellow) *
+	       (gx_max_color_value - black) / gx_max_color_value);
+
+#endif
+
+	}
+    }
+
+    return 0;
+}
+
+/*
+ * Map a r-g-b color to a color index.
+ * We complement the colours, since we're using cmy anyway, and
+ * because the buffering routines expect white to be zero.
+ * Includes colour balancing, following HP recommendations, to try
+ * and correct the greenish cast resulting from an equal mix of the
+ * c, m, y, inks by reducing the cyan component to give a truer black.
+ */
+
+/* Simple black generation/under-color removal with BG(k) = UG(k) = k. YA. */
+
+#define bg_and_ucr(c, c_v, m, m_v, y, y_v, k) \
+    do { \
+       register byte cv = c_v, mv = m_v, yv = y_v, kv; \
+ \
+        kv = (cv > mv ? mv : cv); \
+	kv = (yv > k ? k : y); \
+        y = yv - kv; m = mv - kv; c = cv -kv; k = kv; \
+   } while (0)
+
+private gx_color_index
+gdev_pcl_map_rgb_color(gx_device *pdev, gx_color_value r,
+				 gx_color_value g, gx_color_value b)
+{
+  if (gx_color_value_to_byte(r & g & b) == 0xff)
+    return (gx_color_index)0;         /* white */
+  else {
+    int correction = cprn_device->correction;
+    gx_color_value c = gx_max_color_value - r;
+    gx_color_value m = gx_max_color_value - g;
+    gx_color_value y = gx_max_color_value - b;
+    
+    /* Colour correction for better blacks when using the colour ink
+     * cartridge (on the DeskJet 500C only). We reduce the cyan component
+     * by some fraction (eg. 4/5) to correct the slightly greenish cast
+     * resulting from an equal mix of the three inks */
+    if (correction) {
+      ulong maxval, minval, range;
+      
+      maxval = c >= m ? (c >= y ? c : y) : (m >= y ? m : y);
+      if (maxval > 0) {
+	minval = c <= m ? (c <= y ? c : y) : (m <= y? m : y);
+	range = maxval - minval;
+	
+#define shift (gx_color_value_bits - 12)
+	c = ((c >> shift) * (range + (maxval * correction))) /
+	  ((maxval * (correction + 1)) >> shift);
+      }
+    }
+    
+    switch (pdev->color_info.depth) {
+    case 1:
+      return ((c | m | y) > gx_max_color_value / 2 ?
+	      (gx_color_index)1 : (gx_color_index)0);
+    case 8:
+      if (pdev->color_info.num_components >= 3)
+#define gx_color_value_to_1bit(cv) ((cv) >> (gx_color_value_bits - 1))
+	return (gx_color_value_to_1bit(c) +
+		(gx_color_value_to_1bit(m) << 1) +
+		(gx_color_value_to_1bit(y) << 2));
+      else
+#define red_weight 306
+#define green_weight 601
+#define blue_weight 117
+	return ((((ulong)c * red_weight +
+		  (ulong)m * green_weight +
+		  (ulong)y * blue_weight)
+		 >> (gx_color_value_bits + 2)));
+    case 16:
+#define gx_color_value_to_5bits(cv) ((cv) >> (gx_color_value_bits - 5))
+#define gx_color_value_to_6bits(cv) ((cv) >> (gx_color_value_bits - 6))
+      return (gx_color_value_to_5bits(y) +
+	      (gx_color_value_to_6bits(m) << 5) +
+	      (gx_color_value_to_5bits(c) << 11));
+    case 24:
+      return (gx_color_value_to_byte(y) +
+	      (gx_color_value_to_byte(m) << 8) +
+	      ((ulong)gx_color_value_to_byte(c) << 16));
+    case 32:
+      { return ((c == m && c == y) ? ((ulong)gx_color_value_to_byte(c) << 24)
+     : (gx_color_value_to_byte(y) +
+        (gx_color_value_to_byte(m) << 8) +
+        ((ulong)gx_color_value_to_byte(c) << 16)));
+      }
+    }
+  }
+  return (gx_color_index)0;   /* This never happens */
+}
+    
+/* Map a color index to a r-g-b color. */
+private int
+gdev_pcl_map_color_rgb(gx_device *pdev, gx_color_index color,
+			    gx_color_value prgb[3])
+{
+  /* For the moment, we simply ignore any black correction */
+  switch (pdev->color_info.depth) {
+  case 1:
+    prgb[0] = prgb[1] = prgb[2] = -((gx_color_value)color ^ 1);
+    break;
+  case 8:
+      if (pdev->color_info.num_components >= 3)
+	{ gx_color_value c = (gx_color_value)color ^ 7;
+	  prgb[0] = -(c & 1);
+	  prgb[1] = -((c >> 1) & 1);
+	  prgb[2] = -(c >> 2);
+	}
+      else
+	{ gx_color_value value = (gx_color_value)color ^ 0xff;
+	  prgb[0] = prgb[1] = prgb[2] = (value << 8) + value;
+	}
+    break;
+  case 16:
+    { gx_color_value c = (gx_color_value)color ^ 0xffff;
+      ushort value = c >> 11;
+      prgb[0] = ((value << 11) + (value << 6) + (value << 1) +
+		 (value >> 4)) >> (16 - gx_color_value_bits);
+      value = (c >> 6) & 0x3f;
+      prgb[1] = ((value << 10) + (value << 4) + (value >> 2))
+	>> (16 - gx_color_value_bits);
+      value = c & 0x1f;
+      prgb[2] = ((value << 11) + (value << 6) + (value << 1) +
+		 (value >> 4)) >> (16 - gx_color_value_bits);
+    }
+    break;
+  case 24:
+    { gx_color_value c = (gx_color_value)color ^ 0xffffff;
+      prgb[0] = gx_color_value_from_byte(c >> 16);
+      prgb[1] = gx_color_value_from_byte((c >> 8) & 0xff);
+      prgb[2] = gx_color_value_from_byte(c & 0xff);
+    }
+    break;
+  case 32:
+#define  gx_maxcol gx_color_value_from_byte(gx_color_value_to_byte(gx_max_color_value))
+    { gx_color_value w = gx_maxcol - gx_color_value_from_byte(color >> 24);
+      prgb[0] = w - gx_color_value_from_byte((color >> 16) & 0xff);
+      prgb[1] = w - gx_color_value_from_byte((color >> 8) & 0xff);
+      prgb[2] = w - gx_color_value_from_byte(color & 0xff);
+    }
+    break;
+  }
+  return 0;
+}
+
+/* new_bpp == save_bpp or new_bpp == 0 means don't change bpp.
+   ccomps == 0 means don't change number of color comps.
+   If new_bpp != 0, it must be the value of the BitsPerPixel element of
+     the plist; real_bpp may differ from new_bpp.
+*/
+private int
+cdj_put_param_bpp(gx_device *pdev, gs_param_list *plist, int new_bpp,
+  int real_bpp, int ccomps)
+{
+	if (new_bpp == 0 && ccomps == 0)
+	  return gdev_prn_put_params(pdev, plist);
+	else
+	  {
+		gx_device_color_info save_info;
+		int save_bpp;
+		int code;
+
+		save_info = pdev->color_info;
+		save_bpp = save_info.depth;
+#define save_ccomps save_info.num_components
+		if ( save_bpp == 8 && save_ccomps == 3 && !cprn_device->cmyk)
+		  save_bpp = 3;
+		code = cdj_set_bpp(pdev, real_bpp, ccomps);
+		if ( code < 0 ) {
+		  param_signal_error(plist, "BitsPerPixel", code);
+		  param_signal_error(plist, "ProcessColorModel", code);
+		  return code;
+	        }
+		pdev->color_info.depth = new_bpp;  /* cdj_set_bpp maps 3/6 to 8 */
+		code = gdev_prn_put_params(pdev, plist);
+		if ( code < 0 )
+		  {	cdj_set_bpp(pdev, save_bpp, save_ccomps);
+			return code;
+		  }
+		cdj_set_bpp(pdev, real_bpp, ccomps);	/* reset depth if needed */
+		if ((cdj850->color_info.depth != save_bpp ||
+		     (ccomps != 0 && ccomps != save_ccomps))
+		    && pdev->is_open )
+		  return gs_closedevice(pdev);
+		return 0;
+#undef save_ccomps
+	  }
+}
+
+
