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