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