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