xref: /plan9-contrib/sys/src/cmd/gs/src/gdevdm24.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1992, 1996, 1997 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier #include "gdevprn.h"
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier 
20*593dc095SDavid du Colombier /* $Id: gdevdm24.c,v 1.8 2004/08/04 23:33:29 stefan Exp $*/
217dd7cddfSDavid du Colombier /* High-res 24Dot-matrix printer driver */
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier /* Supported printers
247dd7cddfSDavid du Colombier  *  NEC P6 and similar, implemented by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
257dd7cddfSDavid du Colombier  *  Epson LQ850, implemented by Christian Felsch (felsch@tu-harburg.d400.de)
267dd7cddfSDavid du Colombier  */
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier /* Driver for NEC P6 */
297dd7cddfSDavid du Colombier private dev_proc_print_page (necp6_print_page);
303ff48bf5SDavid du Colombier const gx_device_printer far_data gs_necp6_device =
317dd7cddfSDavid du Colombier   prn_device (prn_std_procs, "necp6",
327dd7cddfSDavid du Colombier 	      DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
337dd7cddfSDavid du Colombier 	      360, 360,
347dd7cddfSDavid du Colombier 	      0, 0, 0.5, 0,	/* margins */
357dd7cddfSDavid du Colombier 	      1, necp6_print_page);
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier /* Driver for Epson LQ850 */
397dd7cddfSDavid du Colombier /* I've tested this driver on a BJ300 with LQ850 emulation and there it produce correct 360x360dpi output. */
407dd7cddfSDavid du Colombier private dev_proc_print_page (lq850_print_page);
413ff48bf5SDavid du Colombier const gx_device_printer gs_lq850_device =
427dd7cddfSDavid du Colombier   prn_device (prn_std_procs, "lq850",
437dd7cddfSDavid du Colombier 	      DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
447dd7cddfSDavid du Colombier 	      360, 360,
457dd7cddfSDavid du Colombier 	      0, 0, 0.5, 0,	/* margins */
467dd7cddfSDavid du Colombier 	      1, lq850_print_page);
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier /* ------ Internal routines ------ */
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier /* Forward references */
51*593dc095SDavid du Colombier private void dot24_output_run (byte *, int, int, FILE *);
52*593dc095SDavid du Colombier private void dot24_improve_bitmap (byte *, int);
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier /* Send the page to the printer. */
557dd7cddfSDavid du Colombier private int
dot24_print_page(gx_device_printer * pdev,FILE * prn_stream,char * init_string,int init_len)567dd7cddfSDavid du Colombier dot24_print_page (gx_device_printer *pdev, FILE *prn_stream, char *init_string, int init_len)
577dd7cddfSDavid du Colombier {
58*593dc095SDavid du Colombier   int xres = (int)pdev->x_pixels_per_inch;
59*593dc095SDavid du Colombier   int yres = (int)pdev->y_pixels_per_inch;
607dd7cddfSDavid du Colombier   int x_high = (xres == 360);
617dd7cddfSDavid du Colombier   int y_high = (yres == 360);
627dd7cddfSDavid du Colombier   int bits_per_column = (y_high ? 48 : 24);
637dd7cddfSDavid du Colombier   uint line_size = gdev_prn_raster (pdev);
647dd7cddfSDavid du Colombier   uint in_size = line_size * bits_per_column;
65*593dc095SDavid du Colombier   byte *in = (byte *) gs_malloc (pdev->memory, in_size, 1, "dot24_print_page (in)");
667dd7cddfSDavid du Colombier   uint out_size = ((pdev->width + 7) & -8) * 3;
67*593dc095SDavid du Colombier   byte *out = (byte *) gs_malloc (pdev->memory, out_size, 1, "dot24_print_page (out)");
687dd7cddfSDavid du Colombier   int y_passes = (y_high ? 2 : 1);
697dd7cddfSDavid du Colombier   int dots_per_space = xres / 10;	/* pica space = 1/10" */
707dd7cddfSDavid du Colombier   int bytes_per_space = dots_per_space * 3;
717dd7cddfSDavid du Colombier   int skip = 0, lnum = 0, ypass;
727dd7cddfSDavid du Colombier 
737dd7cddfSDavid du Colombier   /* Check allocations */
747dd7cddfSDavid du Colombier   if (in == 0 || out == 0)
757dd7cddfSDavid du Colombier     {
767dd7cddfSDavid du Colombier       if (out)
77*593dc095SDavid du Colombier 	gs_free (pdev->memory, (char *) out, out_size, 1, "dot24_print_page (out)");
787dd7cddfSDavid du Colombier       if (in)
79*593dc095SDavid du Colombier 	gs_free (pdev->memory, (char *) in, in_size, 1, "dot24_print_page (in)");
807dd7cddfSDavid du Colombier       return_error (gs_error_VMerror);
817dd7cddfSDavid du Colombier     }
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier   /* Initialize the printer and reset the margins. */
847dd7cddfSDavid du Colombier   fwrite (init_string, init_len - 1, sizeof (char), prn_stream);
857dd7cddfSDavid du Colombier   fputc ((int) (pdev->width / pdev->x_pixels_per_inch * 10) + 2,
867dd7cddfSDavid du Colombier 	 prn_stream);
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier   /* Print lines of graphics */
897dd7cddfSDavid du Colombier   while (lnum < pdev->height)
907dd7cddfSDavid du Colombier     {
917dd7cddfSDavid du Colombier       byte *inp;
927dd7cddfSDavid du Colombier       byte *in_end;
937dd7cddfSDavid du Colombier       byte *out_end;
947dd7cddfSDavid du Colombier       byte *out_blk;
957dd7cddfSDavid du Colombier       register byte *outp;
967dd7cddfSDavid du Colombier       int lcnt;
977dd7cddfSDavid du Colombier 
987dd7cddfSDavid du Colombier       /* Copy 1 scan line and test for all zero. */
997dd7cddfSDavid du Colombier       gdev_prn_copy_scan_lines (pdev, lnum, in, line_size);
1007dd7cddfSDavid du Colombier       if (in[0] == 0
1017dd7cddfSDavid du Colombier 	  && !memcmp ((char *) in, (char *) in + 1, line_size - 1))
1027dd7cddfSDavid du Colombier 	{
1037dd7cddfSDavid du Colombier 	  lnum++;
1047dd7cddfSDavid du Colombier 	  skip += 2 - y_high;
1057dd7cddfSDavid du Colombier 	  continue;
1067dd7cddfSDavid du Colombier 	}
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier       /* Vertical tab to the appropriate position. */
1097dd7cddfSDavid du Colombier       while ((skip >> 1) > 255)
1107dd7cddfSDavid du Colombier 	{
1117dd7cddfSDavid du Colombier 	  fputs ("\033J\377", prn_stream);
1127dd7cddfSDavid du Colombier 	  skip -= 255 * 2;
1137dd7cddfSDavid du Colombier 	}
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier       if (skip)
1167dd7cddfSDavid du Colombier 	{
1177dd7cddfSDavid du Colombier 	  if (skip >> 1)
1187dd7cddfSDavid du Colombier 	    fprintf (prn_stream, "\033J%c", skip >> 1);
1197dd7cddfSDavid du Colombier 	  if (skip & 1)
1207dd7cddfSDavid du Colombier 	    fputc ('\n', prn_stream);
1217dd7cddfSDavid du Colombier 	}
1227dd7cddfSDavid du Colombier 
1237dd7cddfSDavid du Colombier       /* Copy the rest of the scan lines. */
1247dd7cddfSDavid du Colombier       if (y_high)
1257dd7cddfSDavid du Colombier 	{
1267dd7cddfSDavid du Colombier 	  inp = in + line_size;
1277dd7cddfSDavid du Colombier 	  for (lcnt = 1; lcnt < 24; lcnt++, inp += line_size)
1287dd7cddfSDavid du Colombier 	    if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2, inp,
1297dd7cddfSDavid du Colombier 					   line_size))
1307dd7cddfSDavid du Colombier 	      {
1317dd7cddfSDavid du Colombier 		memset (inp, 0, (24 - lcnt) * line_size);
1327dd7cddfSDavid du Colombier 		break;
1337dd7cddfSDavid du Colombier 	      }
1347dd7cddfSDavid du Colombier 	  inp = in + line_size * 24;
1357dd7cddfSDavid du Colombier 	  for (lcnt = 0; lcnt < 24; lcnt++, inp += line_size)
1367dd7cddfSDavid du Colombier 	    if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2 + 1, inp,
1377dd7cddfSDavid du Colombier 					   line_size))
1387dd7cddfSDavid du Colombier 	      {
1397dd7cddfSDavid du Colombier 		memset (inp, 0, (24 - lcnt) * line_size);
1407dd7cddfSDavid du Colombier 		break;
1417dd7cddfSDavid du Colombier 	      }
1427dd7cddfSDavid du Colombier 	}
1437dd7cddfSDavid du Colombier       else
1447dd7cddfSDavid du Colombier 	{
1457dd7cddfSDavid du Colombier 	  lcnt = 1 + gdev_prn_copy_scan_lines (pdev, lnum + 1, in + line_size,
1467dd7cddfSDavid du Colombier 					       in_size - line_size);
1477dd7cddfSDavid du Colombier 	  if (lcnt < 24)
1487dd7cddfSDavid du Colombier 	    /* Pad with lines of zeros. */
1497dd7cddfSDavid du Colombier 	    memset (in + lcnt * line_size, 0, in_size - lcnt * line_size);
1507dd7cddfSDavid du Colombier 	}
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier       for (ypass = 0; ypass < y_passes; ypass++)
1537dd7cddfSDavid du Colombier 	{
1547dd7cddfSDavid du Colombier 	  out_end = out;
1557dd7cddfSDavid du Colombier 	  inp = in;
1567dd7cddfSDavid du Colombier 	  if (ypass)
1577dd7cddfSDavid du Colombier 	    inp += line_size * 24;
1587dd7cddfSDavid du Colombier 	  in_end = inp + line_size;
1597dd7cddfSDavid du Colombier 
1607dd7cddfSDavid du Colombier 	  for (; inp < in_end; inp++, out_end += 24)
1617dd7cddfSDavid du Colombier 	    {
1627dd7cddfSDavid du Colombier 	      memflip8x8 (inp, line_size, out_end, 3);
1637dd7cddfSDavid du Colombier 	      memflip8x8 (inp + line_size * 8, line_size, out_end + 1, 3);
1647dd7cddfSDavid du Colombier 	      memflip8x8 (inp + line_size * 16, line_size, out_end + 2, 3);
1657dd7cddfSDavid du Colombier 	    }
1667dd7cddfSDavid du Colombier 	  /* Remove trailing 0s. */
1677dd7cddfSDavid du Colombier 	  while (out_end - 3 >= out && out_end[-1] == 0
1687dd7cddfSDavid du Colombier 		 && out_end[-2] == 0 && out_end[-3] == 0)
1697dd7cddfSDavid du Colombier 	    out_end -= 3;
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	  for (out_blk = outp = out; outp < out_end;)
1727dd7cddfSDavid du Colombier 	    {
1737dd7cddfSDavid du Colombier 	      /* Skip a run of leading 0s. */
1747dd7cddfSDavid du Colombier 	      /* At least 10 are needed to make tabbing worth it. */
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier 	      if (outp[0] == 0 && outp + 12 <= out_end
1777dd7cddfSDavid du Colombier 		  && outp[1] == 0 && outp[2] == 0
1787dd7cddfSDavid du Colombier 		  && outp[3] == 0 && outp[4] == 0 && outp[5] == 0
1797dd7cddfSDavid du Colombier 		  && outp[6] == 0 && outp[7] == 0 && outp[8] == 0
1807dd7cddfSDavid du Colombier 		  && outp[9] == 0 && outp[10] == 0 && outp[11] == 0)
1817dd7cddfSDavid du Colombier 		{
1827dd7cddfSDavid du Colombier 		  byte *zp = outp;
1837dd7cddfSDavid du Colombier 		  int tpos;
1847dd7cddfSDavid du Colombier 		  byte *newp;
1857dd7cddfSDavid du Colombier 		  outp += 12;
1867dd7cddfSDavid du Colombier 		  while (outp + 3 <= out_end
1877dd7cddfSDavid du Colombier 			 && outp[0] == 0 && outp[1] == 0 && outp[2] == 0)
1887dd7cddfSDavid du Colombier 		    outp += 3;
1897dd7cddfSDavid du Colombier 		  tpos = (outp - out) / bytes_per_space;
1907dd7cddfSDavid du Colombier 		  newp = out + tpos * bytes_per_space;
1917dd7cddfSDavid du Colombier 		  if (newp > zp + 10)
1927dd7cddfSDavid du Colombier 		    {
1937dd7cddfSDavid du Colombier 		      /* Output preceding bit data. */
1947dd7cddfSDavid du Colombier 		      /* only false at beginning of line */
1957dd7cddfSDavid du Colombier 		      if (zp > out_blk)
1967dd7cddfSDavid du Colombier 			{
1977dd7cddfSDavid du Colombier 			  if (x_high)
1987dd7cddfSDavid du Colombier 			    dot24_improve_bitmap (out_blk, (int) (zp - out_blk));
1997dd7cddfSDavid du Colombier 			  dot24_output_run (out_blk, (int) (zp - out_blk),
2007dd7cddfSDavid du Colombier 					  x_high, prn_stream);
2017dd7cddfSDavid du Colombier 			}
2027dd7cddfSDavid du Colombier 		      /* Tab over to the appropriate position. */
2037dd7cddfSDavid du Colombier 		      fprintf (prn_stream, "\033D%c%c\t", tpos, 0);
2047dd7cddfSDavid du Colombier 		      out_blk = outp = newp;
2057dd7cddfSDavid du Colombier 		    }
2067dd7cddfSDavid du Colombier 		}
2077dd7cddfSDavid du Colombier 	      else
2087dd7cddfSDavid du Colombier 		outp += 3;
2097dd7cddfSDavid du Colombier 	    }
2107dd7cddfSDavid du Colombier 	  if (outp > out_blk)
2117dd7cddfSDavid du Colombier 	    {
2127dd7cddfSDavid du Colombier 	      if (x_high)
2137dd7cddfSDavid du Colombier 		dot24_improve_bitmap (out_blk, (int) (outp - out_blk));
2147dd7cddfSDavid du Colombier 	      dot24_output_run (out_blk, (int) (outp - out_blk), x_high,
2157dd7cddfSDavid du Colombier 			      prn_stream);
2167dd7cddfSDavid du Colombier 	    }
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 	  fputc ('\r', prn_stream);
2197dd7cddfSDavid du Colombier 	  if (ypass < y_passes - 1)
2207dd7cddfSDavid du Colombier 	    fputc ('\n', prn_stream);
2217dd7cddfSDavid du Colombier 	}
2227dd7cddfSDavid du Colombier       skip = 48 - y_high;
2237dd7cddfSDavid du Colombier       lnum += bits_per_column;
2247dd7cddfSDavid du Colombier     }
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier   /* Eject the page and reinitialize the printer */
2277dd7cddfSDavid du Colombier   fputs ("\f\033@", prn_stream);
2287dd7cddfSDavid du Colombier   fflush (prn_stream);
2297dd7cddfSDavid du Colombier 
230*593dc095SDavid du Colombier   gs_free (pdev->memory, (char *) out, out_size, 1, "dot24_print_page (out)");
231*593dc095SDavid du Colombier   gs_free (pdev->memory, (char *) in, in_size, 1, "dot24_print_page (in)");
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier   return 0;
2347dd7cddfSDavid du Colombier }
2357dd7cddfSDavid du Colombier 
2367dd7cddfSDavid du Colombier /* Output a single graphics command. */
2377dd7cddfSDavid du Colombier private void
dot24_output_run(byte * data,int count,int x_high,FILE * prn_stream)2387dd7cddfSDavid du Colombier dot24_output_run (byte *data, int count, int x_high, FILE *prn_stream)
2397dd7cddfSDavid du Colombier {
2407dd7cddfSDavid du Colombier   int xcount = count / 3;
2417dd7cddfSDavid du Colombier   fputc (033, prn_stream);
2427dd7cddfSDavid du Colombier   fputc ('*', prn_stream);
2437dd7cddfSDavid du Colombier   fputc ((x_high ? 40 : 39), prn_stream);
2447dd7cddfSDavid du Colombier   fputc (xcount & 0xff, prn_stream);
2457dd7cddfSDavid du Colombier   fputc (xcount >> 8, prn_stream);
2467dd7cddfSDavid du Colombier   fwrite (data, 1, count, prn_stream);
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier /* If xdpi == 360, the P6 / LQ850 cannot print adjacent pixels.  Clear the
2507dd7cddfSDavid du Colombier    second last pixel of every run of set pixels, so that the last pixel
2517dd7cddfSDavid du Colombier    is always printed.  */
2527dd7cddfSDavid du Colombier private void
dot24_improve_bitmap(byte * data,int count)2537dd7cddfSDavid du Colombier dot24_improve_bitmap (byte *data, int count)
2547dd7cddfSDavid du Colombier {
2557dd7cddfSDavid du Colombier   int i;
2567dd7cddfSDavid du Colombier   register byte *p = data + 6;
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier       for (i = 6; i < count; i += 3, p += 3)
2597dd7cddfSDavid du Colombier 	{
2607dd7cddfSDavid du Colombier 	  p[-6] &= ~(~p[0] & p[-3]);
2617dd7cddfSDavid du Colombier 	  p[-5] &= ~(~p[1] & p[-2]);
2627dd7cddfSDavid du Colombier 	  p[-4] &= ~(~p[2] & p[-1]);
2637dd7cddfSDavid du Colombier 	}
2647dd7cddfSDavid du Colombier       p[-6] &= ~p[-3];
2657dd7cddfSDavid du Colombier       p[-5] &= ~p[-2];
2667dd7cddfSDavid du Colombier       p[-4] &= ~p[-1];
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier }
2697dd7cddfSDavid du Colombier 
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier private int
necp6_print_page(gx_device_printer * pdev,FILE * prn_stream)2727dd7cddfSDavid du Colombier necp6_print_page(gx_device_printer *pdev, FILE *prn_stream)
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier   char necp6_init_string [] = "\033@\033P\033l\000\r\034\063\001\033Q";
2757dd7cddfSDavid du Colombier 
2767dd7cddfSDavid du Colombier   return dot24_print_page(pdev, prn_stream, necp6_init_string, sizeof(necp6_init_string));
2777dd7cddfSDavid du Colombier }
2787dd7cddfSDavid du Colombier 
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier private int
lq850_print_page(gx_device_printer * pdev,FILE * prn_stream)2817dd7cddfSDavid du Colombier lq850_print_page(gx_device_printer *pdev, FILE *prn_stream)
2827dd7cddfSDavid du Colombier {
2837dd7cddfSDavid du Colombier   char lq850_init_string [] = "\033@\033P\033l\000\r\033\053\001\033Q";
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier   return dot24_print_page(pdev, prn_stream, lq850_init_string, sizeof(lq850_init_string));
2867dd7cddfSDavid du Colombier }
2877dd7cddfSDavid du Colombier 
288