Coverage Report

Created: 2025-04-22 06:20

/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
}