1 /* Copyright (C) 1989-1994, 1998 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: gdevepsn.c,v 1.9 2004/08/04 19:36:12 stefan Exp $*/
18 /*
19 * Epson (and similar) dot-matrix printer driver for Ghostscript.
20 *
21 * Four devices are defined here: 'epson', 'eps9mid', 'eps9high', and 'ibmpro'.
22 * The 'epson' device is the generic device, for 9-pin and 24-pin printers.
23 * 'eps9high' is a special mode for 9-pin printers where scan lines are
24 * interleaved in multiple passes to produce high vertical resolution at
25 * the expense of several passes of the print head. 'eps9mid' is a special
26 * mode for 9 pin printers too, scan lines are interleaved but with next
27 * vertical line. 'ibmpro' is for the IBM ProPrinter, which has slightly
28 * (but only slightly) different control codes.
29 *
30 * Thanks to:
31 * David Wexelblat (dwex@mtgzfs3.att.com) for the 'eps9high' code;
32 * Guenther Thomsen (thomsen@cs.tu-berlin.de) for the 'eps9mid' code;
33 * James W. Birdsall (jwbirdsa@picarefy.picarefy.com) for the
34 * 'ibmpro' modifications;
35 * Russell J. Lang (rjl@aladdin.com) for the 180x60 and 240x180 dpi
36 * enhancements.
37 */
38 #include "gdevprn.h"
39
40 /*
41 * Define whether the printer is archaic -- so old that it doesn't
42 * support settable tabs, pitch, or left margin. (This should be a
43 * run-time property....) Note: the IBM ProPrinter is archaic.
44 */
45 /*#define ARCHAIC 1*/
46
47 /*
48 * Define whether the printer is a Panasonic 9-pin printer,
49 * which sometimes doesn't recognize a horizontal tab command
50 * when a line contains a lot of graphics commands,
51 * requiring a "backspace, space" sequence before a tab.
52 */
53 /*#define TAB_HICCUP 1*/
54
55 /*
56 * Define the minimum distance for which it's worth converting white space
57 * into a tab. This can be specified in pixels (to save transmission time),
58 * in tenths of an inch (for printers where tabs provoke actual head motion),
59 * or both. The distance must meet BOTH criteria for the driver to tab,
60 * so an irrelevant criterion should be set to 0 rather than infinite.
61 */
62 #define MIN_TAB_PIXELS 10
63 #define MIN_TAB_10THS 15
64
65 /*
66 * Valid values for X_DPI:
67 *
68 * For 9-pin printers: 60, 120, 240
69 * For 24-pin printers: 60, 120, 180, 240, 360
70 *
71 * The value specified at compile time is the default value used if the
72 * user does not specify a resolution at runtime.
73 */
74 #ifndef X_DPI
75 # define X_DPI 240
76 #endif
77
78 /*
79 * For Y_DPI, a given printer will support a base resolution of 60 or 72;
80 * check the printer manual. The Y_DPI value must be a multiple of this
81 * base resolution. Valid values for Y_DPI:
82 *
83 * For 9-pin printers: 1*base_res
84 * For 24-pin printers: 1*base_res, 3*base_res
85 *
86 * The value specified at compile time is the default value used if the
87 * user does not specify a resolution at runtime.
88 */
89
90 #ifndef Y_BASERES
91 # define Y_BASERES 72
92 #endif
93 #ifndef Y_DPI
94 # define Y_DPI (1*Y_BASERES)
95 #endif
96
97 /* The device descriptors */
98 private dev_proc_print_page(epson_print_page);
99 private dev_proc_print_page(eps9mid_print_page);
100 private dev_proc_print_page(eps9high_print_page);
101 private dev_proc_print_page(ibmpro_print_page);
102
103 /* Standard Epson device */
104 const gx_device_printer far_data gs_epson_device =
105 prn_device(prn_std_procs, "epson",
106 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
107 X_DPI, Y_DPI,
108 0.2, 0.0, 0.0, 0.0, /* margins */
109 1, epson_print_page);
110
111 /* Mid-res (interleaved, 1 pass per line) 9-pin device */
112 const gx_device_printer far_data gs_eps9mid_device =
113 prn_device(prn_std_procs, "eps9mid",
114 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
115 X_DPI, 3*Y_BASERES,
116 0.2, 0.0, 0, 0.0, /* margins */
117 1, eps9mid_print_page);
118
119
120 /* High-res (interleaved) 9-pin device */
121 const gx_device_printer far_data gs_eps9high_device =
122 prn_device(prn_std_procs, "eps9high",
123 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
124 X_DPI, 3*Y_BASERES,
125 0.2, 0.0, 0.0, 0.0, /* margins */
126 1, eps9high_print_page);
127
128 /* IBM ProPrinter device */
129 const gx_device_printer far_data gs_ibmpro_device =
130 prn_device(prn_std_procs, "ibmpro",
131 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
132 X_DPI, Y_DPI,
133 0.2, 0.0, 0.0, 0.0, /* margins */
134 1, ibmpro_print_page);
135
136 /* ------ Driver procedures ------ */
137
138 /* Forward references */
139 private void eps_output_run(byte *, int, int, char, FILE *, int);
140
141 /* Send the page to the printer. */
142 #define DD 0x40 /* double density flag */
143 private int
eps_print_page(gx_device_printer * pdev,FILE * prn_stream,int y_9pin_high,const char * init_string,int init_length,const char * end_string,int archaic,int tab_hiccup)144 eps_print_page(gx_device_printer *pdev, FILE *prn_stream, int y_9pin_high,
145 const char *init_string, int init_length, const char *end_string,
146 int archaic, int tab_hiccup)
147 {
148 static const char graphics_modes_9[5] =
149 {
150 -1, 0 /*60*/, 1 /*120*/, 7 /*180*/, DD+3 /*240*/
151 };
152
153 static const char graphics_modes_24[7] =
154 {
155 -1, 32 /*60*/, 33 /*120*/, 39 /*180*/,
156 DD+35 /*240*/, -1, DD+40 /*360*/
157 };
158
159 int y_24pin = (y_9pin_high ? 0 : pdev->y_pixels_per_inch > 72);
160 int in_y_mult = ((y_24pin | y_9pin_high) ? 3 : 1);
161 int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
162 /* Note that in_size is a multiple of 8. */
163 int in_size = line_size * (8 * in_y_mult);
164 byte *buf1 = (byte *)gs_malloc(pdev->memory, in_size, 1, "eps_print_page(buf1)");
165 byte *buf2 = (byte *)gs_malloc(pdev->memory, in_size, 1, "eps_print_page(buf2)");
166 byte *in = buf1;
167 byte *out = buf2;
168 int out_y_mult = (y_24pin ? 3 : 1);
169 int x_dpi = (int)pdev->x_pixels_per_inch;
170 char start_graphics =
171 (y_24pin ? graphics_modes_24 : graphics_modes_9)[x_dpi / 60];
172 int first_pass = (start_graphics & DD ? 1 : 0);
173 int last_pass = first_pass * (y_9pin_high == 2 ? 1 : 2);
174 int y_passes = (y_9pin_high ? 3 : 1);
175 int dots_per_space = x_dpi / 10; /* pica space = 1/10" */
176 int bytes_per_space = dots_per_space * out_y_mult;
177 int tab_min_pixels = x_dpi * MIN_TAB_10THS / 10;
178 int skip = 0, lnum = 0, pass, ypass;
179
180 /* Check allocations */
181 if ( buf1 == 0 || buf2 == 0 )
182 { if ( buf1 )
183 gs_free(pdev->memory, (char *)buf1, in_size, 1, "eps_print_page(buf1)");
184 if ( buf2 )
185 gs_free(pdev->memory, (char *)buf2, in_size, 1, "eps_print_page(buf2)");
186 return_error(gs_error_VMerror);
187 }
188
189 /* Initialize the printer and reset the margins. */
190 fwrite(init_string, 1, init_length, prn_stream);
191 if ( init_string[init_length - 1] == 'Q' )
192 fputc((int)(pdev->width / pdev->x_pixels_per_inch * 10) + 2,
193 prn_stream);
194
195 /* Calculate the minimum tab distance. */
196 if ( tab_min_pixels < max(MIN_TAB_PIXELS, 3) )
197 tab_min_pixels = max(MIN_TAB_PIXELS, 3);
198 tab_min_pixels -= tab_min_pixels % 3; /* simplify life */
199
200 /* Print lines of graphics */
201 while ( lnum < pdev->height )
202 {
203 byte *in_data;
204 byte *inp;
205 byte *in_end;
206 byte *out_end;
207 byte *out_blk;
208 register byte *outp;
209 int lcnt;
210
211 /* Copy 1 scan line and test for all zero. */
212 gdev_prn_get_bits(pdev, lnum, in, &in_data);
213 if ( in_data[0] == 0 &&
214 !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1)
215 )
216 {
217 lnum++;
218 skip += 3 / in_y_mult;
219 continue;
220 }
221
222 /* Vertical tab to the appropriate position. */
223 while ( skip > 255 )
224 {
225 fputs("\033J\377", prn_stream);
226 skip -= 255;
227 }
228 if ( skip )
229 {
230 fprintf(prn_stream, "\033J%c", skip);
231 }
232
233 /* Copy the the scan lines. */
234 lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
235 if ( lcnt < 8 * in_y_mult )
236 { /* Pad with lines of zeros. */
237 memset(in + lcnt * line_size, 0,
238 in_size - lcnt * line_size);
239 }
240
241 if ( y_9pin_high == 2 )
242 { /* Force printing of every dot in one pass */
243 /* by reducing vertical resolution */
244 /* (ORing with the next line of data). */
245 /* This is necessary because some Epson compatibles */
246 /* can't print neighboring dots. */
247 int i;
248 for ( i = 0; i < line_size * in_y_mult; ++i )
249 in_data[i] |= in_data[i + line_size];
250 }
251
252 if ( y_9pin_high )
253 { /* Shuffle the scan lines */
254 byte *p;
255 int i;
256 static const char index[] =
257 { 0, 8, 16, 1, 9, 17,
258 2, 10, 18, 3, 11, 19,
259 4, 12, 20, 5, 13, 21,
260 6, 14, 22, 7, 15, 23
261 };
262
263 for ( i = 0; i < 24; i++ )
264 {
265 memcpy(out+(index[i]*line_size),
266 in+(i*line_size), line_size);
267 }
268 p = in;
269 in = out;
270 out = p;
271 }
272
273 for ( ypass = 0; ypass < y_passes; ypass++ )
274 {
275 for ( pass = first_pass; pass <= last_pass; pass++ )
276 {
277 /* We have to 'transpose' blocks of 8 pixels x 8 lines, */
278 /* because that's how the printer wants the data. */
279 /* If we are in a 24-pin mode, we have to transpose */
280 /* groups of 3 lines at a time. */
281
282 if ( pass == first_pass )
283 {
284 out_end = out;
285 inp = in;
286 in_end = inp + line_size;
287
288 if ( y_24pin )
289 {
290 for ( ; inp < in_end; inp++, out_end += 24 )
291 {
292 gdev_prn_transpose_8x8(inp, line_size, out_end, 3);
293 gdev_prn_transpose_8x8(inp + line_size * 8,
294 line_size, out_end + 1, 3);
295 gdev_prn_transpose_8x8(inp + line_size * 16,
296 line_size, out_end + 2, 3);
297 }
298 /* Remove trailing 0s. */
299 while ( out_end > out && out_end[-1] == 0 &&
300 out_end[-2] == 0 && out_end[-3] == 0)
301 {
302 out_end -= 3;
303 }
304 }
305 else
306 {
307 for ( ; inp < in_end; inp++, out_end += 8 )
308 {
309 gdev_prn_transpose_8x8(inp + (ypass * 8*line_size),
310 line_size, out_end, 1);
311 }
312 /* Remove trailing 0s. */
313 while ( out_end > out && out_end[-1] == 0 )
314 {
315 out_end--;
316 }
317 }
318 }
319
320 for ( out_blk = outp = out; outp < out_end; )
321 {
322 /* Skip a run of leading 0s. At least */
323 /* tab_min_pixels are needed to make tabbing */
324 /* worth it. We do everything by 3's to */
325 /* avoid having to make different cases */
326 /* for 9- and 24-pin. */
327 if ( !archaic &&
328 *outp == 0 && out_end - outp >= tab_min_pixels &&
329 (outp[1] | outp[2]) == 0 &&
330 !memcmp((char *)outp, (char *)outp + 3,
331 tab_min_pixels - 3)
332 )
333 {
334 byte *zp = outp;
335 int tpos;
336 byte *newp;
337
338 outp += tab_min_pixels;
339 while ( outp + 3 <= out_end &&
340 *outp == 0 &&
341 outp[1] == 0 && outp[2] == 0 )
342 {
343 outp += 3;
344 }
345 tpos = (outp - out) / bytes_per_space;
346 newp = out + tpos * bytes_per_space;
347 if ( newp > zp + 10 )
348 {
349 /* Output preceding bit data.*/
350 if ( zp > out_blk )
351 {
352 /* only false at beginning of line */
353 eps_output_run(out_blk, (int)(zp - out_blk),
354 out_y_mult, start_graphics,
355 prn_stream,
356 (y_9pin_high == 2 ?
357 (1 + ypass) & 1 : pass));
358 }
359 /* Tab over to the appropriate position. */
360 if ( tab_hiccup )
361 fputs("\010 ", prn_stream); /* bksp, space */
362 /* The following statement is broken up */
363 /* to work around a bug in emx/gcc. */
364 fprintf(prn_stream, "\033D%c", tpos);
365 fputc(0, prn_stream);
366 fputc('\t', prn_stream);
367 out_blk = outp = newp;
368 }
369 }
370 else
371 {
372 outp += out_y_mult;
373 }
374 }
375 if ( outp > out_blk )
376 {
377 eps_output_run(out_blk, (int)(outp - out_blk),
378 out_y_mult, start_graphics,
379 prn_stream,
380 (y_9pin_high == 2 ? (1 + ypass) & 1 : pass));
381 }
382
383 fputc('\r', prn_stream);
384 }
385 if ( ypass < y_passes - 1 )
386 fputs("\033J\001", prn_stream);
387 }
388 skip = 24 - y_passes + 1; /* no skip on last Y pass */
389 lnum += 8 * in_y_mult;
390 }
391
392 /* Eject the page and reinitialize the printer */
393 fputs(end_string, prn_stream);
394 fflush(prn_stream);
395
396 gs_free(pdev->memory, (char *)buf2, in_size, 1, "eps_print_page(buf2)");
397 gs_free(pdev->memory, (char *)buf1, in_size, 1, "eps_print_page(buf1)");
398 return 0;
399 }
400
401 /* Output a single graphics command. */
402 /* pass=0 for all columns, 1 for even columns, 2 for odd columns. */
403 private void
eps_output_run(byte * data,int count,int y_mult,char start_graphics,FILE * prn_stream,int pass)404 eps_output_run(byte *data, int count, int y_mult,
405 char start_graphics, FILE *prn_stream, int pass)
406 {
407 int xcount = count / y_mult;
408
409 fputc(033, prn_stream);
410 if ( !(start_graphics & ~3) )
411 {
412 fputc("KLYZ"[(int)start_graphics], prn_stream);
413 }
414 else
415 {
416 fputc('*', prn_stream);
417 fputc(start_graphics & ~DD, prn_stream);
418 }
419 fputc(xcount & 0xff, prn_stream);
420 fputc(xcount >> 8, prn_stream);
421 if ( !pass )
422 {
423 fwrite(data, 1, count, prn_stream);
424 }
425 else
426 {
427 /* Only write every other column of y_mult bytes. */
428 int which = pass;
429 register byte *dp = data;
430 register int i, j;
431
432 for ( i = 0; i < xcount; i++, which++ )
433 {
434 for ( j = 0; j < y_mult; j++, dp++ )
435 {
436 putc(((which & 1) ? *dp : 0), prn_stream);
437 }
438 }
439 }
440 }
441
442 /* The print_page procedures are here, to avoid a forward reference. */
443 #ifndef ARCHAIC
444 # define ARCHAIC 0
445 #endif
446 #ifndef TAB_HICCUP
447 # define TAB_HICCUP 0
448 #endif
449
450 #define ESC 0x1b
451 private const char eps_init_string[] = {
452 #if ARCHAIC
453 ESC, '@', 022 /*^R*/, ESC, 'Q'
454 #else
455 ESC, '@', ESC, 'P', ESC, 'l', 0, '\r', ESC, 'Q'
456 #endif
457 };
458
459 private int
epson_print_page(gx_device_printer * pdev,FILE * prn_stream)460 epson_print_page(gx_device_printer *pdev, FILE *prn_stream)
461 {
462 return eps_print_page(pdev, prn_stream, 0, eps_init_string,
463 sizeof(eps_init_string), "\f\033@",
464 ARCHAIC, TAB_HICCUP);
465 }
466
467 private int
eps9high_print_page(gx_device_printer * pdev,FILE * prn_stream)468 eps9high_print_page(gx_device_printer *pdev, FILE *prn_stream)
469 {
470 return eps_print_page(pdev, prn_stream, 1, eps_init_string,
471 sizeof(eps_init_string), "\f\033@",
472 ARCHAIC, TAB_HICCUP);
473 }
474
475 private int
eps9mid_print_page(gx_device_printer * pdev,FILE * prn_stream)476 eps9mid_print_page(gx_device_printer *pdev, FILE *prn_stream)
477 {
478 return eps_print_page(pdev, prn_stream, 2, eps_init_string,
479 sizeof(eps_init_string), "\f\033@",
480 ARCHAIC, TAB_HICCUP);
481 }
482
483 private int
ibmpro_print_page(gx_device_printer * pdev,FILE * prn_stream)484 ibmpro_print_page(gx_device_printer *pdev, FILE *prn_stream)
485 {
486 /*
487 * IBM Proprinter Guide to Operations, p. 4-5: "DC1: Select Printer: Sets
488 * the printer to accept data from your computer." Prevents printer from
489 * interpreting first characters as literal text.
490 */
491 #define DC1 0x11
492 static const char ibmpro_init_string[] = {
493 DC1, ESC, '3', 0x30
494 };
495 #undef DC1
496 return eps_print_page(pdev, prn_stream, 0, ibmpro_init_string,
497 sizeof(ibmpro_init_string), "\f", 1, 0);
498 }
499