home *** CD-ROM | disk | FTP | other *** search
/ Der Mediaplex Sampler - Die 6 von Plex / 6_v_plex.zip / 6_v_plex / DISK5 / DOS_14 / GS252DVX.ZIP / GDEVCDJ.C < prev    next >
C/C++ Source or Header  |  1992-09-19  |  23KB  |  744 lines

  1. /* Copyright (C) 1991, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gdevcdj.c */
  21. /* H-P DeskJet 500C driver (colour) for Ghostscript */
  22. #include <stdlib.h>        /* for rand() */
  23. #include "gdevprn.h"
  24. #include "gdevpcl.h"
  25. #include "gsprops.h"
  26.  
  27. /***
  28.  *** Note: this driver was contributed by a user, George Cameron:
  29.  ***       please contact g.cameron@biomed.abdn.ac.uk if you have questions.
  30.  ***/
  31.  
  32. /*
  33.  * Note that there are three drivers contained in this code:
  34.  *
  35.  *     1 - cdeskjet:    A slightly updated version of the original
  36.  *                      cdeskjet driver.
  37.  *     2 - cdjcolor:    This is the significant addition - a 24-bit
  38.  *                      Floyd-Steinberg dithering driver, which gives
  39.  *                      excellent quality, but necessarily results in
  40.  *                      slow printing.
  41.  *     3 - cdjmono:     Included purely to give dj500c owners the benefit
  42.  *                      of Mode 9 fast printing with their black cartridge.
  43.  */
  44.  
  45. /*
  46.  * You may select a resolution of 75, 100, 150, or 300 DPI. Normally you
  47.  * would do this in the makefile or on the gs command line, not here.
  48.  * 
  49.  * If the preprocessor symbol A4 is defined, the default paper size is the
  50.  * European A4 size; otherwise it is the U.S. letter size (8.5"x11").
  51.  */
  52.  
  53. #define X_DPI_MAX 300
  54. #define Y_DPI_MAX 300
  55.  
  56. #ifndef X_DPI
  57. #  define X_DPI X_DPI_MAX
  58. #endif
  59. #ifndef Y_DPI
  60. #  define Y_DPI Y_DPI_MAX
  61. #endif
  62.  
  63. /*
  64.  * Maximum printing width = 2400 dots = 8"
  65.  *
  66.  * All Deskjets have 1/2" unprintable bottom margin
  67.  */
  68.  
  69. #define PRINT_LIMIT 0.0625    /* 'real' top margin? */
  70.  
  71. /* Margins are left, bottom, right, top. */
  72. #define DESKJET_MARGINS_LETTER  0.25, 0.50, 0.25, 0.167
  73. #define DESKJET_MARGINS_A4      0.15, 0.50, 0.15, 0.167
  74.  
  75. #ifndef A4
  76. #  define WIDTH_10THS           85
  77. #  define HEIGHT_10THS          110
  78. #  define DESKJET_MARGINS       DESKJET_MARGINS_LETTER
  79. #else
  80. #  define WIDTH_10THS           83      /* 210mm */
  81. #  define HEIGHT_10THS          117     /* 297mm */
  82. #  define DESKJET_MARGINS       DESKJET_MARGINS_A4
  83. #endif
  84.  
  85. /* The number of blank lines that make it worthwhile to reposition */
  86. /* the cursor. */
  87. #define MIN_SKIP_LINES 7
  88.  
  89. #define W sizeof(word)
  90. #define I sizeof(int)
  91. #define WSIZE(a) (((a) + W - 1) / W)
  92.  
  93. /* Printer types */
  94. #define DJ500C_COLOUR    0    /* Standard colour, GS internal dithering */
  95. #define DJ500C_COLOUR_FS 1    /* High quality dithering, but can be slow */
  96. #define DJ500C_MONO      2    /* Black ink + mode 9 compression */
  97.  
  98. /* Procedures */
  99. private dev_proc_map_rgb_color (gdev_pcl_true_map_rgb_color);
  100. private dev_proc_map_color_rgb (gdev_pcl_true_map_color_rgb);
  101.  
  102. /* The device descriptors */
  103. private dev_proc_open_device(hp_dj500c_open);
  104. private dev_proc_print_page(cdeskjet_print_page);
  105. private dev_proc_print_page(cdjcolor_print_page);
  106. private dev_proc_print_page(cdjmono_print_page);
  107. private dev_proc_get_props(hp_dj500c_get_props);
  108. private dev_proc_put_props(hp_dj500c_put_props);
  109.  
  110. /* The device descriptor */
  111. typedef struct gx_device_hp_dj500c_s gx_device_hp_dj500c;
  112. struct gx_device_hp_dj500c_s {
  113.         gx_device_common;
  114.         gx_prn_device_common;
  115.     int shingling;        /* Interlaced, multi-pass printing */
  116.                             /* 0 = none, 1 = 50%, 2 = 25%, 2 is best &
  117.                  * slowest */
  118.     int depletion;        /* 'Intelligent' dot-removal */
  119.                         /* 0 = none, 1 = 25%, 2 = 50%, 1 best for
  120.                 /* graphics? */
  121.                 /* Use 0 for transparencies */
  122. };
  123.  
  124. #define ppdev ((gx_device_hp_dj500c *)pdev)
  125.  
  126. #define hp_dj500c_device(procs, dev_name, width_10ths, height_10ths, x_dpi, y_dpi, l_margin, b_margin, r_margin, t_margin, color_bits, print_page, shingling, depletion)\
  127. { prn_device_body(gx_device_printer, procs, dev_name,\
  128.     width_10ths, height_10ths, x_dpi, y_dpi,\
  129.     l_margin, b_margin, r_margin, t_margin,\
  130.     (color_bits > 1 ? 3 : 1),\
  131.     ((color_bits > 1) & (color_bits < 8) ? 8 : color_bits),\
  132.     (color_bits >= 8 ? 255 : 1),\
  133.     (color_bits >= 8 ? 255 : color_bits > 1 ? 1 : 0),\
  134.     (color_bits >= 8 ? 5 : 2),\
  135.     (color_bits >= 8 ? 5 : color_bits > 1 ? 2 : 0),\
  136.     print_page),\
  137.     shingling,\
  138.     depletion\
  139. }
  140.  
  141. #define hp_dj500c_procs(proc_map_rgb_color, proc_map_color_rgb, proc_get_props, proc_put_props) {\
  142.     hp_dj500c_open,\
  143.     gdev_pcl_get_initial_matrix,\
  144.     gx_default_sync_output,\
  145.     gdev_prn_output_page,\
  146.     gdev_prn_close,\
  147.     proc_map_rgb_color,\
  148.     proc_map_color_rgb,\
  149.     NULL,    /* fill_rectangle */\
  150.     NULL,    /* tile_rectangle */\
  151.     NULL,    /* copy_mono */\
  152.     NULL,    /* copy_color */\
  153.     NULL,    /* draw_line */\
  154.     gx_default_get_bits,\
  155.     proc_get_props,\
  156.     proc_put_props\
  157. }
  158.  
  159. private gx_device_procs cdeskjet_procs =
  160. hp_dj500c_procs(gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb,
  161.         hp_dj500c_get_props, hp_dj500c_put_props);
  162.  
  163. private gx_device_procs cdjcolor_procs =
  164. hp_dj500c_procs(gdev_pcl_true_map_rgb_color, gdev_pcl_true_map_color_rgb,
  165.         hp_dj500c_get_props, hp_dj500c_put_props);
  166.  
  167. private gx_device_procs cdjmono_procs =
  168. hp_dj500c_procs(gdev_prn_map_rgb_color, gdev_prn_map_color_rgb,
  169.         hp_dj500c_get_props, hp_dj500c_put_props);
  170.  
  171. gx_device_hp_dj500c gs_cdeskjet_device =
  172. hp_dj500c_device(cdeskjet_procs, "cdeskjet",
  173.        WIDTH_10THS, HEIGHT_10THS,
  174.        X_DPI, Y_DPI,
  175.        0, 0, 0, 0,
  176.        3, cdeskjet_print_page, 1, 1);
  177.  
  178. gx_device_hp_dj500c gs_cdjcolor_device =
  179. hp_dj500c_device(cdjcolor_procs, "cdjcolor",
  180.        WIDTH_10THS, HEIGHT_10THS,
  181.        X_DPI, Y_DPI,
  182.        0, 0, 0, 0,
  183.        24, cdjcolor_print_page, 2, 1);
  184.  
  185. gx_device_hp_dj500c gs_cdjmono_device =
  186. hp_dj500c_device(cdjmono_procs, "cdjmono",
  187.        WIDTH_10THS, HEIGHT_10THS,
  188.        X_DPI, Y_DPI,
  189.        0, 0, 0, 0,
  190.        1, cdjmono_print_page, 1, 1);
  191.  
  192. /* Forward references */
  193. private int gdev_pcl_mode9compress(P4(int, const byte *, byte *, byte *));
  194. private int hp_dj500c_print_page(P3(gx_device_printer *, FILE *, int));
  195.  
  196. /* Open the printer and set up the margins. */
  197. private int
  198. hp_dj500c_open(gx_device *pdev)
  199. {       /* Change the margins if necessary. */
  200.   static const float m_a4[4] = { DESKJET_MARGINS_A4 };
  201.   static const float m_letter[4] = { DESKJET_MARGINS_LETTER };
  202.   const float _ds *m =
  203.     (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 :
  204.      m_letter);
  205.   pdev->l_margin = m[0];
  206.   pdev->b_margin = m[1];
  207.   pdev->r_margin = m[2];
  208.   pdev->t_margin = m[3];
  209.   return gdev_prn_open(pdev);
  210. }
  211.  
  212. /* Added properties for DeskJet 500C */
  213.  
  214. private const gs_prop_item props_dj500c[] = {
  215.   /* Read-write properties. */
  216.   prop_def("Shingling", prt_int),
  217.   prop_def("Depletion", prt_int),
  218. };
  219.  
  220. /* Get properties.  In addition to the standard and printer */
  221. /* properties, we supply shingling and depletion parameters */
  222. private int
  223. hp_dj500c_get_props(gx_device *pdev, gs_prop_item *plist)
  224. {    int start = gdev_prn_get_props(pdev, plist);
  225.     if ( plist != 0 )
  226.        {    register gs_prop_item *pi = plist + start;
  227.         memcpy(pi, props_dj500c, sizeof(props_dj500c));
  228.         pi[0].value.i = ppdev->shingling;
  229.         pi[1].value.i = ppdev->depletion;
  230.        }
  231.     return start + sizeof(props_dj500c) / sizeof(gs_prop_item);
  232. }
  233.  
  234. /* Put properties. */
  235. private int
  236. hp_dj500c_put_props(gx_device *pdev, gs_prop_item *plist, int count)
  237. {    gs_prop_item *known[2];
  238.     int code = 0;
  239.     int j;
  240.     props_extract(plist, count, props_dj500c, 2, known, 0);
  241.     code = gdev_prn_put_props(pdev, plist, count);
  242.     if ( code < 0 ) return code;
  243.     for (j = 0; j < 2; j++) {
  244.       if ( known[j] != 0 ) {
  245.         gs_prop_item *pi = known[j];
  246.         if ( pi->value.i < 0 || pi->value.i > 2 )
  247.           pi->status = pv_rangecheck,
  248.           code = gs_error_rangecheck;
  249.         else {
  250.           switch (j) {
  251.           case 0:
  252.         ppdev->shingling = known[j]->value.i;
  253.         break;
  254.           case 1:
  255.         ppdev->depletion = known[j]->value.i;
  256.         break;
  257.           }
  258.           if ( code == 0 ) code = 1;
  259.         }
  260.       }
  261.     }
  262.     if ( code < 0 )
  263.         return_error(code);
  264.     return code;
  265. }
  266.  
  267. /* ------ Internal routines ------ */
  268.  
  269. /* The DeskJet 500C can compress (mode 9, for all versions) */
  270. private int
  271. cdeskjet_print_page(gx_device_printer * pdev, FILE * prn_stream)
  272. {
  273.   return hp_dj500c_print_page(pdev, prn_stream, DJ500C_COLOUR);
  274. }
  275.  
  276. private int
  277. cdjcolor_print_page(gx_device_printer * pdev, FILE * prn_stream)
  278. {
  279.   return hp_dj500c_print_page(pdev, prn_stream, DJ500C_COLOUR_FS);
  280. }
  281.  
  282. private int
  283. cdjmono_print_page(gx_device_printer * pdev, FILE * prn_stream)
  284. {
  285.   return hp_dj500c_print_page(pdev, prn_stream, DJ500C_MONO);
  286. }
  287.  
  288. /* Some convenient shorthand .. */
  289. #define x_dpi    (pdev->x_pixels_per_inch)
  290. #define y_dpi    (pdev->y_pixels_per_inch)
  291. #define height   (pdev->height)
  292. #define t_margin (pdev->t_margin)
  293. #define b_margin (pdev->b_margin)
  294. #define XTRA 12                /* 2 x 6 XTRA values for end-of-line */
  295.                                 /* in FSdither error buffers */
  296.  
  297. /* Floyd-Steinberg dithering. Often results in a dramatic improvement in
  298.  * subjective image quality, but can also produce dramatic increases in
  299.  * amount of printer data generated and actual printing time!! Mode 9 2D
  300.  * compression is still useful for fairly flat colour or blank areas but its
  301.  * compression is much less effective in areas where the dithering has
  302.  * effectively randomised the dot distribution. This is a first attempt, but
  303.  * it seems to work reasonably well for the images I've tried. */
  304. #define MAXVALUE  0xff
  305. #define THRESHOLD 0x80
  306. #define C 4                /* ought to be 8, but this seems to be too much */
  307. #define FSdither(inP, out, errP, Err, Bit, DD, II, Offset)\
  308.     oldErr = Err;\
  309.     Err = (* DD errP + ((Err * 7 + C) >> 4) + *(DD inP II));\
  310.     if (Err > THRESHOLD) {\
  311.       out |= Bit;\
  312.       Err -= MAXVALUE;\
  313.     }\
  314.     errP[Offset 6] += ((oldErr * 3 + C) >> 4);\
  315.     errP[Offset 3] += ((oldErr * 5 + C) >> 4);\
  316.     * errP II = ((oldErr + C) >> 4);
  317.  
  318. /* Send the page to the printer.  Compress each scan line. */
  319. private int
  320. hp_dj500c_print_page(gx_device_printer * pdev, FILE * prn_stream, int ptype)
  321. {
  322.   int line_size = gdev_prn_raster(pdev);
  323.   int line_size_words = WSIZE(line_size);
  324.   int paper_size = gdev_pcl_paper_size((gx_device *)pdev);
  325.   int num_comps = pdev->color_info.num_components;
  326.   int plane_size;
  327.   int buffer_size;
  328.   int *errors;
  329.   byte *data, *plane_data[3], *prev_plane_data[3], *out_data;
  330.   word *storage, *data_words;
  331.   uint storage_size_words;
  332.  
  333.   switch (ptype) {
  334.   case DJ500C_COLOUR:
  335.     plane_size = (line_size + 7) / 8;
  336.     buffer_size = plane_size * 8;
  337.     storage_size_words = WSIZE(plane_size * (8 + 3 + 3));
  338.     /* data, plane, prev_plane */
  339.     break;
  340.   case DJ500C_COLOUR_FS:
  341.     plane_size = (line_size + 23) / 24;
  342.     buffer_size = plane_size * 24;
  343.     storage_size_words = WSIZE(plane_size * (24 * I + 24 + 3 + 3) + XTRA * I);
  344.     /* errors, data, plane, prev_plane, XTRA */
  345.     break;
  346.   case DJ500C_MONO:
  347.     plane_size = WSIZE(line_size) * W;
  348.     buffer_size = plane_size;
  349.     storage_size_words = WSIZE(plane_size * (1 + 1 + 2));
  350.     /* plane, prev_plane, out_data */
  351.     break;
  352.   }
  353.   storage = (ulong *) gs_malloc(storage_size_words, W, "hp_dj500c_print_page");
  354.   data_words = storage;
  355.  
  356.   if (storage == 0)        /* can't allocate working area */
  357.     return_error(gs_error_VMerror);
  358.   else {
  359.     int i;
  360.     byte *p = data = out_data = (byte *) storage;
  361.     if ((ptype == DJ500C_COLOUR) || (ptype == DJ500C_COLOUR_FS)) {
  362.       p += buffer_size;
  363.     }
  364.     if (ptype == DJ500C_COLOUR_FS) {
  365.       errors = (int *)p;
  366.       p += (buffer_size + XTRA) * I;
  367.     }
  368.     for (i = 0; i < num_comps; i++) {
  369.       plane_data[i] = p;
  370.       p += plane_size;
  371.     }
  372.     for (i = 0; i < num_comps; i++) {
  373.       prev_plane_data[i] = p;
  374.       p += plane_size;
  375.     }
  376.     if (ptype == DJ500C_MONO) {
  377.       out_data = p;        /* size is plane_size x 2 */
  378.     }
  379.   }
  380.  
  381.   /* Clear temp storage */
  382.   memset(storage, 0, storage_size_words * W);
  383.  
  384.   /* Initialize printer. */
  385.   fputs("\033E", prn_stream);                          /* reset printer */
  386.   fputs("\033*rbC", prn_stream);                      /* end raster graphics */
  387.   fprintf(prn_stream, "\033*t%dR", (int)x_dpi);          /* set resolution */
  388.   fprintf(prn_stream, "\033&l%da0o0e0L", paper_size); /* paper size etc. */
  389.  
  390.   /* set the number of color planes (1 or 3). -3 means CMY in colour mode */
  391.   fprintf(prn_stream, "\033*r-%dU", num_comps);
  392.  
  393.   /* set depletion and shingling levels */
  394.   fprintf(prn_stream, "\033*o%dd%dQ", ppdev->depletion, ppdev->shingling);
  395.  
  396.   /* move to top left of printed area */
  397. #define OFFSET (t_margin - PRINT_LIMIT)    /* Offset to print position */
  398.   fprintf(prn_stream, "\033*p0x%dY", (int)(Y_DPI_MAX * OFFSET));
  399.  
  400.   /* select data compression */
  401.   fputs("\033*b9M", prn_stream);/* mode 9 */
  402.  
  403.   /* Start raster graphics.  From now on */
  404.   /* all escape commands start with \033*b, */
  405.   /* so we combine them. */
  406.   fputs("\033*r1A\033*b", prn_stream);
  407.  
  408.   /* Send each scan line in turn */
  409.   {
  410.     int lnum, i;
  411.     int lend = height - (t_margin + b_margin) * y_dpi;
  412.     int num_blank_lines = 0;
  413.     word rmask = ~(word) 0 << (-pdev->width & (W * 8 - 1));
  414.     int c, m, y, cErr, mErr, yErr;
  415.     int going_up = 1;
  416.     byte *cP = plane_data[0], *mP = plane_data[1], *yP = plane_data[2];
  417.     register int *ep = errors + (XTRA / 2);
  418.     register byte *dp = data;
  419.  
  420.     c = m = y = cErr = mErr = yErr = 0;
  421.  
  422.     if (ptype == DJ500C_COLOUR_FS) { /* Randomly seed initial error buffer */
  423.       for (i = 0; i < buffer_size; i++) {
  424.     *ep++ = (rand() % MAXVALUE) >> 4;
  425.       }
  426.       ep = errors + (XTRA / 2);
  427.     }
  428.  
  429.     for (lnum = 0; lnum < lend; lnum++) {
  430.       register word *end_data = data_words + line_size_words;
  431.       gdev_prn_copy_scan_lines(pdev, lnum, data, line_size);
  432.  
  433.       /* Mask off 1-bits beyond the line width. */
  434.       end_data[-1] &= rmask;
  435.  
  436.       /* Remove trailing 0s. */
  437.       while (end_data > data_words && end_data[-1] == 0)
  438.     end_data--;
  439.       if (end_data == data_words) {    /* Blank line */
  440.     num_blank_lines++;
  441.     continue;
  442.       }
  443.       /* Skip blank lines if any */
  444.       if (num_blank_lines > 0) {
  445.     if (num_blank_lines < MIN_SKIP_LINES) {
  446.       /* Moving down from current position */
  447.       /* causes head motion on the DeskJet, so */
  448.       /* if the number of lines is small, */
  449.       /* we're better off printing blanks. */
  450.       fputs("y", prn_stream); /* Clear current and seed rows */
  451.       for (; num_blank_lines; num_blank_lines--)
  452.         fputs("w", prn_stream);
  453.     } else {
  454.       fprintf(prn_stream, "%dy", num_blank_lines);
  455.     }
  456.     memset(prev_plane_data[0], 0, plane_size * num_comps);
  457.     num_blank_lines = 0;
  458.       } {            /* Printing non-blank lines */
  459.     int i, j;
  460.     byte *odp;
  461.  
  462.     /* In colour modes, we have some bit-shuffling to do before */
  463.     /* we can print the data; in FS mode we also have the */
  464.     /* dithering to take care of. */
  465.     switch (ptype) {
  466.     case DJ500C_COLOUR:
  467.  
  468.       /* Transpose the data to get pixel planes. */
  469.       for (i = 0, odp = plane_data[0]; i < buffer_size;
  470.            i += 8, odp++) {    /* The following is for 16-bit
  471.                  * machines */
  472. #define spread3(c)\
  473. { 0, c, c*0x100, c*0x101, c*0x10000L, c*0x10001L, c*0x10100L, c*0x10101L }
  474.         static ulong spr40[8] = spread3(0x40);
  475.         static ulong spr08[8] = spread3(8);
  476.         static ulong spr02[8] = spread3(2);
  477.         register byte *dp = data + i;
  478.         register ulong pword =
  479.         (spr40[dp[0]] << 1) +
  480.         (spr40[dp[1]]) +
  481.         (spr40[dp[2]] >> 1) +
  482.         (spr08[dp[3]] << 1) +
  483.         (spr08[dp[4]]) +
  484.         (spr08[dp[5]] >> 1) +
  485.         (spr02[dp[6]]) +
  486.         (spr02[dp[7]] >> 1);
  487.         odp[0] = (byte) (pword >> 16);
  488.         odp[plane_size] = (byte) (pword >> 8);
  489.         odp[plane_size * 2] = (byte) (pword);
  490.       }
  491.       break;
  492.  
  493.     case DJ500C_COLOUR_FS:
  494.  
  495.       if (going_up) {
  496.         for (i = 0; i < plane_size; i++) {
  497.           byte c, y, m, bitmask;
  498.           int oldErr;
  499.  
  500.           bitmask = 0x80;
  501.           for (c = m = y = j = 0; j < 8; j++) {
  502.         FSdither(dp, c, ep, cErr, bitmask,, ++, -);
  503.         FSdither(dp, m, ep, mErr, bitmask,, ++, -);
  504.         FSdither(dp, y, ep, yErr, bitmask,, ++, -);
  505.         bitmask >>= 1;
  506.           }
  507.           *cP++ = c;
  508.           *mP++ = m;
  509.           *yP++ = y;
  510.         }
  511.       } else {        /* going_down */
  512.         for (i = 0; i < plane_size; i++) {
  513.           byte c, y, m, bitmask;
  514.           int oldErr;
  515.  
  516.           bitmask = 0x01;
  517.           for (c = m = y = j = 0; j < 8; j++) {
  518.         FSdither(dp, y, ep, yErr, bitmask, --,, +);
  519.         FSdither(dp, m, ep, mErr, bitmask, --,, +);
  520.         FSdither(dp, c, ep, cErr, bitmask, --,, +);
  521.         bitmask <<= 1;
  522.           }
  523.           *--cP = c;
  524.           *--mP = m;
  525.           *--yP = y;
  526.         }
  527.       }
  528.       going_up = !going_up;       /* toggle scan direction */
  529.       break;
  530.     } /* switch() DJET500C_COLOUR and DJET500C_COLOUR_FS */
  531.  
  532.     /* Transfer raster graphics */
  533.     /* in the order C, M, Y. */
  534.     for (i = num_comps - 1; i >= 0; i--) {
  535.  
  536.       int out_count = gdev_pcl_mode9compress(plane_size,
  537.                          plane_data[i],
  538.                          prev_plane_data[i],
  539.                          out_data);
  540.  
  541.       fprintf(prn_stream, "%d%c", out_count, "wvv"[i]);
  542.       fwrite(out_data, sizeof(byte), out_count, prn_stream);
  543.     }
  544.       }      /* Printing non-blank lines */
  545.     }     /* for lnum ... */
  546.   }       /* send each scan line in turn */
  547.  
  548.   /* end raster graphics */
  549.   fputs("\033*rbC", prn_stream);
  550.  
  551.   /* reset to monochrome */
  552.   fputs("\033*r1U", prn_stream);
  553.  
  554.   /* eject page */
  555.   fputs("\033&l0H", prn_stream);
  556.  
  557.   /* free temporary storage */
  558.   gs_free((char *) storage, storage_size_words, W, "hp_dj500c_print_page");
  559.  
  560.   return 0;
  561. }
  562.  
  563. /*
  564.  * Mode 9 2D compression for the HP DeskJet 500C. This mode can give
  565.  * very good compression ratios, especially if there are areas of flat
  566.  * colour (or blank areas), and so is 'highly recommended' for colour
  567.  * printing in particular because of the very large amounts of data which
  568.  * can be generated
  569.  */
  570. private int
  571. gdev_pcl_mode9compress(int bytecount, const byte * current, byte * previous, byte * compressed)
  572. {
  573.   register const byte *cur = current;
  574.   register byte *prev = previous;
  575.   register byte *out = compressed;
  576.   const byte *end = current + bytecount;
  577.  
  578.   while (cur < end) {        /* Detect a run of unchanged bytes. */
  579.     const byte *run = cur;
  580.     register const byte *diff;
  581.     int offset;
  582.     while (cur < end && *cur == *prev) {
  583.       cur++, prev++;
  584.     }
  585.     if (cur == end)
  586.       break;            /* rest of row is unchanged */
  587.     /* Detect a run of changed bytes. */
  588.     /* We know that *cur != *prev. */
  589.     diff = cur;
  590.     do {
  591.       *prev++ = *cur++;
  592.     }
  593.     while (cur < end && *cur != *prev);
  594.     /* Now [run..diff) are unchanged, and */
  595.     /* [diff..cur) are changed. */
  596.     offset = diff - run;
  597.     {
  598.       const byte *stop_test = cur - 4;
  599.       int dissimilar, similar;
  600.  
  601.       while (diff < cur) {
  602.     const byte *compr = diff;
  603.     const byte *next;    /* end of run */
  604.     byte value;
  605.     while (diff <= stop_test &&
  606.            ((value = *diff) != diff[1] ||
  607.         value != diff[2] ||
  608.         value != diff[3]))
  609.       diff++;
  610.  
  611.     /* Find out how long the run is */
  612.     if (diff > stop_test)    /* no run */
  613.       next = diff = cur;
  614.     else {
  615.       next = diff + 4;
  616.       while (next < cur && *next == value)
  617.         next++;
  618.     }
  619.  
  620. #define MAXOFFSETU 15
  621. #define MAXCOUNTU 7
  622.     /* output 'dissimilar' bytes, uncompressed */
  623.     if ((dissimilar = diff - compr)) {
  624.       int temp, i;
  625.  
  626.       if ((temp = --dissimilar) > MAXCOUNTU)
  627.         temp = MAXCOUNTU;
  628.       if (offset < MAXOFFSETU)
  629.         *out++ = (offset << 3) | (byte) temp;
  630.       else {
  631.         *out++ = (MAXOFFSETU << 3) | (byte) temp;
  632.         offset -= MAXOFFSETU;
  633.         while (offset >= 255) {
  634.           *out++ = 255;
  635.           offset -= 255;
  636.         }
  637.         *out++ = offset;
  638.       }
  639.       if (temp == MAXCOUNTU) {
  640.         temp = dissimilar - MAXCOUNTU;
  641.         while (temp >= 255) {
  642.           *out++ = 255;
  643.           temp -= 255;
  644.         }
  645.         *out++ = (byte) temp;
  646.       }
  647.       for (i = 0; i <= dissimilar; i++)
  648.         *out++ = *compr++;
  649.       offset = 0;
  650.     }            /* end uncompressed */
  651. #define MAXOFFSETC 3
  652. #define MAXCOUNTC 31
  653.     /* output 'similar' bytes, run-length encoded */
  654.     if ((similar = next - diff)) {
  655.       int temp;
  656.  
  657.       if ((temp = (similar -= 2)) > MAXCOUNTC)
  658.         temp = MAXCOUNTC;
  659.       if (offset < MAXOFFSETC)
  660.         *out++ = 0x80 | (offset << 5) | (byte) temp;
  661.       else {
  662.         *out++ = 0x80 | (MAXOFFSETC << 5) | (byte) temp;
  663.         offset -= MAXOFFSETC;
  664.         while (offset >= 255) {
  665.           *out++ = 255;
  666.           offset -= 255;
  667.         }
  668.         *out++ = offset;
  669.       }
  670.       if (temp == MAXCOUNTC) {
  671.         temp = similar - MAXCOUNTC;
  672.         while (temp >= 255) {
  673.           *out++ = 255;
  674.           temp -= 255;
  675.         }
  676.         *out++ = (byte) temp;
  677.       }
  678.       *out++ = value;
  679.       offset = 0;
  680.     }            /* end compressed */
  681.     diff = next;
  682.       }
  683.     }
  684.   }
  685.   return out - compressed;
  686. }
  687.  
  688. /* Map a r-g-b color to a color index. */
  689. /* We complement the colours, since we're using cmy anyway, */
  690. /* and because the buffering routines expect white to be zero. */
  691. private gx_color_index
  692. gdev_pcl_true_map_rgb_color(gx_device * dev, gx_color_value r,
  693.                 gx_color_value g, gx_color_value b)
  694. {
  695.   if ((r & g & b) == 0xff)
  696.     return (gx_color_index)0;   /* white */
  697.   else
  698.     return (gx_color_value_to_byte(r) +
  699.         ((uint) gx_color_value_to_byte(g) << 8) +
  700.         ((ulong) gx_color_value_to_byte(b) << 16)) ^ 0xffffff;
  701. }
  702.  
  703. /* Map a color index to a r-g-b color. */
  704. /* Includes colour balancing, following HP recommendations, to try */
  705. /* and correct the greenish cast resulting from an equal mix of the */
  706. /* c, m, y, inks to give a truer black. */
  707. /* Someday we can add gamma-lookup tables as well */
  708. private int
  709. gdev_pcl_true_map_color_rgb(gx_device * dev, gx_color_index color,
  710.                 gx_color_value prgb[3])
  711. {
  712.   /* NB. We actually have cmy colours, from the way we set up the */
  713.   /* mapping rgb_color */
  714.   int c = (int)(color >> 16);
  715.   int m = (int)((color >> 8) & 0xff);
  716.   int y = (int)(color & 0xff);
  717.   if ((c & m & y) == 0)    /* white */
  718.     return 0;
  719.   else {
  720.     int maxval, minval, range;
  721.  
  722.     maxval = c >= m ? c : m;
  723.     maxval = maxval >= y ? maxval : y;
  724.     if (maxval > 0) {
  725.       minval = c <= m ? c : m;
  726.       minval = minval <= y ? minval : y;
  727.       range = maxval - minval;
  728.  
  729. #define CORRECTION 4  /* ie. 4/5 reduction in cyan to get true black */
  730.       c = ((long)(c << 1) + (range + (long)(maxval * CORRECTION)) + 1) /
  731.     (long)(maxval * ((CORRECTION + 1) << 1));
  732.       
  733.       prgb[0] = (gx_color_value)c;
  734.       prgb[1] = (gx_color_value)m;
  735.       prgb[2] = (gx_color_value)y;
  736.     }
  737.   }
  738.   return 0;
  739. }
  740.  
  741. #undef t_margin
  742. #undef b_margin
  743. #undef height
  744.