xref: /plan9/sys/src/cmd/gs/src/gdevescp.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1993, 1994 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevescp.c,v 1.7 2004/08/04 23:33:29 stefan Exp $*/
18 /*
19  * Epson 'ESC/P 2' language printer driver.
20  *
21  * This driver uses the ESC/P2 language raster graphics commands with
22  * compression. The driver skips vertical white space, provided that
23  * the white space is >= 24/band_size (<~ 1.7mm @ 360dpi!) high. There
24  * is no attempt to skip horizontal white space, but the compression
25  * greatly reduces the significance of this (a nearly blank line would
26  * take about 45 bytes). The driver compresses the data one scan line at
27  * a time, even though this is not enforced by the hardware. The reason
28  * I have done this is that, since the driver skips data outside the
29  * margins, we would have to set up a extra pointers to keep track of
30  * the data from the previous scan line. Doing this would add extra
31  * complexity at a small saving of disk space.
32  *
33  * These are the only possible optimisations that remain, and would
34  * greatly increase the complexity of the driver. At this point, I don't
35  * consider them necessary, but I might consider implementing them if
36  * enough people encourage me to do so.
37  *
38  * Richard Brown (rab@tauon.ph.unimelb.edu.au)
39  *
40  */
41 
42 #include "gdevprn.h"
43 
44 /*
45  * Valid values for X_DPI and Y_DPI: 180, 360
46  *
47  * The value specified at compile time is the default value used if the
48  * user does not specify a resolution at runtime.
49  */
50 #ifndef X_DPI
51 #  define X_DPI 360
52 #endif
53 
54 #ifndef Y_DPI
55 #  define Y_DPI 360
56 #endif
57 
58 /*
59  * Margin definitions: Stylus 800 printer driver:
60  *
61  * The commented margins are from the User's Manual.
62  *
63  * The values actually used here are more accurate for my printer.
64  * The Stylus paper handling is quite sensitive to these settings.
65  * If you find that the printer uses an extra page after every real
66  * page, you'll need to increase the top and/or bottom margin.
67  */
68 
69 #define STYLUS_L_MARGIN 0.13	/*0.12*/
70 #define STYLUS_B_MARGIN 0.56	/*0.51*/
71 #define STYLUS_T_MARGIN 0.34	/*0.12*/
72 #ifdef A4
73 #   define STYLUS_R_MARGIN 0.18 /*0.15*/
74 #else
75 #   define STYLUS_R_MARGIN 0.38
76 #endif
77 
78 /*
79  * Epson AP3250 Margins:
80  */
81 
82 #define AP3250_L_MARGIN 0.18
83 #define AP3250_B_MARGIN 0.51
84 #define AP3250_T_MARGIN 0.34
85 #define AP3250_R_MARGIN 0.28  /* US paper */
86 
87 /* The device descriptor */
88 private dev_proc_print_page(escp2_print_page);
89 
90 /* Stylus 800 device */
91 const gx_device_printer far_data gs_st800_device =
92   prn_device(prn_std_procs, "st800",
93 	DEFAULT_WIDTH_10THS,
94 	DEFAULT_HEIGHT_10THS,
95 	X_DPI, Y_DPI,
96 	STYLUS_L_MARGIN, STYLUS_B_MARGIN, STYLUS_R_MARGIN, STYLUS_T_MARGIN,
97 	1, escp2_print_page);
98 
99 /* AP3250 device */
100 const gx_device_printer far_data gs_ap3250_device =
101   prn_device(prn_std_procs, "ap3250",
102 	DEFAULT_WIDTH_10THS,
103 	DEFAULT_HEIGHT_10THS,
104 	X_DPI, Y_DPI,
105 	AP3250_L_MARGIN, AP3250_B_MARGIN, AP3250_R_MARGIN, AP3250_T_MARGIN,
106 	1, escp2_print_page);
107 
108 /* ------ Internal routines ------ */
109 
110 /* Send the page to the printer. */
111 private int
escp2_print_page(gx_device_printer * pdev,FILE * prn_stream)112 escp2_print_page(gx_device_printer *pdev, FILE *prn_stream)
113 {
114 	int line_size = gdev_prn_raster((gx_device_printer *)pdev);
115 	int band_size = 24;	/* 1, 8, or 24 */
116 	int in_size = line_size * band_size;
117 
118 	byte *buf1 = (byte *)gs_malloc(pdev->memory, in_size, 1, "escp2_print_page(buf1)");
119 	byte *buf2 = (byte *)gs_malloc(pdev->memory, in_size, 1, "escp2_print_page(buf2)");
120 	byte *in = buf1;
121 	byte *out = buf2;
122 
123 	int skip, lnum, top, bottom, left, width;
124 	int auto_feed = 1;
125 	int count, i;
126 
127 	/*
128 	** Check for valid resolution:
129 	**
130 	**	XDPI	YDPI
131 	**	360	360
132 	**	360	180
133 	**	180	180
134 	*/
135 
136 	if( !( (pdev->x_pixels_per_inch == 180 &&
137 	        pdev->y_pixels_per_inch == 180) ||
138 	       (pdev->x_pixels_per_inch == 360 &&
139 	       (pdev->y_pixels_per_inch == 360 ||
140 	        pdev->y_pixels_per_inch == 180) )) )
141 		   return_error(gs_error_rangecheck);
142 
143 	/*
144 	** Check buffer allocations:
145 	*/
146 
147 	if ( buf1 == 0 || buf2 == 0 )
148 	{	if ( buf1 )
149 		  gs_free(pdev->memory, (char *)buf1, in_size, 1, "escp2_print_page(buf1)");
150 		if ( buf2 )
151 		  gs_free(pdev->memory, (char *)buf2, in_size, 1, "escp2_print_page(buf2)");
152 		return_error(gs_error_VMerror);
153 	}
154 
155 	/*
156 	** Reset printer, enter graphics mode:
157 	*/
158 
159 	fwrite("\033@\033(G\001\000\001", 1, 8, prn_stream);
160 
161 #ifdef A4
162 	/*
163 	** After reset, the Stylus is set up for US letter paper.
164 	** We need to set the page size appropriately for A4 paper.
165 	** For some bizarre reason the ESC/P2 language wants the bottom
166 	** margin measured from the *top* of the page:
167 	*/
168 
169 	fwrite("\033(U\001\0\n\033(C\002\0t\020\033(c\004\0\0\0t\020",
170 	                                                1, 22, prn_stream);
171 #endif
172 
173 	/*
174 	** Set the line spacing to match the band height:
175 	*/
176 
177 	if( pdev->y_pixels_per_inch == 360 )
178 	   fwrite("\033(U\001\0\012\033+\030", 1, 9, prn_stream);
179 	else
180 	   fwrite("\033(U\001\0\024\033+\060", 1, 9, prn_stream);
181 
182         /*
183         ** If the printer has automatic page feeding, then the paper
184         ** will already be positioned at the top margin value, so we
185         ** start printing the image from there. Similarly, we must not
186         ** try to print or even line feed past the bottom margin, since
187         ** the printer will automatically load a new page.
188         ** Printers without this feature may actually need to be told
189         ** to skip past the top margin.
190         */
191 
192         if( auto_feed ) {
193            top = (int)(dev_t_margin(pdev) * pdev->y_pixels_per_inch);
194            bottom = (int)(pdev->height -
195 			dev_b_margin(pdev) * pdev->y_pixels_per_inch);
196         } else {
197            top = 0;
198            bottom = pdev->height;
199         }
200 
201         /*
202         ** Make left margin and width sit on byte boundaries:
203         */
204 
205         left  = ( (int) (dev_l_margin(pdev) * pdev->x_pixels_per_inch) ) >> 3;
206 
207         width = ((pdev->width - (int)(dev_r_margin(pdev) * pdev->x_pixels_per_inch)) >> 3) - left;
208 
209 	/*
210 	** Print the page:
211 	*/
212 
213 	for ( lnum = top, skip = 0 ; lnum < bottom ; )
214 	{
215 		byte *in_data;
216 		byte *inp;
217 		byte *in_end;
218 		byte *outp;
219 		register byte *p, *q;
220 		int lcnt;
221 
222 		/*
223 		** Check buffer for 0 data. We can't do this mid-band
224 		*/
225 
226 		gdev_prn_get_bits(pdev, lnum, in, &in_data);
227 		while ( in_data[0] == 0 &&
228 		        !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1) &&
229 		        lnum < bottom )
230 	    	{
231 			lnum++;
232 			skip++;
233 			gdev_prn_get_bits(pdev, lnum, in, &in_data);
234 		}
235 
236 		if(lnum == bottom ) break;	/* finished with this page */
237 
238 		/*
239 		** Skip blank lines if we need to:
240 		*/
241 
242 		if( skip ) {
243 		   fwrite("\033(v\002\000", 1, 5, prn_stream);
244 		   fputc(skip & 0xff, prn_stream);
245 		   fputc(skip >> 8,   prn_stream);
246 		   skip = 0;
247 		}
248 
249 		lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
250 
251 		/*
252 		** Check to see if we don't have enough data to fill an entire
253 		** band. Padding here seems to work (the printer doesn't jump
254 		** to the next (blank) page), although the ideal behaviour
255 		** would probably be to reduce the band height.
256 		**
257 		** Pad with nulls:
258 		*/
259 
260 		if( lcnt < band_size )
261 		   memset(in + lcnt * line_size, 0, in_size - lcnt * line_size);
262 
263 		/*
264 		** Now we have a band of data: try to compress it:
265 		*/
266 
267 		for( outp = out, i = 0 ; i < band_size ; i++ ) {
268 
269 		   /*
270 		   ** Take margins into account:
271 		   */
272 
273 		   inp = in + i * line_size + left;
274 		   in_end = inp + width;
275 
276 		   /*
277 		   ** walk through input buffer, looking for repeated data:
278 		   ** Since we need more than 2 repeats to make the compression
279 		   ** worth it, we can compare pairs, since it doesn't matter if we
280 		   **
281 		   */
282 
283 		   for( p = inp, q = inp + 1 ; q < in_end ; ) {
284 
285 		   	if( *p != *q ) {
286 
287 		   	   p += 2;
288 		   	   q += 2;
289 
290 		   	} else {
291 
292 		   	   /*
293 		   	   ** Check behind us, just in case:
294 		   	   */
295 
296 		   	   if( p > inp && *p == *(p-1) )
297 		   	      p--;
298 
299 			   /*
300 			   ** walk forward, looking for matches:
301 			   */
302 
303 			   for( q++ ; *q == *p && q < in_end ; q++ ) {
304 			      if( (q-p) >= 128 ) {
305 			         if( p > inp ) {
306 			            count = p - inp;
307 			            while( count > 128 ) {
308 				       *outp++ = '\177';
309 				       memcpy(outp, inp, 128);	/* data */
310 				       inp += 128;
311 				       outp += 128;
312 				       count -= 128;
313 			            }
314 			            *outp++ = (char) (count - 1); /* count */
315 			            memcpy(outp, inp, count);	/* data */
316 			            outp += count;
317 			         }
318 				 *outp++ = '\201';	/* Repeat 128 times */
319 				 *outp++ = *p;
320 			         p += 128;
321 			         inp = p;
322 			      }
323 			   }
324 
325 			   if( (q - p) > 2 ) {	/* output this sequence */
326 			      if( p > inp ) {
327 				 count = p - inp;
328 				 while( count > 128 ) {
329 				    *outp++ = '\177';
330 				    memcpy(outp, inp, 128);	/* data */
331 				    inp += 128;
332 				    outp += 128;
333 				    count -= 128;
334 				 }
335 				 *outp++ = (char) (count - 1);	/* byte count */
336 				 memcpy(outp, inp, count);	/* data */
337 				 outp += count;
338 			      }
339 			      count = q - p;
340 			      *outp++ = (char) (256 - count + 1);
341 			      *outp++ = *p;
342 			      p += count;
343 			      inp = p;
344 			   } else	/* add to non-repeating data list */
345 			      p = q;
346 			   if( q < in_end )
347 			      q++;
348 		   	}
349 		   }
350 
351 		   /*
352 		   ** copy remaining part of line:
353 		   */
354 
355 		   if( inp < in_end ) {
356 
357 		      count = in_end - inp;
358 
359 		      /*
360 		      ** If we've had a long run of varying data followed by a
361 		      ** sequence of repeated data and then hit the end of line,
362 		      ** it's possible to get data counts > 128.
363 		      */
364 
365 		      while( count > 128 ) {
366 			*outp++ = '\177';
367 			memcpy(outp, inp, 128);	/* data */
368 			inp += 128;
369 			outp += 128;
370 			count -= 128;
371 		      }
372 
373 		      *outp++ = (char) (count - 1);	/* byte count */
374 		      memcpy(outp, inp, count);	/* data */
375 		      outp += count;
376 		   }
377 		}
378 
379 		/*
380 		** Output data:
381 		*/
382 
383 	        fwrite("\033.\001", 1, 3, prn_stream);
384 
385 	        if(pdev->y_pixels_per_inch == 360)
386 	           fputc('\012', prn_stream);
387 		else
388 	           fputc('\024', prn_stream);
389 
390 	        if(pdev->x_pixels_per_inch == 360)
391 	           fputc('\012', prn_stream);
392 		else
393 	           fputc('\024', prn_stream);
394 
395 		fputc(band_size, prn_stream);
396 
397 	        fputc((width << 3) & 0xff, prn_stream);
398 		fputc( width >> 5,         prn_stream);
399 
400 	        fwrite(out, 1, (outp - out), prn_stream);
401 
402         	fwrite("\r\n", 1, 2, prn_stream);
403 		lnum += band_size;
404 	}
405 
406 	/* Eject the page and reinitialize the printer */
407 
408 	fputs("\f\033@", prn_stream);
409 	fflush(prn_stream);
410 
411 	gs_free(pdev->memory, (char *)buf2, in_size, 1, "escp2_print_page(buf2)");
412 	gs_free(pdev->memory, (char *)buf1, in_size, 1, "escp2_print_page(buf1)");
413 	return 0;
414 }
415