xref: /plan9/sys/src/cmd/gs/src/gdevo182.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1993, 1996 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: gdevo182.c,v 1.6 2004/08/10 13:02:36 stefan Exp $*/
18 /* Okidata Microline 182 printer driver */
19 
20 /* Contributed by Maarten Koning (smeg@bnr.ca) April 4, 1993 */
21 
22 /****************************************************************
23 
24 I use this driver from Unix with the following aliases:
25 
26 alias psp "gs -q -sDEVICE=oki182 -sOutputFile=\|lpr - <\!*"
27 alias psphigh "gs -q -sDEVICE=oki182 -r144 -sOutputFile=\|lpr - <\!*"
28 
29 ps. I have my printer DIP switches set to the following (as viewed
30 	while standing in front of your printer looking down into the
31 	config access hatch located at the top of your printer
32 	in the centre back).
33 
34 Upper  Upper   Bottom
35 Left   Right   (at right)
36 
37  x	x        x
38  x       x	x
39  x       x       x
40 x        x	x
41  x	x        x
42  x	x        x
43 x        x	x
44  x	x        x
45 
46 The upper DIP switches are on a SuperSpeed Serial
47 card that will do 19200 baud.  I have it set at 9600
48 baud since that seems sufficient to keep the printer
49 busy.
50 
51 The important thing is to be in 8-bit mode so that
52 the graphics data can't match any Okidata commands
53 (This driver sets the high bit of graphics data to 1).
54 
55 ****************************************************************/
56 
57 #include "gdevprn.h"
58 
59 /*
60  *  Available resolutions are 72x72 or 144x144;
61  *  (144x72) would be possible to do also, but I didn't bother)
62  */
63 
64 /* The device descriptor */
65 
66 private dev_proc_print_page(oki_print_page);
67 
68 const gx_device_printer far_data gs_oki182_device =
69   prn_device(prn_std_procs, "oki182",
70 	80,				/* width_10ths, 8.0" */
71 	110,				/* height_10ths, 11" */
72 	72,				/* x_dpi */
73 	72,				/* y_dpi */
74 	0, 0, 0, 0,			/* margins */
75 	1, oki_print_page);
76 
77 /* ------ internal routines ------ */
78 
79 /* out is a pointer to an array of 7 scan lines,
80    lineSize is the number of bytes between a pixel and
81    the pixel directly beneath it.
82    scanBits is the number of bits in each scan line
83    out is a pointer to an array of column data, which
84    is how the Okidata wants the graphics image.
85 
86    each column of graphics data is 7 bits high and
87    is encoded in a byte - highest pixel in the column
88    is the lowest bit in the byte.  The upper bit of the
89    byte is set so that the okidata doesn't mistake
90    graphic image data for graphic commands.
91 */
92 
93 private void
oki_transpose(byte * in,byte * out,int scanBits,register int lineSize)94 oki_transpose(byte *in, byte *out, int scanBits, register int lineSize)
95 {
96 	register bitMask = 0x80;
97 	register byte *inPtr;
98 	register byte outByte;
99 
100 	while (scanBits-- > 0) {
101 
102 		inPtr = in;
103 
104 		if (*inPtr & bitMask)
105 			outByte = 0x81;
106 		else
107 			outByte = 0x80;
108 		if (*(inPtr += lineSize) & bitMask)
109 			outByte += 0x02;
110 		if (*(inPtr += lineSize) & bitMask)
111 			outByte += 0x04;
112 		if (*(inPtr += lineSize) & bitMask)
113 			outByte += 0x08;
114 		if (*(inPtr += lineSize) & bitMask)
115 			outByte += 0x10;
116 		if (*(inPtr += lineSize) & bitMask)
117 			outByte += 0x20;
118 		if (*(inPtr += lineSize) & bitMask)
119 			outByte += 0x40;
120 
121 		*out++ = outByte;
122 
123 		if ((bitMask >>= 1) == 0) {
124 			bitMask = 0x80;
125 			in ++;
126 		}
127 	}
128 }
129 
130 /* This routine tries to compress a sequence of okidata
131    graphic bytes by trimming off leading and trailing
132    zeros.  Trailing zeros can be thrown away and leading
133    zeros can be replaced with a much smaller number of spaces.
134 
135    'in' is a pointer to the graphic bytes to be compressed.
136    origWidth is the number of bytes pointed to by 'in'.
137    highRes is non-zero when 144x144 mode is being used.
138 
139    numSpaces is set to the number of spaces that should
140    be printed before the compressed image. newWidth is
141    the new number of bytes that the return value of this
142    function points to.
143 
144    xxx - A future enhancement would be to replace long sequences
145    of embedded zeros with exit.graphics-<n> spaces-enter.graphics
146 */
147 private byte *
oki_compress(byte * in,int origWidth,int highRes,int * numSpaces,int * newWidth)148 oki_compress(byte *in, int origWidth, int highRes,
149 			int *numSpaces, int *newWidth)
150 {
151 	int spaces = 0;
152 	int columns_per_space = 6;
153 
154 	byte *in_end = in + origWidth;
155 
156 	/* remove trailing zeros (which are realy 0x80's) */
157 	while (in_end > in && in_end[-1] == 0x80)
158 		in_end --;
159 
160 	if (highRes)
161 		columns_per_space = 12;
162 
163 	/* remove leading zeros that can be replaced by spaces */
164 	while(in < in_end && in[0] == 0x80 && memcmp((char *)in,
165 				(char *)in + 1, columns_per_space - 1) == 0) {
166 		spaces++;
167 		in += columns_per_space;
168 	}
169 
170 	*numSpaces = spaces;
171 
172 	/* just in case we compressed this line out of existance */
173 	if (in_end > in)
174 		*newWidth = in_end - in;
175 	else
176 		*newWidth = 0;
177 
178 	return(in);
179 }
180 
181 /* Send the page to the printer. */
182 
183 private int
oki_print_page(gx_device_printer * pdev,FILE * prn_stream)184 oki_print_page(gx_device_printer *pdev, FILE *prn_stream)
185 {
186 	int highRes = pdev->y_pixels_per_inch > 100;
187 	int bits_per_column = 7;
188 	int i, spaces, width;
189 	int lcnt;
190 
191 	int line_size = gdev_prn_raster((gx_device_printer *)pdev);
192 
193 	byte *in = (byte *)gs_malloc(pdev->memory, 16, line_size, "oki_print_page(in)");
194 
195 	byte *out1 = (byte *)gs_malloc(pdev->memory, 8, line_size, "oki_print_page(out1)");
196 	byte *out2 = (byte *)gs_malloc(pdev->memory, 8, line_size, "oki_print_page(out2)");
197 
198 	byte *out3;
199 
200 	int lnum = 0;
201 	int skip = 0;
202 	int code = 0;
203 
204 	if ( in == 0 || out1 == 0 || out2 == 0)
205 	{	code = gs_error_VMerror;
206 		gs_note_error(code);
207 		goto bail;
208 	}
209 
210 	/* Initialize the printer. */
211 	/* CAN; 72x72; left margin = 001; disable skip over perforation */
212 	fwrite("\030\034\033%C001\033%S0", 1, 12, prn_stream);
213 
214 	if (highRes) {
215 		fwrite("\033R", 1, 2, prn_stream);
216 		bits_per_column = 14;
217 	}
218 
219 	/* Transfer pixels to printer */
220 	while ( lnum < pdev->height ) {
221 
222 		/* Copy 1 scan line and test for all zero. */
223 		code = gdev_prn_copy_scan_lines(pdev, lnum, in, line_size);
224 		if ( code < 0 )
225 			goto xit;
226 
227 		/* if line is all zero, skip */
228 		if ( in[0] == 0 && !memcmp((char *)in, (char *)in + 1,
229 							line_size - 1)) {
230 			lnum++;
231 			if (highRes)
232 				skip++;
233 			else
234 				skip += 2;
235 			continue;
236 		}
237 
238 		/* use fine line feed to get to the appropriate position. */
239 		while ( skip > 127 ) {
240 			fputs("\033%5\177", prn_stream);
241 			skip -= 127;
242 		}
243 		if ( skip )
244 			fprintf(prn_stream, "\033%%5%c",
245 					(char) (skip & 0xff));
246 		skip = 0;
247 
248 		/* get the rest of the scan lines */
249 		code = gdev_prn_copy_scan_lines(pdev, lnum + 1,
250 			in + line_size, (bits_per_column - 1) * line_size);
251 
252 		if ( code < 0 )
253 			goto xit;
254 
255 		lcnt = code + 1; /* since we already grabbed one line */
256 
257 		if ( lcnt < bits_per_column )
258 			memset(in + lcnt * line_size, 0,
259 					(bits_per_column - lcnt) * line_size);
260 
261 		if (highRes) {
262 			oki_transpose(in, out1, pdev->width, 2 * line_size);
263 			oki_transpose(in + line_size, out2,
264 						pdev->width, 2 * line_size);
265 		} else
266 			oki_transpose(in, out1, pdev->width, line_size);
267 
268 		out3 = oki_compress(out1, pdev->width, highRes,
269 						&spaces, &width);
270 
271 		for (i=0; i < spaces; i++)
272 			putc(' ', prn_stream);
273 
274 		fwrite("\003", 1, 1, prn_stream);
275 		fwrite(out3, 1, width, prn_stream);
276 
277 		if (highRes) {
278 			/* exit graphics; carriage return; 1 bit line feed */
279 			fprintf(prn_stream, "\003\002\015\033%%5%c", (char) 1);
280 			out3 = oki_compress(out2, pdev->width, highRes,
281 							&spaces, &width);
282 			for (i=0; i < spaces; i++)
283 				putc(' ', prn_stream);
284 			fwrite("\003", 1, 1, prn_stream);
285 			fwrite(out3, 1, width, prn_stream);
286 			fprintf(prn_stream, "\003\002\015\033%%5%c", (char) 13);
287 		} else
288 			fwrite("\003\016\003\002", 1, 4, prn_stream);
289 
290 		lnum += bits_per_column;
291 	   }
292 
293 	/* Eject the page */
294 xit:
295 	fputc(014, prn_stream);	/* form feed */
296 	fflush(prn_stream);
297 
298 bail:
299 	if ( out1 != 0 )
300 		gs_free(pdev->memory, (char *)out1, 8, line_size, "oki_print_page(out1)");
301 
302 	if ( out2 != 0 )
303 		gs_free(pdev->memory, (char *)out2, 8, line_size, "oki_print_page(out2)");
304 
305 	if ( in != 0 )
306 		gs_free(pdev->memory, (char *)in, 16, line_size, "oki_print_page(in)");
307 
308 	return code;
309 }
310