1 /* Copyright (C) 1989, 1995 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: gdevadmp.c,v 1.6 2004/08/10 13:02:36 stefan Exp $*/
18 /*
19 * Apple DMP / Imagewriter driver
20 *
21 * This is a modification of Mark Wedel's Apple DMP and
22 * Jonathan Luckey's Imagewriter II driver to
23 * support the Imagewriter LQ's higher resolution (320x216):
24 * appledmp: 120dpi x 72dpi is still supported (yuck)
25 * iwlo: 160dpi x 72dpi
26 * iwhi: 160dpi x 144dpi
27 * iwlq: 320dpi x 216dpi
28 *
29 * This is also my first attempt to work with gs. I have not included the LQ's
30 * ability to print in colour. Perhaps at a later date I will tackle that.
31 *
32 * BTW, to get your Imagewriter LQ serial printer to work with a PC, attach it
33 * with a nullmodem serial cable.
34 *
35 * Scott Barker (barkers@cuug.ab.ca)
36 */
37
38 /*
39 * This is a modification of Mark Wedel's Apple DMP driver to
40 * support 2 higher resolutions:
41 * appledmp: 120dpi x 72dpi is still supported (yuck)
42 * iwlo: 160dpi x 72dpi
43 * iwhi: 160dpi x 144dpi
44 *
45 * The Imagewriter II is a bit odd. In pinfeed mode, it thinks its
46 * First line is 1 inch from the top of the page. If you set the top
47 * form so that it starts printing at the top of the page, and print
48 * to near the bottom, it thinks it has run onto the next page and
49 * the formfeed will skip a whole page. As a work around, I reverse
50 * the paper about a 1.5 inches at the end of the page before the
51 * formfeed to make it think its on the 'right' page. bah. hack!
52 *
53 * This is my first attempt to work with gs, so your milage may vary
54 *
55 * Jonathan Luckey (luckey@rtfm.mlb.fl.us)
56 */
57
58 /* This is a bare bones driver I developed for my apple Dot Matrix Printer.
59 * This code originally was from the epson driver, but I removed a lot
60 * of stuff that was not needed.
61 *
62 * The Dot Matrix Printer was a predecessor to the apple Imagewriter. Its
63 * main difference being that it was parallel.
64 *
65 * This code should work fine on Imagewriters, as they have a superset
66 * of commands compared to the DMP printer.
67 *
68 * This driver does not produce the smalles output files possible. To
69 * do that, it should look through the output strings and find repeat
70 * occurances of characters, and use the escape sequence that allows
71 * printing repeat sequences. However, as I see it, this the limiting
72 * factor in printing is not transmission speed to the printer itself,
73 * but rather, how fast the print head can move. This is assuming the
74 * printer is set up with a reasonable speed (9600 bps)
75 *
76 * WHAT THE CODE DOES AND DOES NOT DO:
77 *
78 * To print out images, it sets the printer for unidirection printing
79 * and 15 cpi (120 dpi). IT sets line feed to 1/9 of an inch (72 dpi).
80 * When finished, it sets things back to bidirection print, 1/8" line
81 * feeds, and 12 cpi. There does not appear to be a way to reset
82 * things to initial values.
83 *
84 * This code does not set for 8 bit characters (which is required). It
85 * also assumes that carriage return/newline is needed, and not just
86 * carriage return. These are all switch settings on the DMP, and
87 * I have configured them for 8 bit data and cr only.
88 *
89 * You can search for the strings Init and Reset to find the strings
90 * that set up the printer and clear things when finished, and change
91 * them to meet your needs.
92 *
93 * Also, you need to make sure that the printer daemon (assuming unix)
94 * doesn't change the data as it is being printed. I have set my
95 * printcap file (sunos 4.1.1) with the string:
96 * ms=pass8,-opost
97 * and it works fine.
98 *
99 * Feel free to improve this code if you want. However, please make
100 * sure that the old DMP will still be supported by any changes. This
101 * may mean making an imagewriter device, and just copying this file
102 * to something like gdevimage.c.
103 *
104 * The limiting factor of the DMP is the vertical resolution. However, I
105 * see no way to do anything about this. Horizontal resolution could
106 * be increased by using 17 cpi (136 dpi). I believe the Imagewriter
107 * supports 24 cpi (192 dpi). However, the higher dpi, the slower
108 * the printing.
109 *
110 * Dot Matrix Code by Mark Wedel (master@cats.ucsc.edu)
111 */
112
113
114 #include "gdevprn.h"
115
116 /* The device descriptors */
117 private dev_proc_print_page(dmp_print_page);
118
119 /* Standard DMP device */
120 const gx_device_printer far_data gs_appledmp_device =
121 prn_device(prn_std_procs, "appledmp",
122 85, /* width_10ths, 8.5" */
123 110, /* height_10ths, 11" */
124 120, 72, /* X_DPI, Y_DPI */
125 0, 0.5, 0.5, 0, /* margins */
126 1, dmp_print_page);
127
128
129 /* lowrez Imagewriter device */
130 const gx_device_printer far_data gs_iwlo_device =
131 prn_device(prn_std_procs, "iwlo",
132 85, /* width_10ths, 8.5" */
133 110, /* height_10ths, 11" */
134 160, 72, /* X_DPI, Y_DPI */
135 0, 0.5, 0.5, 0, /* margins */
136 1, dmp_print_page);
137
138
139 /* hirez Imagewriter device */
140 const gx_device_printer far_data gs_iwhi_device =
141 prn_device(prn_std_procs, "iwhi",
142 85, /* width_10ths, 8.5" */
143 110, /* height_10ths, 11" */
144 160, 144, /* X_DPI, Y_DPI */
145 0, 0.5, 0.5, 0, /* margins */
146 1, dmp_print_page);
147
148
149 /* LQ hirez Imagewriter device */
150 const gx_device_printer far_data gs_iwlq_device =
151 prn_device(prn_std_procs, "iwlq",
152 85, /* width_10ths, 8.5" */
153 110, /* height_10ths, 11" */
154 320, 216,
155 0, 0, 0.5, 0, /* margins */
156 1, dmp_print_page);
157
158
159 /* ------ Internal routines ------ */
160
161 #define DMP 1
162 #define IWLO 2
163 #define IWHI 3
164 #define IWLQ 4
165
166 /* Send the page to the printer. */
167 private int
dmp_print_page(gx_device_printer * pdev,FILE * prn_stream)168 dmp_print_page(gx_device_printer *pdev, FILE *prn_stream)
169 {
170 int dev_type;
171
172 int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
173 /* Note that in_size is a multiple of 8. */
174 int in_size = line_size * 8;
175
176 byte *buf1 = (byte *)gs_malloc(pdev->memory, in_size, 1, "dmp_print_page(buf1)");
177 byte *buf2 = (byte *)gs_malloc(pdev->memory, in_size, 1, "dmp_print_page(buf2)");
178 byte *prn = (byte *)gs_malloc(pdev->memory, 3*in_size, 1, "dmp_print_page(prn)");
179
180 byte *in = buf1;
181 byte *out = buf2;
182 int lnum = 0;
183
184 /* Check allocations */
185 if ( buf1 == 0 || buf2 == 0 || prn == 0 )
186 {
187 if ( buf1 )
188 gs_free(pdev->memory, (char *)buf1, in_size, 1,
189 "dmp_print_page(buf1)");
190 if ( buf2 )
191 gs_free(pdev->memory, (char *)buf2, in_size, 1,
192 "dmp_print_page(buf2)");
193 if ( prn )
194 gs_free(pdev->memory, (char *)prn, in_size, 1,
195 "dmp_print_page(prn)");
196 return_error(gs_error_VMerror);
197 }
198
199 if ( pdev->y_pixels_per_inch == 216 )
200 dev_type = IWLQ;
201 else if ( pdev->y_pixels_per_inch == 144 )
202 dev_type = IWHI;
203 else if ( pdev->x_pixels_per_inch == 160 )
204 dev_type = IWLO;
205 else
206 dev_type = DMP;
207
208 /* Initialize the printer and reset the margins. */
209
210 fputs("\r\n\033>\033T16", prn_stream);
211
212 switch(dev_type)
213 {
214 case IWLQ:
215 fputs("\033P\033a3", prn_stream);
216 break;
217 case IWHI:
218 case IWLO:
219 fputs("\033P", prn_stream);
220 break;
221 case DMP:
222 default:
223 fputs("\033q", prn_stream);
224 break;
225 }
226
227 /* Print lines of graphics */
228 while ( lnum < pdev->height )
229 {
230 byte *inp;
231 byte *in_end;
232 byte *out_end;
233 int lcnt,ltmp;
234 int count, passes;
235 byte *prn_blk, *prn_end, *prn_tmp;
236
237 /* The apple DMP printer seems to be odd in that the bit order on
238 * each line is reverse what might be expected. Meaning, an
239 * underscore would be done as a series of 0x80, while on overscore
240 * would be done as a series of 0x01. So we get each
241 * scan line in reverse order.
242 */
243
244 switch (dev_type)
245 {
246 case IWLQ: passes = 3; break;
247 case IWHI: passes = 2; break;
248 case IWLO:
249 case DMP:
250 default: passes = 1; break;
251 }
252
253 for (count = 0; count < passes; count++)
254 {
255 for (lcnt=0; lcnt<8; lcnt++)
256 {
257 switch(dev_type)
258 {
259 case IWLQ: ltmp = lcnt + 8*count; break;
260 case IWHI: ltmp = 2*lcnt + count; break;
261 case IWLO:
262 case DMP:
263 default: ltmp = lcnt; break;
264 }
265
266 if ((lnum+ltmp)>pdev->height)
267 memset(in+lcnt*line_size,0,line_size);
268 else
269 gdev_prn_copy_scan_lines(pdev,
270 lnum+ltmp, in + line_size*(7 - lcnt),
271 line_size);
272 }
273
274 out_end = out;
275 inp = in;
276 in_end = inp + line_size;
277 for ( ; inp < in_end; inp++, out_end += 8 )
278 {
279 gdev_prn_transpose_8x8(inp, line_size,
280 out_end, 1);
281 }
282
283 out_end = out;
284
285 switch (dev_type)
286 {
287 case IWLQ: prn_end = prn + count; break;
288 case IWHI: prn_end = prn + in_size*count; break;
289 case IWLO:
290 case DMP:
291 default: prn_end = prn; break;
292 }
293
294 while ( (int)(out_end-out) < in_size)
295 {
296 *prn_end = *(out_end++);
297 if ((dev_type) == IWLQ) prn_end += 3;
298 else prn_end++;
299 }
300 }
301
302 switch (dev_type)
303 {
304 case IWLQ:
305 prn_blk = prn;
306 prn_end = prn_blk + in_size * 3;
307 while (prn_end > prn && prn_end[-1] == 0 &&
308 prn_end[-2] == 0 && prn_end[-3] == 0)
309 {
310 prn_end -= 3;
311 }
312 while (prn_blk < prn_end && prn_blk[0] == 0 &&
313 prn_blk[1] == 0 && prn_blk[2] == 0)
314 {
315 prn_blk += 3;
316 }
317 if (prn_end != prn_blk)
318 {
319 if ((prn_blk - prn) > 7)
320 fprintf(prn_stream,"\033U%04d%c%c%c",
321 (int)((prn_blk - prn)/3),
322 0, 0, 0);
323 else
324 prn_blk = prn;
325 fprintf(prn_stream,"\033C%04d",
326 (int)((prn_end - prn_blk)/3));
327 fwrite(prn_blk, 1, (int)(prn_end - prn_blk),
328 prn_stream);
329 }
330 break;
331 case IWHI:
332 for (count = 0; count < 2; count++)
333 {
334 prn_blk = prn_tmp = prn + in_size*count;
335 prn_end = prn_blk + in_size;
336 while (prn_end > prn_blk && prn_end[-1] == 0)
337 prn_end--;
338 while (prn_blk < prn_end && prn_blk[0] == 0)
339 prn_blk++;
340 if (prn_end != prn_blk)
341 {
342 if ((prn_blk - prn_tmp) > 7)
343 fprintf(prn_stream,
344 "\033V%04d%c",
345 (int)(prn_blk-prn_tmp),
346 0);
347 else
348 prn_blk = prn_tmp;
349 fprintf(prn_stream,"\033G%04d",
350 (int)(prn_end - prn_blk));
351 fwrite(prn_blk, 1,
352 (int)(prn_end - prn_blk),
353 prn_stream);
354 }
355 if (!count) fputs("\033T01\r\n",prn_stream);
356 }
357 fputs("\033T15",prn_stream);
358 break;
359 case IWLO:
360 case DMP:
361 default:
362 prn_blk = prn;
363 prn_end = prn_blk + in_size;
364 while (prn_end > prn_blk && prn_end[-1] == 0)
365 prn_end--;
366 while (prn_blk < prn_end && prn_blk[0] == 0)
367 prn_blk++;
368 if (prn_end != prn_blk)
369 {
370 if ((prn_blk - prn) > 7)
371 fprintf(prn_stream,"\033V%04d%c",
372 (int)(prn_blk - prn), 0);
373 else
374 prn_blk = prn;
375 fprintf(prn_stream,"\033G%04d",
376 (int)(prn_end - prn_blk));
377 fwrite(prn_blk, 1, (int)(prn_end - prn_blk),
378 prn_stream);
379 }
380 break;
381 }
382
383 fputs("\r\n",prn_stream);
384
385 switch (dev_type)
386 {
387 case IWLQ: lnum += 24 ; break;
388 case IWHI: lnum += 16 ; break;
389 case IWLO:
390 case DMP:
391 default: lnum += 8 ; break;
392 }
393 }
394
395 /* ImageWriter will skip a whole page if too close to end */
396 /* so skip back more than an inch */
397 if ( !(dev_type == DMP) )
398 fputs("\033T99\n\n\033r\n\n\n\n\033f", prn_stream);
399
400 /* Formfeed and Reset printer */
401 fputs("\033T16\f\033<\033B\033E", prn_stream);
402 fflush(prn_stream);
403
404 gs_free(pdev->memory, (char *)prn, in_size, 1, "dmp_print_page(prn)");
405 gs_free(pdev->memory, (char *)buf2, in_size, 1, "dmp_print_page(buf2)");
406 gs_free(pdev->memory, (char *)buf1, in_size, 1, "dmp_print_page(buf1)");
407 return 0;
408 }
409