1 /* Copyright (C) 1989, 1992, 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: gdevokii.c,v 1.7 2004/08/10 13:02:36 stefan Exp $*/
18 /*
19 * Okidata IBM compatible dot-matrix printer driver for Ghostscript.
20 *
21 * This device is for the Okidata Microline IBM compatible 9 pin dot
22 * matrix printers. It is derived from the Epson 9 pin printer driver
23 * using the standard 1/72" vertical pin spacing and the 60/120/240
24 * dpi horizontal resolutions. The vertical feed resolution however
25 * is 1/144" and the Okidata implements the standard 1/216" requests
26 * through "scaling":
27 *
28 * (power on)
29 * "\033J\001" (vertical feed 1/216") => Nothing happens
30 * "\033J\001" (vertical feed 1/216") => Advance 1/144"
31 * "\033J\001" (vertical feed 1/216") => Advance 1/144"
32 * "\033J\001" (vertical feed 1/216") => Nothing happens
33 * (and so on)
34 *
35 * The simple minded accounting used here keep track of when the
36 * page actually advances assumes the printer starts in a "power on"
37 * state.
38 *
39 * Supported resolutions are:
40 *
41 * 60x72 60x144
42 * 120x72 120x144
43 * 240x72 240x144
44 *
45 */
46 #include "gdevprn.h"
47
48 /*
49 * Valid values for X_DPI:
50 *
51 * 60, 120, 240
52 *
53 * The value specified at compile time is the default value used if the
54 * user does not specify a resolution at runtime.
55 */
56
57 #ifndef X_DPI
58 # define X_DPI 120
59 #endif
60
61 /*
62 * Valid values for Y_DPI:
63 *
64 * 72, 144
65 *
66 * The value specified at compile time is the default value used if the
67 * user does not specify a resolution at runtime.
68 */
69
70 #ifndef Y_DPI
71 # define Y_DPI 72
72 #endif
73
74 /* The device descriptor */
75 private dev_proc_print_page(okiibm_print_page);
76
77 /* Okidata IBM device */
78 const gx_device_printer far_data gs_okiibm_device =
79 prn_device(prn_std_procs, "okiibm",
80 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
81 X_DPI, Y_DPI,
82 0.25, 0.0, 0.25, 0.0, /* margins */
83 1, okiibm_print_page);
84
85 /* ------ Internal routines ------ */
86
87 /* Forward references */
88 private void okiibm_output_run(byte *, int, int, char, FILE *, int);
89
90 /* Send the page to the printer. */
91 private int
okiibm_print_page1(gx_device_printer * pdev,FILE * prn_stream,int y_9pin_high,const char * init_string,int init_length,const char * end_string,int end_length)92 okiibm_print_page1(gx_device_printer *pdev, FILE *prn_stream, int y_9pin_high,
93 const char *init_string, int init_length,
94 const char *end_string, int end_length)
95 {
96 static const char graphics_modes_9[5] =
97 {
98 -1, 0 /*60*/, 1 /*120*/, -1, 3 /*240*/
99 };
100
101 int in_y_mult = (y_9pin_high ? 2 : 1);
102 int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
103 /* Note that in_size is a multiple of 8. */
104 int in_size = line_size * (8 * in_y_mult);
105 byte *buf1 = (byte *)gs_malloc(pdev->memory, in_size, 1, "okiibm_print_page(buf1)");
106 byte *buf2 = (byte *)gs_malloc(pdev->memory, in_size, 1, "okiibm_print_page(buf2)");
107 byte *in = buf1;
108 byte *out = buf2;
109 int out_y_mult = 1;
110 int x_dpi = pdev->x_pixels_per_inch;
111 char start_graphics = graphics_modes_9[x_dpi / 60];
112 int first_pass = (start_graphics == 3 ? 1 : 0);
113 int last_pass = first_pass * 2;
114 int y_passes = (y_9pin_high ? 2 : 1);
115 int skip = 0, lnum = 0, pass, ypass;
116 int y_step = 0;
117
118 /* Check allocations */
119 if ( buf1 == 0 || buf2 == 0 )
120 { if ( buf1 )
121 gs_free(pdev->memory, (char *)buf1, in_size, 1, "okiibm_print_page(buf1)");
122 if ( buf2 )
123 gs_free(pdev->memory, (char *)buf2, in_size, 1, "okiibm_print_page(buf2)");
124 return_error(gs_error_VMerror);
125 }
126
127 /* Initialize the printer. */
128 fwrite(init_string, 1, init_length, prn_stream);
129
130 /* Print lines of graphics */
131 while ( lnum < pdev->height )
132 {
133 byte *in_data;
134 byte *inp;
135 byte *in_end;
136 byte *out_end;
137 int lcnt;
138
139 /* Copy 1 scan line and test for all zero. */
140 gdev_prn_get_bits(pdev, lnum, in, &in_data);
141 if ( in_data[0] == 0 &&
142 !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1)
143 )
144 {
145 lnum++;
146 skip += 2 / in_y_mult;
147 continue;
148 }
149
150 /*
151 * Vertical tab to the appropriate position.
152 * The skip count is in 1/144" steps. If total
153 * vertical request is not a multiple od 1/72"
154 * we need to make sure the page is actually
155 * going to advance.
156 */
157 if ( skip & 1 )
158 {
159 int n = 1 + (y_step == 0 ? 1 : 0);
160 fprintf(prn_stream, "\033J%c", n);
161 y_step = (y_step + n) % 3;
162 skip -= 1;
163 }
164 skip = skip / 2 * 3;
165 while ( skip > 255 )
166 {
167 fputs("\033J\377", prn_stream);
168 skip -= 255;
169 }
170 if ( skip )
171 {
172 fprintf(prn_stream, "\033J%c", skip);
173 }
174
175 /* Copy the the scan lines. */
176 lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
177 if ( lcnt < 8 * in_y_mult )
178 { /* Pad with lines of zeros. */
179 memset(in + lcnt * line_size, 0,
180 in_size - lcnt * line_size);
181 }
182
183 if ( y_9pin_high )
184 { /* Shuffle the scan lines */
185 byte *p;
186 int i;
187 static const char index[] =
188 { 0, 2, 4, 6, 8, 10, 12, 14,
189 1, 3, 5, 7, 9, 11, 13, 15
190 };
191 for ( i = 0; i < 16; i++ )
192 {
193 memcpy( out + (i * line_size),
194 in + (index[i] * line_size),
195 line_size);
196 }
197 p = in;
198 in = out;
199 out = p;
200 }
201
202 for ( ypass = 0; ypass < y_passes; ypass++ )
203 {
204 for ( pass = first_pass; pass <= last_pass; pass++ )
205 {
206 /* We have to 'transpose' blocks of 8 pixels x 8 lines, */
207 /* because that's how the printer wants the data. */
208
209 if ( pass == first_pass )
210 {
211 out_end = out;
212 inp = in;
213 in_end = inp + line_size;
214
215 for ( ; inp < in_end; inp++, out_end += 8 )
216 {
217 gdev_prn_transpose_8x8(inp + (ypass * 8 * line_size),
218 line_size, out_end, 1);
219 }
220 /* Remove trailing 0s. */
221 while ( out_end > out && out_end[-1] == 0 )
222 {
223 out_end--;
224 }
225 }
226
227 /* Transfer whatever is left and print. */
228 if ( out_end > out )
229 {
230 okiibm_output_run(out, (int)(out_end - out),
231 out_y_mult, start_graphics,
232 prn_stream, pass);
233 }
234 fputc('\r', prn_stream);
235 }
236 if ( ypass < y_passes - 1 )
237 {
238 int n = 1 + (y_step == 0 ? 1 : 0);
239 fprintf(prn_stream, "\033J%c", n);
240 y_step = (y_step + n) % 3;
241 }
242 }
243 skip = 16 - y_passes + 1; /* no skip on last Y pass */
244 lnum += 8 * in_y_mult;
245 }
246
247 /* Reinitialize the printer. */
248 fwrite(end_string, 1, end_length, prn_stream);
249 fflush(prn_stream);
250
251 gs_free(pdev->memory, (char *)buf2, in_size, 1, "okiibm_print_page(buf2)");
252 gs_free(pdev->memory, (char *)buf1, in_size, 1, "okiibm_print_page(buf1)");
253 return 0;
254 }
255
256 /* Output a single graphics command. */
257 /* pass=0 for all columns, 1 for even columns, 2 for odd columns. */
258 private void
okiibm_output_run(byte * data,int count,int y_mult,char start_graphics,FILE * prn_stream,int pass)259 okiibm_output_run(byte *data, int count, int y_mult,
260 char start_graphics, FILE *prn_stream, int pass)
261 {
262 int xcount = count / y_mult;
263
264 fputc(033, prn_stream);
265 fputc("KLYZ"[start_graphics], prn_stream);
266 fputc(xcount & 0xff, prn_stream);
267 fputc(xcount >> 8, prn_stream);
268 if ( !pass )
269 {
270 fwrite(data, 1, count, prn_stream);
271 }
272 else
273 {
274 /* Only write every other column of y_mult bytes. */
275 int which = pass;
276 register byte *dp = data;
277 register int i, j;
278
279 for ( i = 0; i < xcount; i++, which++ )
280 {
281 for ( j = 0; j < y_mult; j++, dp++ )
282 {
283 putc(((which & 1) ? *dp : 0), prn_stream);
284 }
285 }
286 }
287 }
288
289 /* The print_page procedures are here, to avoid a forward reference. */
290
291 private const char okiibm_init_string[] = { 0x18 };
292 private const char okiibm_end_string[] = { 0x0c };
293 private const char okiibm_one_direct[] = { 0x1b, 0x55, 0x01 };
294 private const char okiibm_two_direct[] = { 0x1b, 0x55, 0x00 };
295
296 private int
okiibm_print_page(gx_device_printer * pdev,FILE * prn_stream)297 okiibm_print_page(gx_device_printer *pdev, FILE *prn_stream)
298 {
299 char init_string[16], end_string[16];
300 int init_length, end_length;
301
302 init_length = sizeof(okiibm_init_string);
303 memcpy(init_string, okiibm_init_string, init_length);
304
305 end_length = sizeof(okiibm_end_string);
306 memcpy(end_string, okiibm_end_string, end_length);
307
308 if ( pdev->y_pixels_per_inch > 72 &&
309 pdev->x_pixels_per_inch > 60 )
310 {
311 /* Unidirectional printing for the higher resolutions. */
312 memcpy( init_string + init_length, okiibm_one_direct,
313 sizeof(okiibm_one_direct) );
314 init_length += sizeof(okiibm_one_direct);
315
316 memcpy( end_string + end_length, okiibm_two_direct,
317 sizeof(okiibm_two_direct) );
318 end_length += sizeof(okiibm_two_direct);
319 }
320
321 return okiibm_print_page1( pdev, prn_stream,
322 pdev->y_pixels_per_inch > 72 ? 1 : 0,
323 init_string, init_length,
324 end_string, end_length );
325 }
326