xref: /plan9/sys/src/cmd/gs/src/gdevsj48.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1990, 1992, 1993 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: gdevsj48.c,v 1.5 2004/08/10 13:02:36 stefan Exp $*/
18 /*
19  * StarJet SJ48 printer driver.
20  *
21  * --- derived from gdevbj10.c 1993-10-07
22  *                by Mats kerblom (f86ma@dd.chalmers.se).
23  */
24 
25 #include "gdevprn.h"
26 
27 
28 /*
29  * The only available resolutions (in the program) are (180,360)x(180,360).
30  *
31  * Used control codes:
32  *   <Esc>@	Printer reset
33  *   <Esc>J<n>	Make a n/180 inch linefeed
34  *   <Esc>\<a><b>	Move the print position (a+256b)/180 inch to the right
35  *   <Esc>*<m><a><b>... Print graphics; m=39: 180*180 dpi
36  *					m=40: 360*180 dpi
37  *					m=71: 180*360 dpi
38  *					m=72: 360*360 dpi
39  *			a+256b columns is printed.
40  */
41 
42 /* The device descriptor */
43 private dev_proc_print_page(sj48_print_page);
44 gx_device_printer far_data gs_sj48_device =
45   prn_device(prn_std_procs, "sj48",
46 	80,				/* width_10ths, 8" */
47 	105,				/* height_10ths, 10.5" */
48 	360,				/* x_dpi */
49 	360,				/* y_dpi */
50 	0,0,0,0,			/* margins */
51 	1, sj48_print_page);
52 
53 
54 /*   This comes from the bj10/bj200 source. I don't know how it applies
55  *   for a StarJet.  --- Mats kerblom.
56  *
57  *
58  * The following is taken from the BJ200 Programmer's manual.  The top
59  * margin is 3mm (0.12"), and the bottom margin is 6.4mm (0.25").  The
60  * left and right margin depend on the type of paper -- US letter or
61  * A4 -- but ultimately rest on a print width of 203.2mm (8").  For letter
62  * paper, the left margin (and hence the right) is 6.4mm (0.25"), while
63  * for A4 paper, both are 3.4mm (0.13").
64  *
65  * The bottom margin requires a bit of care.  The image is printed
66  * as strips, each about 3.4mm wide.  We can only attain the bottom
67  * margin if the final strip coincides with it.  Note that each strip
68  * is generated using only 48 of the available 64 jets, and the absence
69  * of those bottom 16 jets makes our bottom margin, in effect, about
70  * 1.1mm (0.04") larger.
71  *
72  * The bj200 behaves, in effect, as though the origin were at the first
73  * printable position, rather than the top left corner of the page, so
74  * we add a translation to the initial matrix to compensate for this.
75  *
76  * Except for the details of getting the margins correct, the bj200 is
77  * no different from the bj10e, and uses the same routine to print each
78  * page.
79  *
80  */
81 
82 
83 /* Send the page to the printer. */
84 private int
sj48_print_page(gx_device_printer * pdev,FILE * prn_stream)85 sj48_print_page(gx_device_printer *pdev, FILE *prn_stream)
86 {	int line_size = gx_device_raster((gx_device *)pdev, 0);
87 	int xres = pdev->x_pixels_per_inch;
88 	int yres = pdev->y_pixels_per_inch;
89 	int mode = (yres == 180 ?
90 			(xres == 180 ? 39 : 40) :
91 			(xres == 180 ? 71 : 72));
92 	int bytes_per_column = (yres == 180) ? 3 : 6;
93 	int bits_per_column = bytes_per_column * 8;
94 	int skip_unit = bytes_per_column * (xres == 180 ? 1 : 2); /* Skips in step of 1/180" */
95 	byte *in = (byte *)gs_malloc(pdev->memory, 8, line_size, "sj48_print_page(in)");
96 	byte *out = (byte *)gs_malloc(pdev->memory, bits_per_column, line_size, "sj48_print_page(out)");
97 	int lnum = 0;
98 	int skip = 0;
99 	int skips;
100 	int code = 0;
101 	int last_row = dev_print_scan_lines(pdev);
102 	int limit = last_row - bits_per_column;
103 
104 	if ( in == 0 || out == 0 )
105 	{	code = gs_error_VMerror;
106 		gs_note_error(code);
107 		goto fin;
108 	}
109 
110 	/* Abort if the requested resolution is unsupported. */
111 	if ((xres !=180 && xres != 360) || (yres !=180 && yres != 360))
112 	{	code = gs_error_rangecheck;
113 		gs_note_error(code);
114 		goto fin;
115 	}
116 
117 	/* Initialize the printer. */
118 	fwrite("\033@\000\000", 1, 4, prn_stream);  /* <Printer reset>, <0>, <0>. */
119 
120 	/* Transfer pixels to printer.  The last row we can print is defined
121 	   by "last_row".  Only the bottom of the print head can print at the
122 	   bottom margin, and so we align the final printing pass.  The print
123 	   head is kept from moving below "limit", which is exactly one pass
124 	   above the bottom margin.  Once it reaches this limit, we make our
125 	   final printing pass of a full "bits_per_column" rows. */
126 	while ( lnum < last_row )
127 	   {
128 		byte *in_data;
129 		byte *in_end = in + line_size;
130 		byte *out_beg = out;
131 		byte *out_end = out + bytes_per_column * pdev->width;
132 		byte *outl = out;
133 		int count, bnum;
134 
135 		/* Copy 1 scan line and test for all zero. */
136 		code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
137 		if ( code < 0 ) goto xit;
138 		/* The mem... or str... functions should be faster than */
139 		/* the following code, but all systems seem to implement */
140 		/* them so badly that this code is faster. */
141 		   {	register const long *zip = (const long *)in_data;
142 			register int zcnt = line_size;
143 			register const byte *zipb;
144 			for ( ; zcnt >= 4 * sizeof(long); zip += 4, zcnt -= 4 * sizeof(long) )
145 			   {	if ( zip[0] | zip[1] | zip[2] | zip[3] )
146 					goto notz;
147 			   }
148 			zipb = (const byte *)zip;
149 			while ( --zcnt >= 0 )
150 			   {
151 				if ( *zipb++ )
152 					goto notz;
153 			   }
154 			/* Line is all zero, skip */
155 			lnum++;
156 			skip++;
157 			continue;
158 notz:			;
159 		   }
160 
161 		/* Vertical tab to the appropriate position.  Note here that
162 		   we make sure we don't move below limit. */
163 		if ( lnum > limit )
164 		    {	skip -= (limit - lnum);
165 			lnum = limit;
166 		    }
167 
168 		/* The SJ48 can only skip in steps of 1/180" */
169 		if (yres == 180) {
170 		  skips = skip;
171 		} else {
172 		  if (skip & 1) {
173 		    skip--; /* Makes skip even. */
174 		    lnum--;
175 		  }
176                   skips = skip/2;
177 		}
178 
179 		while ( skips > 255 )
180 		   {	fputs("\033J\377", prn_stream);
181 			skips -= 255;
182 		   }
183 		if ( skips )
184 			fprintf(prn_stream, "\033J%c", skips);
185 
186 		/* If we've printed as far as "limit", then reset "limit"
187 		   to "last_row" for the final printing pass. */
188 		if ( lnum == limit )
189 			limit = last_row;
190 		skip = 0;
191 
192 		/* Transpose in blocks of 8 scan lines. */
193 		for ( bnum = 0; bnum < bits_per_column; bnum += 8 )
194 		   {	int lcnt = min(8, limit - lnum);
195 			byte *inp = in;
196 			byte *outp = outl;
197 		   	lcnt = gdev_prn_copy_scan_lines(pdev,
198 				lnum, in, lcnt * line_size);
199 			if ( lcnt < 0 )
200 			   {	code = lcnt;
201 				goto xit;
202 			   }
203 			if ( lcnt < 8 )
204 				memset(in + lcnt * line_size, 0,
205 				       (8 - lcnt) * line_size);
206 			for ( ; inp < in_end; inp++, outp += bits_per_column )
207 			   {	gdev_prn_transpose_8x8(inp, line_size,
208 					outp, bytes_per_column);
209 			   }
210 			outl++;
211 			lnum += lcnt;
212 			skip += lcnt;
213 		   }
214 
215 		/* Send the bits to the printer.  We alternate horizontal
216 		   skips with the data.  The horizontal skips are in units
217 		   of 1/180 inches, so we look at the data in groups of
218 		   1 or 2 columns depending on resolution (controlled
219                    by skip_unit).  */
220 		outl = out;
221 		do
222 		   {	int count;
223 			int n;
224 			byte *out_ptr;
225 
226 			/* First look for blank groups of columns. */
227 			while(outl < out_end)
228 			   {	n = count = min(out_end - outl, skip_unit);
229 				out_ptr = outl;
230 				while ( --count >= 0 )
231 				   {	if ( *out_ptr++ )
232 						break;
233 				   }
234 				if ( count >= 0 )
235 					break;
236 				else
237 					outl = out_ptr;
238 			   }
239 			if (outl >= out_end)
240 				break;
241 			if (outl > out_beg)
242 			   {	count = (outl - out_beg) / skip_unit;
243 				fprintf(prn_stream, "\033\\%c%c",
244 					count & 0xff, count >> 8);
245 			   }
246 
247 			/* Next look for non-blank groups of columns. */
248 			out_beg = outl;
249 			outl += n;
250 			while(outl < out_end)
251 			   {	n = count = min(out_end - outl, skip_unit);
252 				out_ptr = outl;
253 				while ( --count >= 0 )
254 				   {	if ( *out_ptr++ )
255 						break;
256 				   }
257 				if ( count < 0 )
258 					break;
259 				else
260 					outl += n;
261 			   }
262 			count = outl - out_beg;
263 			{
264 			  /* What to transmit is the number of columns in the row.
265 			     Compare this with the <Esc>|*-command wich expects the
266 			     total number of bytes in the graphic row! */
267 			  int count1 = count/bytes_per_column;
268 			  fprintf(prn_stream, "\033*%c%c%c",
269 				  mode, count1 & 0xff, count1 >> 8);
270 			}
271 			fwrite(out_beg, 1, count, prn_stream);
272 			out_beg = outl;
273 			outl += n;
274 		   }
275 		while ( out_beg < out_end );
276 
277 		fputc('\r', prn_stream);
278 		skip = bits_per_column;  /* <CR> only moves to the beginning of the row. */
279 	   }
280 
281 	/* Eject the page */
282 xit:	fputc(014, prn_stream);	/* form feed */
283 	fflush(prn_stream);
284 fin:	if ( out != 0 )
285 		gs_free(pdev->memory, (char *)out, bits_per_column, line_size,
286 			"sj48_print_page(out)");
287 	if ( in != 0 )
288 		gs_free(pdev->memory, (char *)in, 8, line_size, "sj48_print_page(in)");
289 	return code;
290 }
291