1 /* Copyright (C) 2000 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: gdevatx.c,v 1.9 2004/01/29 18:19:41 ray Exp $ */
18 /* Practical Automation ATX-23, -24, and -38 driver */
19 #include "math_.h"
20 #include "gdevprn.h"
21
22 /*
23 * All of the ATX printers have an unprintable margin of 0.125" at the top
24 * and bottom of the page. They also have unprintable left/right margins:
25 * ATX-23 0.25"
26 * ATX-24 0.193"
27 * ATS-38 0.25"
28 * The code below assumes that coordinates refer only to the *printable*
29 * part of each page. This is wrong and must eventually be changed.
30 */
31
32 /* Define the printer commands. */
33 #define ATX_SET_PAGE_LENGTH "\033f" /* + 2-byte length */
34 #define ATX_VERTICAL_TAB "\033L" /* + 2-byte count */
35 #define ATX_UNCOMPRESSED_DATA "\033d" /* + 2-byte count */
36 #define ATX_COMPRESSED_DATA "\033x" /* + 1-byte word count */
37 #define ATX_END_PAGE "\033e"
38
39 /* The device descriptors */
40 private dev_proc_print_page(atx23_print_page);
41 private dev_proc_print_page(atx24_print_page);
42 private dev_proc_print_page(atx38_print_page);
43
44 #define ATX_DEVICE(dname, w10, h10, dpi, lrm, btm, print_page)\
45 prn_device_margins(prn_std_procs, dname, w10, h10, dpi, dpi, 0, 0,\
46 lrm, btm, lrm, btm, 1, print_page)
47
48 const gx_device_printer gs_atx23_device = /* real width = 576 pixels */
49 ATX_DEVICE("atx23", 28 /* 2.84" */, 35 /* (minimum) */,
50 203, 0.25, 0.125, atx23_print_page);
51
52 const gx_device_printer gs_atx24_device = /* real width = 832 pixels */
53 ATX_DEVICE("atx24", 41 /* 4.1" */, 35 /* (minimum) */,
54 203, 0.193, 0.125, atx24_print_page);
55
56 const gx_device_printer gs_atx38_device = /* real width = 2400 pixels */
57 ATX_DEVICE("atx38", 80 /* 8.0" */, 35 /* (minimum) */,
58 300, 0.25, 0.125, atx38_print_page);
59
60 /* Output a printer command with a 2-byte, little-endian numeric argument. */
61 private void
fput_atx_command(FILE * f,const char * str,int value)62 fput_atx_command(FILE *f, const char *str, int value)
63 {
64 fputs(str, f);
65 fputc((byte)value, f);
66 fputc((byte)(value >> 8), f);
67 }
68
69 /*
70 * Attempt to compress a scan line of data. in_size and out_size are even.
71 * Return -1 if the compressed data would exceed out_size, otherwise the
72 * size of the compressed data (always even).
73 */
74 #define MIN_IN_SIZE_TO_COMPRESS 50
75 #define MAX_COMPRESSED_SEGMENT_PAIRS 127
76 #define MAX_UNCOMPRESSED_SEGMENT_PAIRS 255
77 #define COMPRESSED_SEGMENT_COMMAND 0x80 /* + # of repeated pairs */
78 #define UNCOMPRESSED_SEGMENT_COMMAND 0x7f /* followed by # of pairs */
79 private int
atx_compress(const byte * in_buf,int in_size,byte * out_buf,int out_size)80 atx_compress(const byte *in_buf, int in_size, byte *out_buf, int out_size)
81 {
82 const byte *const in_end = in_buf + in_size;
83 byte *const out_end = out_buf + out_size;
84 const byte *in = in_buf;
85 byte *out = out_buf;
86 byte *out_command;
87 int pair_count;
88
89 if (in_size < MIN_IN_SIZE_TO_COMPRESS)
90 return -1; /* not worth compressing */
91
92 /* Start a new segment. */
93 New_Segment:
94 if (in == in_end) /* end of input data */
95 return out - out_buf;
96 if (out == out_end) /* output buffer full */
97 return -1;
98 out_command = out;
99 out += 2;
100 if (in[1] == in[0]) { /* start compressed segment */
101 /* out[-2] will be compressed segment command */
102 out[-1] = in[0];
103 pair_count = 1;
104 goto Scan_Compressed_Pair;
105 } else { /* start uncompressed segment */
106 out[-2] = UNCOMPRESSED_SEGMENT_COMMAND;
107 /* out[-1] will be pair count */
108 pair_count = 0;
109 goto Scan_Uncompressed_Pair;
110 }
111
112 /* Scan compressed data. */
113 Scan_Compressed:
114 if (pair_count == MAX_COMPRESSED_SEGMENT_PAIRS ||
115 in == in_end || in[0] != in[-1] || in[1] != in[0]
116 ) { /* end the segment */
117 out_command[0] = COMPRESSED_SEGMENT_COMMAND + pair_count;
118 goto New_Segment;
119 }
120 ++pair_count;
121 Scan_Compressed_Pair:
122 in += 2;
123 goto Scan_Compressed;
124
125 /* Scan uncompressed data. */
126 Scan_Uncompressed:
127 if (pair_count == MAX_UNCOMPRESSED_SEGMENT_PAIRS ||
128 in == in_end || in[1] == in[0]
129 ) { /* end the segment */
130 out_command[1] = pair_count;
131 goto New_Segment;
132 }
133 Scan_Uncompressed_Pair:
134 if (out == out_end) /* output buffer full */
135 return -1;
136 out[0] = in[0], out[1] = in[1];
137 in += 2;
138 out += 2;
139 ++pair_count;
140 goto Scan_Uncompressed;
141
142 }
143
144 /* Send the page to the printer. */
145 private int
atx_print_page(gx_device_printer * pdev,FILE * f,int max_width_bytes)146 atx_print_page(gx_device_printer *pdev, FILE *f, int max_width_bytes)
147 {
148 /*
149 * The page length command uses 16 bits to represent the length in
150 * units of 0.01", so the maximum representable page length is
151 * 655.35", including the unprintable top and bottom margins.
152 * Compute the maximum height of the printable area in pixels.
153 */
154 float top_bottom_skip = (pdev->HWMargins[1] + pdev->HWMargins[3]) / 72.0;
155 int max_height = (int)(pdev->HWResolution[1] * 655 - top_bottom_skip);
156 int height = min(pdev->height, max_height);
157 int page_length_100ths =
158 (int)ceil((height / pdev->HWResolution[1] + top_bottom_skip) * 100);
159 gs_memory_t *mem = pdev->memory;
160 int raster = gx_device_raster((gx_device *)pdev, true);
161 byte *buf;
162 /*
163 * ATX_COMPRESSED_DATA only takes a 1-byte (word) count.
164 * Thus no compressed scan line can take more than 510 bytes.
165 */
166 int compressed_raster = min(raster / 2, 510); /* require 50% compression */
167 byte *compressed;
168 int blank_lines, lnum;
169 int code = 0;
170
171 /* Enforce a minimum 3" page length. */
172 if (page_length_100ths < 300)
173 page_length_100ths = 300;
174 buf = gs_alloc_bytes(mem, raster, "atx_print_page(buf)");
175 compressed = gs_alloc_bytes(mem, compressed_raster,
176 "atx_print_page(compressed)");
177 if (buf == 0 || compressed == 0) {
178 code = gs_note_error(gs_error_VMerror);
179 goto done;
180 }
181 fput_atx_command(f, ATX_SET_PAGE_LENGTH, page_length_100ths);
182 for (blank_lines = 0, lnum = 0; lnum < height; ++lnum) {
183 byte *row;
184 byte *end;
185 int count;
186
187 gdev_prn_get_bits(pdev, lnum, buf, &row);
188 /* Find the end of the non-blank data. */
189 for (end = row + raster; end > row && end[-1] == 0 && end[-2] == 0; )
190 end -= 2;
191 if (end == row) { /* blank line */
192 ++blank_lines;
193 continue;
194 }
195 if (blank_lines) { /* skip vertically */
196 fput_atx_command(f, ATX_VERTICAL_TAB, blank_lines + 1);
197 blank_lines = 0;
198 }
199 /* Truncate the line to the maximum printable width. */
200 if (end - row > max_width_bytes)
201 end = row + max_width_bytes;
202 count = atx_compress(row, end - row, compressed, compressed_raster);
203 if (count >= 0) { /* compressed line */
204 /*
205 * Note that since compressed_raster can't exceed 510, count
206 * can't exceed 510 either.
207 */
208 fputs(ATX_COMPRESSED_DATA, f);
209 fputc(count / 2, f);
210 fwrite(compressed, 1, count, f);
211 } else { /* uncompressed line */
212 int num_bytes = end - row;
213
214 fput_atx_command(f, ATX_UNCOMPRESSED_DATA, num_bytes);
215 fwrite(row, 1, num_bytes, f);
216 }
217 }
218
219 #if 0 /**************** MAY NOT BE NEEDED ****************/
220 /* Enforce the minimum page length, and skip any final blank lines. */
221 {
222 int paper_length = (int)(pdev->HWResolution[1] * 3 + 0.5);
223 int printed_length = height - blank_lines;
224
225 if (height > paper_length)
226 paper_length = height;
227 if (printed_length < paper_length)
228 fput_atx_command(f, ATX_VERTICAL_TAB,
229 paper_length - printed_length + 1);
230 }
231 #endif
232
233 /* End the page. */
234 fputs(ATX_END_PAGE, f);
235
236 done:
237 gs_free_object(mem, compressed, "atx_print_page(compressed)");
238 gs_free_object(mem, buf, "atx_print_page(buf)");
239 return code;
240 }
241
242 /* Print pages with specified maximum pixel widths. */
243 private int
atx23_print_page(gx_device_printer * pdev,FILE * f)244 atx23_print_page(gx_device_printer *pdev, FILE *f)
245 {
246 return atx_print_page(pdev, f, 576 / 8);
247 }
248 private int
atx24_print_page(gx_device_printer * pdev,FILE * f)249 atx24_print_page(gx_device_printer *pdev, FILE *f)
250 {
251 return atx_print_page(pdev, f, 832 / 8);
252 }
253 private int
atx38_print_page(gx_device_printer * pdev,FILE * f)254 atx38_print_page(gx_device_printer *pdev, FILE *f)
255 {
256 return atx_print_page(pdev, f, 2400 / 8);
257 }
258