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