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