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