xref: /plan9/sys/src/cmd/gs/src/gdevl31s.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 /* Copyright (C) 1998 Aladdin Enterprises.  All rights reserved.
2 
3   This file is part of AFPL Ghostscript.
4 
5   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6   distributor accepts any responsibility for the consequences of using it, or
7   for whether it serves any particular purpose or works at all, unless he or
8   she says so in writing.  Refer to the Aladdin Free Public License (the
9   "License") for full details.
10 
11   Every copy of AFPL Ghostscript must include a copy of the License, normally
12   in a plain ASCII text file named PUBLIC.  The License grants you the right
13   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14   conditions described in the License.  Among other things, the License
15   requires that the copyright notice and this notice be preserved on all
16   copies.
17 */
18 
19 /*$Id: gdevl31s.c,v 1.2 2000/09/19 19:00:13 lpd Exp $ */
20 /*
21  * H-P LaserJet 3100 driver
22  *
23  * This is a driver for use with the H-P LaserJet 3100 Software.
24  * It requires installed H-P LaserJet 3100 Software to print.
25  * It can be used with smbclient to print from an UNIX box
26  * to a LaserJet 3100 printer attached to a MS-Windows box.
27  *
28  * Written by Ulrich Schmid, uschmid@mail.hh.provi.de.
29  */
30 
31 #include "gdevprn.h"
32 #include "gdevmeds.h"
33 
34 #define XCORRECTION 0.11
35 #define YCORRECTION 0.12
36 
37 /* order matters!             0       1        2        3       4      5     6       7           8 */
38 const char *media[10]   =  {"a4", "letter", "legal", "com10", "c5",  "dl", "b5", "monarch", "executive", 0};
39 const int height[2][10] = {{3447,     3240,    4140,    5587, 2644,  5083, 2975,      4387,        3090, 0},
40 			   {6894,     6480,    8280,   11167, 5288, 10159, 5950,      8767,        6180, 0}};
41 const int width[2]      = {2528,
42 			   5056};
43 #define LARGEST_MEDIUM 2 /* legal */
44 
45 /* These codes correspond to sequences of pixels with the same color.
46  * After the code for a sequence < 64 pixels the color changes.
47  * After the code for a sequence with 64 pixels the previous color continues. */
48 private struct {
49 	uint bits;
50 	uint length; /* number of valid bits */
51 } code[2][65] =
52 /* White */
53 {{{0x0ac,  8}, {0x038,  6}, {0x00e,  4}, {0x001,  4}, {0x00d,  4}, {0x003,  4}, {0x007,  4}, {0x00f,  4},
54   {0x019,  5}, {0x005,  5}, {0x01c,  5}, {0x002,  5}, {0x004,  6}, {0x030,  6}, {0x00b,  6}, {0x02b,  6},
55   {0x015,  6}, {0x035,  6}, {0x072,  7}, {0x018,  7}, {0x008,  7}, {0x074,  7}, {0x060,  7}, {0x010,  7},
56   {0x00a,  7}, {0x06a,  7}, {0x064,  7}, {0x012,  7}, {0x00c,  7}, {0x040,  8}, {0x0c0,  8}, {0x058,  8},
57   {0x0d8,  8}, {0x048,  8}, {0x0c8,  8}, {0x028,  8}, {0x0a8,  8}, {0x068,  8}, {0x0e8,  8}, {0x014,  8},
58   {0x094,  8}, {0x054,  8}, {0x0d4,  8}, {0x034,  8}, {0x0b4,  8}, {0x020,  8}, {0x0a0,  8}, {0x050,  8},
59   {0x0d0,  8}, {0x04a,  8}, {0x0ca,  8}, {0x02a,  8}, {0x0aa,  8}, {0x024,  8}, {0x0a4,  8}, {0x01a,  8},
60   {0x09a,  8}, {0x05a,  8}, {0x0da,  8}, {0x052,  8}, {0x0d2,  8}, {0x04c,  8}, {0x0cc,  8}, {0x02c,  8},
61   {0x01b,  5}},
62 /* Black */
63  {{0x3b0, 10}, {0x002,  3}, {0x003,  2}, {0x001,  2}, {0x006,  3}, {0x00c,  4}, {0x004,  4}, {0x018,  5},
64   {0x028,  6}, {0x008,  6}, {0x010,  7}, {0x050,  7}, {0x070,  7}, {0x020,  8}, {0x0e0,  8}, {0x030,  9},
65   {0x3a0, 10}, {0x060, 10}, {0x040, 10}, {0x730, 11}, {0x0b0, 11}, {0x1b0, 11}, {0x760, 11}, {0x0a0, 11},
66   {0x740, 11}, {0x0c0, 11}, {0x530, 12}, {0xd30, 12}, {0x330, 12}, {0xb30, 12}, {0x160, 12}, {0x960, 12},
67   {0x560, 12}, {0xd60, 12}, {0x4b0, 12}, {0xcb0, 12}, {0x2b0, 12}, {0xab0, 12}, {0x6b0, 12}, {0xeb0, 12},
68   {0x360, 12}, {0xb60, 12}, {0x5b0, 12}, {0xdb0, 12}, {0x2a0, 12}, {0xaa0, 12}, {0x6a0, 12}, {0xea0, 12},
69   {0x260, 12}, {0xa60, 12}, {0x4a0, 12}, {0xca0, 12}, {0x240, 12}, {0xec0, 12}, {0x1c0, 12}, {0xe40, 12},
70   {0x140, 12}, {0x1a0, 12}, {0x9a0, 12}, {0xd40, 12}, {0x340, 12}, {0x5a0, 12}, {0x660, 12}, {0xe60, 12},
71   {0x3c0, 10}}};
72 
73 /* Define the default, maximum resolutions. */
74 #ifndef X_DPI
75 #  define X_DPI 600
76 #endif
77 #ifndef Y_DPI
78 #  define Y_DPI 600
79 #endif
80 
81 /* The device descriptors */
82 private dev_proc_print_page_copies(lj3100sw_print_page_copies);
83 private dev_proc_close_device(lj3100sw_close);
84 
85 private gx_device_procs prn_lj3100sw_procs =
86     prn_params_procs(gdev_prn_open, gdev_prn_output_page, lj3100sw_close,
87 	     gdev_prn_get_params, gdev_prn_put_params);
88 
89 /* workaround to emulate the missing prn_device_margins_copies macro */
90 #define gx_default_print_page_copies lj3100sw_print_page_copies
91 gx_device_printer far_data gs_lj3100sw_device =
92     prn_device_margins/*_copies*/(prn_lj3100sw_procs, "lj3100sw",
93 	     DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
94 	     X_DPI, Y_DPI,
95 	     XCORRECTION, YCORRECTION,
96 	     0.25, 0.2, 0.25, 0.2,
97 	     1, 0 /* lj3100sw_print_page_copies */);
98 #undef gx_default_print_page_copies
99 
100 #define ppdev ((gx_device_printer *)pdev)
101 
102 #define BUFFERSIZE 0x1000
103 
104 private void
105 lj3100sw_output_section_header(FILE *prn_stream, int type, int arg1, int arg2)
106 {
107 	fputc(type      & 0xff, prn_stream);
108 	fputc(type >> 8 & 0xff, prn_stream);
109 	fputc(arg1      & 0xff, prn_stream);
110 	fputc(arg1 >> 8 & 0xff, prn_stream);
111 	fputc(arg2      & 0xff, prn_stream);
112 	fputc(arg2 >> 8 & 0xff, prn_stream);
113 }
114 
115 private void
116 lj3100sw_flush_buffer(FILE *prn_stream, char *buffer, char **pptr)
117 {
118 	int size = *pptr - buffer;
119 	if (size) {
120 		lj3100sw_output_section_header(prn_stream, 0, size, 0);
121 		fwrite(buffer, 1, size, prn_stream);
122 		*pptr = buffer;
123 	}
124 }
125 
126 private void
127 lj3100sw_output_data_byte(FILE *prn_stream, char *buffer, char **pptr, int val)
128 {
129 	if (*pptr >= buffer + BUFFERSIZE)
130 		lj3100sw_flush_buffer(prn_stream, buffer, pptr);
131 	*(*pptr)++ = val;
132 }
133 
134 private void
135 lj3100sw_output_repeated_data_bytes(FILE *prn_stream, char *buffer, char **pptr, int val, int num)
136 {
137 	int size;
138 	while (num) {
139 		if (*pptr >= buffer + BUFFERSIZE)
140 			lj3100sw_flush_buffer(prn_stream, buffer, pptr);
141 		size = min(num, buffer + BUFFERSIZE - *pptr);
142 		memset(*pptr, val, size);
143 		*pptr += size;
144 		num -= size;
145 	}
146 }
147 
148 private void
149 lj3100sw_output_newline(FILE *prn_stream, char *buffer, char **pptr)
150 {
151 	lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0);
152 	lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0);
153 	lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x80);
154 }
155 
156 private void
157 lj3100sw_output_empty_line(FILE *prn_stream, char *buffer, char **pptr, bool high_resolution)
158 {
159 	if (high_resolution) {
160 		lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x80);
161 		lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x0f);
162 		lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x78);
163 		lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0xac);
164 	} else {
165 		lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x80);
166 		lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x87);
167 		lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x0d);
168 	}
169 }
170 
171 private int
172 lj3100sw_print_page_copies(gx_device_printer *pdev, FILE *prn_stream, int num_copies /* ignored */)
173 {
174 	int i, j;
175 	char buffer[BUFFERSIZE], *ptr = buffer;
176 	int medium_index = select_medium(pdev, media, LARGEST_MEDIUM);
177 	bool high_resolution = (pdev->x_pixels_per_inch > 300);
178 	int printer_height = height[high_resolution ? 1 : 0][medium_index];
179 	int printer_width  = width[high_resolution ? 1 : 0];
180 	int paper_height = pdev->height;
181 	int paper_width  = pdev->width;
182 	int line_size = gdev_prn_raster(pdev);
183 	byte *in = (byte *)gs_malloc(line_size, 1, "lj3100sw_print_page");
184 	byte *data;
185 	if (in == 0)
186 		return_error(gs_error_VMerror);
187 	if (gdev_prn_file_is_new(pdev)) {
188 		lj3100sw_output_section_header(prn_stream, 1, 0, 0);
189 		lj3100sw_output_repeated_data_bytes(prn_stream, buffer, &ptr, 0x1b, 12);
190 		ptr += sprintf(ptr, "\r\nBD");
191 		lj3100sw_output_repeated_data_bytes(prn_stream, buffer, &ptr, 0, 5520);
192 		ptr += sprintf(ptr, "%s\r\n%s %d\r\n%s %d\r\n%s %d\r\n%s %d\r\n%s %d\r\n%s %d\r\n",
193 			       "NJ",
194 			       "PQ", -1,
195 			       "RE",  high_resolution ? 6 : 2,
196 			       "SL",  printer_width,
197 			       "LM",  0,
198 			       "PS",  medium_index,
199 			       "PC",  0);
200 		lj3100sw_flush_buffer(prn_stream, buffer, &ptr);
201 	}
202 
203 	lj3100sw_output_section_header(prn_stream, 3, ppdev->NumCopies, 0);
204 	ptr += sprintf(ptr, "%s %d\r\n%s\r\n",
205 		       "CM", 1,
206 		       "PD");
207 	*ptr++ = 0;
208 	lj3100sw_output_newline(prn_stream, buffer, &ptr);
209 
210 	for (i = 0; i < printer_height; i++) {
211 		if (i < paper_height) {
212 			int color = 0; /* white */
213 			int count = 0;
214 			int bit_index = 0;
215 			uint tmp = 0;
216 			gdev_prn_get_bits(pdev, i, in, &data);
217 			for (j = 0; j <= printer_width; j++) {
218 				int xoffset = (printer_width - paper_width) / 2;
219 				int newcolor = 0;
220 				if (j >= xoffset && j <  xoffset + paper_width)
221 					newcolor = (data[(j - xoffset) / 8] >> (7 - (j - xoffset) % 8)) & 1;
222 				if (j == printer_width)
223 					newcolor = !color; /* force output */
224 				if (newcolor == color)
225 					count++;
226 				else if (count == printer_width && color == 0) /* implies j == printer_width */
227 					lj3100sw_output_empty_line(prn_stream, buffer, &ptr, high_resolution);
228 				else    /* print a sequence of pixels with a uniform color */
229 					while (newcolor != color) {
230 						int size = min(count, 64);
231 						tmp |= code[color][size].bits << bit_index;
232 						bit_index += code[color][size].length;
233 						while (bit_index >= 8)	{
234 							lj3100sw_output_data_byte(prn_stream, buffer, &ptr, tmp & 0xff);
235 							tmp >>= 8;
236 							bit_index -= 8;
237 						}
238 						if (size == 64)
239 							count -= 64;
240 						else {
241 							color = newcolor;
242 							count = 1;
243 						}
244 					}
245 			}
246 			if (bit_index)
247 				lj3100sw_output_data_byte(prn_stream, buffer, &ptr, tmp & 0xff);
248 		}
249 		else
250 			lj3100sw_output_empty_line(prn_stream, buffer, &ptr, high_resolution);
251 		lj3100sw_output_newline(prn_stream, buffer, &ptr);
252 	}
253 
254 	for (i = 0; i < 3; i++ ) {
255 		lj3100sw_output_data_byte(prn_stream, buffer, &ptr, 0x00);
256 		lj3100sw_output_data_byte(prn_stream, buffer, &ptr, 0x08);
257 		lj3100sw_output_data_byte(prn_stream, buffer, &ptr, 0x80);
258 	}
259 	lj3100sw_output_repeated_data_bytes(prn_stream, buffer, &ptr, 0, 520);
260 	lj3100sw_flush_buffer(prn_stream, buffer, &ptr);
261 
262 	lj3100sw_output_section_header(prn_stream, 4, 0, 0);
263 	for (i = 0; i < 4 * ppdev->NumCopies; i++)
264 		lj3100sw_output_section_header(prn_stream, 54, 0, 0);
265 
266 	gs_free((char *)in, line_size, 1, "lj3100sw_print_page");
267 	return 0;
268 }
269 
270 private int
271 lj3100sw_close(gx_device *pdev)
272 {
273 	int i;
274 	FILE *prn_stream = ((gx_device_printer *)pdev)->file;
275 
276 	lj3100sw_output_section_header(prn_stream, 0, 4, 0);
277 	fputs("XX\r\n", prn_stream);
278 	for (i = 0; i < 4 * ppdev->NumCopies; i++)
279 		lj3100sw_output_section_header(prn_stream, 54, 0, 0);
280 	lj3100sw_output_section_header(prn_stream, 2, 0, 0);
281 
282 	return gdev_prn_close(pdev);
283 }
284