xref: /plan9-contrib/sys/src/cmd/gs/src/gdevdm24.c (revision 9b943567965ba040fd275927fbe088656eb8ce4f)
1 /* Copyright (C) 1992, 1996, 1997 Aladdin Enterprises.  All rights reserved.
2 
3   This file is part of AFPL Ghostscript.
4 
5   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6   distributor accepts any responsibility for the consequences of using it, or
7   for whether it serves any particular purpose or works at all, unless he or
8   she says so in writing.  Refer to the Aladdin Free Public License (the
9   "License") for full details.
10 
11   Every copy of AFPL Ghostscript must include a copy of the License, normally
12   in a plain ASCII text file named PUBLIC.  The License grants you the right
13   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14   conditions described in the License.  Among other things, the License
15   requires that the copyright notice and this notice be preserved on all
16   copies.
17 */
18 
19 #include "gdevprn.h"
20 
21 
22 /*$Id: gdevdm24.c,v 1.3 2001/08/01 00:48:23 stefan911 Exp $*/
23 /* High-res 24Dot-matrix printer driver */
24 
25 /* Supported printers
26  *  NEC P6 and similar, implemented by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
27  *  Epson LQ850, implemented by Christian Felsch (felsch@tu-harburg.d400.de)
28  */
29 
30 /* Driver for NEC P6 */
31 private dev_proc_print_page (necp6_print_page);
32 const gx_device_printer far_data gs_necp6_device =
33   prn_device (prn_std_procs, "necp6",
34 	      DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
35 	      360, 360,
36 	      0, 0, 0.5, 0,	/* margins */
37 	      1, necp6_print_page);
38 
39 
40 /* Driver for Epson LQ850 */
41 /* I've tested this driver on a BJ300 with LQ850 emulation and there it produce correct 360x360dpi output. */
42 private dev_proc_print_page (lq850_print_page);
43 const gx_device_printer gs_lq850_device =
44   prn_device (prn_std_procs, "lq850",
45 	      DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
46 	      360, 360,
47 	      0, 0, 0.5, 0,	/* margins */
48 	      1, lq850_print_page);
49 
50 /* ------ Internal routines ------ */
51 
52 /* Forward references */
53 private void dot24_output_run (P4 (byte *, int, int, FILE *));
54 private void dot24_improve_bitmap (P2 (byte *, int));
55 
56 /* Send the page to the printer. */
57 private int
58 dot24_print_page (gx_device_printer *pdev, FILE *prn_stream, char *init_string, int init_len)
59 {
60   int xres = pdev->x_pixels_per_inch;
61   int yres = pdev->y_pixels_per_inch;
62   int x_high = (xres == 360);
63   int y_high = (yres == 360);
64   int bits_per_column = (y_high ? 48 : 24);
65   uint line_size = gdev_prn_raster (pdev);
66   uint in_size = line_size * bits_per_column;
67   byte *in = (byte *) gs_malloc (in_size, 1, "dot24_print_page (in)");
68   uint out_size = ((pdev->width + 7) & -8) * 3;
69   byte *out = (byte *) gs_malloc (out_size, 1, "dot24_print_page (out)");
70   int y_passes = (y_high ? 2 : 1);
71   int dots_per_space = xres / 10;	/* pica space = 1/10" */
72   int bytes_per_space = dots_per_space * 3;
73   int skip = 0, lnum = 0, ypass;
74 
75   /* Check allocations */
76   if (in == 0 || out == 0)
77     {
78       if (out)
79 	gs_free ((char *) out, out_size, 1, "dot24_print_page (out)");
80       if (in)
81 	gs_free ((char *) in, in_size, 1, "dot24_print_page (in)");
82       return_error (gs_error_VMerror);
83     }
84 
85   /* Initialize the printer and reset the margins. */
86   fwrite (init_string, init_len - 1, sizeof (char), prn_stream);
87   fputc ((int) (pdev->width / pdev->x_pixels_per_inch * 10) + 2,
88 	 prn_stream);
89 
90   /* Print lines of graphics */
91   while (lnum < pdev->height)
92     {
93       byte *inp;
94       byte *in_end;
95       byte *out_end;
96       byte *out_blk;
97       register byte *outp;
98       int lcnt;
99 
100       /* Copy 1 scan line and test for all zero. */
101       gdev_prn_copy_scan_lines (pdev, lnum, in, line_size);
102       if (in[0] == 0
103 	  && !memcmp ((char *) in, (char *) in + 1, line_size - 1))
104 	{
105 	  lnum++;
106 	  skip += 2 - y_high;
107 	  continue;
108 	}
109 
110       /* Vertical tab to the appropriate position. */
111       while ((skip >> 1) > 255)
112 	{
113 	  fputs ("\033J\377", prn_stream);
114 	  skip -= 255 * 2;
115 	}
116 
117       if (skip)
118 	{
119 	  if (skip >> 1)
120 	    fprintf (prn_stream, "\033J%c", skip >> 1);
121 	  if (skip & 1)
122 	    fputc ('\n', prn_stream);
123 	}
124 
125       /* Copy the rest of the scan lines. */
126       if (y_high)
127 	{
128 	  inp = in + line_size;
129 	  for (lcnt = 1; lcnt < 24; lcnt++, inp += line_size)
130 	    if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2, inp,
131 					   line_size))
132 	      {
133 		memset (inp, 0, (24 - lcnt) * line_size);
134 		break;
135 	      }
136 	  inp = in + line_size * 24;
137 	  for (lcnt = 0; lcnt < 24; lcnt++, inp += line_size)
138 	    if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2 + 1, inp,
139 					   line_size))
140 	      {
141 		memset (inp, 0, (24 - lcnt) * line_size);
142 		break;
143 	      }
144 	}
145       else
146 	{
147 	  lcnt = 1 + gdev_prn_copy_scan_lines (pdev, lnum + 1, in + line_size,
148 					       in_size - line_size);
149 	  if (lcnt < 24)
150 	    /* Pad with lines of zeros. */
151 	    memset (in + lcnt * line_size, 0, in_size - lcnt * line_size);
152 	}
153 
154       for (ypass = 0; ypass < y_passes; ypass++)
155 	{
156 	  out_end = out;
157 	  inp = in;
158 	  if (ypass)
159 	    inp += line_size * 24;
160 	  in_end = inp + line_size;
161 
162 	  for (; inp < in_end; inp++, out_end += 24)
163 	    {
164 	      memflip8x8 (inp, line_size, out_end, 3);
165 	      memflip8x8 (inp + line_size * 8, line_size, out_end + 1, 3);
166 	      memflip8x8 (inp + line_size * 16, line_size, out_end + 2, 3);
167 	    }
168 	  /* Remove trailing 0s. */
169 	  while (out_end - 3 >= out && out_end[-1] == 0
170 		 && out_end[-2] == 0 && out_end[-3] == 0)
171 	    out_end -= 3;
172 
173 	  for (out_blk = outp = out; outp < out_end;)
174 	    {
175 	      /* Skip a run of leading 0s. */
176 	      /* At least 10 are needed to make tabbing worth it. */
177 
178 	      if (outp[0] == 0 && outp + 12 <= out_end
179 		  && outp[1] == 0 && outp[2] == 0
180 		  && outp[3] == 0 && outp[4] == 0 && outp[5] == 0
181 		  && outp[6] == 0 && outp[7] == 0 && outp[8] == 0
182 		  && outp[9] == 0 && outp[10] == 0 && outp[11] == 0)
183 		{
184 		  byte *zp = outp;
185 		  int tpos;
186 		  byte *newp;
187 		  outp += 12;
188 		  while (outp + 3 <= out_end
189 			 && outp[0] == 0 && outp[1] == 0 && outp[2] == 0)
190 		    outp += 3;
191 		  tpos = (outp - out) / bytes_per_space;
192 		  newp = out + tpos * bytes_per_space;
193 		  if (newp > zp + 10)
194 		    {
195 		      /* Output preceding bit data. */
196 		      /* only false at beginning of line */
197 		      if (zp > out_blk)
198 			{
199 			  if (x_high)
200 			    dot24_improve_bitmap (out_blk, (int) (zp - out_blk));
201 			  dot24_output_run (out_blk, (int) (zp - out_blk),
202 					  x_high, prn_stream);
203 			}
204 		      /* Tab over to the appropriate position. */
205 		      fprintf (prn_stream, "\033D%c%c\t", tpos, 0);
206 		      out_blk = outp = newp;
207 		    }
208 		}
209 	      else
210 		outp += 3;
211 	    }
212 	  if (outp > out_blk)
213 	    {
214 	      if (x_high)
215 		dot24_improve_bitmap (out_blk, (int) (outp - out_blk));
216 	      dot24_output_run (out_blk, (int) (outp - out_blk), x_high,
217 			      prn_stream);
218 	    }
219 
220 	  fputc ('\r', prn_stream);
221 	  if (ypass < y_passes - 1)
222 	    fputc ('\n', prn_stream);
223 	}
224       skip = 48 - y_high;
225       lnum += bits_per_column;
226     }
227 
228   /* Eject the page and reinitialize the printer */
229   fputs ("\f\033@", prn_stream);
230   fflush (prn_stream);
231 
232   gs_free ((char *) out, out_size, 1, "dot24_print_page (out)");
233   gs_free ((char *) in, in_size, 1, "dot24_print_page (in)");
234 
235   return 0;
236 }
237 
238 /* Output a single graphics command. */
239 private void
240 dot24_output_run (byte *data, int count, int x_high, FILE *prn_stream)
241 {
242   int xcount = count / 3;
243   fputc (033, prn_stream);
244   fputc ('*', prn_stream);
245   fputc ((x_high ? 40 : 39), prn_stream);
246   fputc (xcount & 0xff, prn_stream);
247   fputc (xcount >> 8, prn_stream);
248   fwrite (data, 1, count, prn_stream);
249 }
250 
251 /* If xdpi == 360, the P6 / LQ850 cannot print adjacent pixels.  Clear the
252    second last pixel of every run of set pixels, so that the last pixel
253    is always printed.  */
254 private void
255 dot24_improve_bitmap (byte *data, int count)
256 {
257   int i;
258   register byte *p = data + 6;
259 
260       for (i = 6; i < count; i += 3, p += 3)
261 	{
262 	  p[-6] &= ~(~p[0] & p[-3]);
263 	  p[-5] &= ~(~p[1] & p[-2]);
264 	  p[-4] &= ~(~p[2] & p[-1]);
265 	}
266       p[-6] &= ~p[-3];
267       p[-5] &= ~p[-2];
268       p[-4] &= ~p[-1];
269 
270 }
271 
272 
273 private int
274 necp6_print_page(gx_device_printer *pdev, FILE *prn_stream)
275 {
276   char necp6_init_string [] = "\033@\033P\033l\000\r\034\063\001\033Q";
277 
278   return dot24_print_page(pdev, prn_stream, necp6_init_string, sizeof(necp6_init_string));
279 }
280 
281 
282 private int
283 lq850_print_page(gx_device_printer *pdev, FILE *prn_stream)
284 {
285   char lq850_init_string [] = "\033@\033P\033l\000\r\033\053\001\033Q";
286 
287   return dot24_print_page(pdev, prn_stream, lq850_init_string, sizeof(lq850_init_string));
288 }
289 
290