1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gdevpjet.c 8250 2007-09-25 13:31:24Z giles $*/
15 /* H-P PaintJet, PaintJet XL, and DEC LJ250 drivers. */
16 /* Thanks to Rob Reiss (rob@moray.berkeley.edu) for the PaintJet XL */
17 /* modifications. */
18 #include "gdevprn.h"
19 #include "gdevpcl.h"
20 
21 /* X_DPI and Y_DPI must be the same, and may be either 90 or 180. */
22 #define X_DPI 180
23 #define Y_DPI 180
24 
25 /* We round up LINE_SIZE to a multiple of 8 bytes */
26 /* because that's the unit of transposition from pixels to planes. */
27 #define LINE_SIZE ((X_DPI * 85 / 10 + 63) / 64 * 8)
28 
29 /* The device descriptors */
30 static dev_proc_print_page(lj250_print_page);
31 static dev_proc_print_page(paintjet_print_page);
32 static dev_proc_print_page(pjetxl_print_page);
33 static int pj_common_print_page(gx_device_printer *, FILE *, int, const char *);
34 static gx_device_procs paintjet_procs =
35   prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
36     gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb);
37 const gx_device_printer far_data gs_lj250_device =
38   prn_device(paintjet_procs, "lj250",
39 	85,				/* width_10ths, 8.5" */
40 	110,				/* height_10ths, 11" */
41 	X_DPI, Y_DPI,
42 	0.25, 0, 0.25, 0,		/* margins */
43 	3, lj250_print_page);
44 const gx_device_printer far_data gs_paintjet_device =
45   prn_device(paintjet_procs, "paintjet",
46 	85,				/* width_10ths, 8.5" */
47 	110,				/* height_10ths, 11" */
48 	X_DPI, Y_DPI,
49 	0.25, 0, 0.25, 0,		/* margins */
50 	3, paintjet_print_page);
51 static gx_device_procs pjetxl_procs =
52   prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
53     gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb);
54 const gx_device_printer far_data gs_pjetxl_device =
55   prn_device(pjetxl_procs, "pjetxl",
56 	85,				/* width_10ths, 8.5" */
57 	110,				/* height_10ths, 11" */
58 	X_DPI, Y_DPI,
59 	0.25, 0, 0, 0,			/* margins */
60 	3, pjetxl_print_page);
61 
62 /* Forward references */
63 static int compress1_row(const byte *, const byte *, byte *);
64 
65 /* ------ Internal routines ------ */
66 
67 /* Send a page to the LJ250.  We need to enter and exit */
68 /* the PaintJet emulation mode. */
69 static int
lj250_print_page(gx_device_printer * pdev,FILE * prn_stream)70 lj250_print_page(gx_device_printer *pdev, FILE *prn_stream)
71 {	fputs("\033%8", prn_stream);	/* Enter PCL emulation mode */
72 	/* ends raster graphics to set raster graphics resolution */
73 	fputs("\033*rB", prn_stream);
74 	/* Exit PCL emulation mode after printing */
75 	return pj_common_print_page(pdev, prn_stream, 0, "\033*r0B\014\033%@");
76 }
77 
78 /* Send a page to the PaintJet. */
79 static int
paintjet_print_page(gx_device_printer * pdev,FILE * prn_stream)80 paintjet_print_page(gx_device_printer *pdev, FILE *prn_stream)
81 {	/* ends raster graphics to set raster graphics resolution */
82 	fputs("\033*rB", prn_stream);
83 	return pj_common_print_page(pdev, prn_stream, 0, "\033*r0B\014");
84 }
85 
86 /* Send a page to the PaintJet XL. */
87 static int
pjetxl_print_page(gx_device_printer * pdev,FILE * prn_stream)88 pjetxl_print_page(gx_device_printer *pdev, FILE *prn_stream)
89 {	/* Initialize PaintJet XL for printing */
90 	fputs("\033E", prn_stream);
91 	/* The XL has a different vertical origin, who knows why?? */
92 	return pj_common_print_page(pdev, prn_stream, -360, "\033*rC");
93 }
94 
95 /* Send the page to the printer.  Compress each scan line. */
96 static int
pj_common_print_page(gx_device_printer * pdev,FILE * prn_stream,int y_origin,const char * end_page)97 pj_common_print_page(gx_device_printer *pdev, FILE *prn_stream, int y_origin,
98   const char *end_page)
99 {
100 #define DATA_SIZE (LINE_SIZE * 8)
101 	byte *data =
102 	        (byte *)gs_malloc(pdev->memory, DATA_SIZE, 1,
103 				  "paintjet_print_page(data)");
104 	byte *plane_data =
105 		(byte *)gs_malloc(pdev->memory, LINE_SIZE * 3, 1,
106 				  "paintjet_print_page(plane_data)");
107 	if ( data == 0 || plane_data == 0 )
108 	{	if ( data )
109 			gs_free(pdev->memory, (char *)data, DATA_SIZE, 1,
110 				"paintjet_print_page(data)");
111 		if ( plane_data )
112 			gs_free(pdev->memory, (char *)plane_data, LINE_SIZE * 3, 1,
113 				"paintjet_print_page(plane_data)");
114 		return_error(gs_error_VMerror);
115 	}
116 
117 	/* set raster graphics resolution -- 90 or 180 dpi */
118 	fprintf(prn_stream, "\033*t%dR", X_DPI);
119 
120 	/* set the line width */
121 	fprintf(prn_stream, "\033*r%dS", DATA_SIZE);
122 
123 	/* set the number of color planes */
124 	fprintf(prn_stream, "\033*r%dU", 3);		/* always 3 */
125 
126 	/* move to top left of page */
127 	fprintf(prn_stream, "\033&a0H\033&a%dV", y_origin);
128 
129 	/* select data compression */
130 	fputs("\033*b1M", prn_stream);
131 
132 	/* start raster graphics */
133 	fputs("\033*r1A", prn_stream);
134 
135 	/* Send each scan line in turn */
136 	   {	int lnum;
137 		int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
138 		int num_blank_lines = 0;
139 		for ( lnum = 0; lnum < pdev->height; lnum++ )
140 		   {	byte *end_data = data + line_size;
141 			gdev_prn_copy_scan_lines(pdev, lnum,
142 						 (byte *)data, line_size);
143 			/* Remove trailing 0s. */
144 			while ( end_data > data && end_data[-1] == 0 )
145 				end_data--;
146 			if ( end_data == data )
147 			   {	/* Blank line */
148 				num_blank_lines++;
149 			   }
150 			else
151 			   {	int i;
152 				byte *odp;
153 				byte *row;
154 
155 				/* Pad with 0s to fill out the last */
156 				/* block of 8 bytes. */
157 				memset(end_data, 0, 7);
158 
159 				/* Transpose the data to get pixel planes. */
160 				for ( i = 0, odp = plane_data; i < DATA_SIZE;
161 				      i += 8, odp++
162 				    )
163 				 { /* The following is for 16-bit machines */
164 #define spread3(c)\
165  { 0, c, c*0x100, c*0x101, c*0x10000L, c*0x10001L, c*0x10100L, c*0x10101L }
166 				   static ulong spr40[8] = spread3(0x40);
167 				   static ulong spr8[8] = spread3(8);
168 				   static ulong spr2[8] = spread3(2);
169 				   register byte *dp = data + i;
170 				   register ulong pword =
171 				     (spr40[dp[0]] << 1) +
172 				     (spr40[dp[1]]) +
173 				     (spr40[dp[2]] >> 1) +
174 				     (spr8[dp[3]] << 1) +
175 				     (spr8[dp[4]]) +
176 				     (spr8[dp[5]] >> 1) +
177 				     (spr2[dp[6]]) +
178 				     (spr2[dp[7]] >> 1);
179 				   odp[0] = (byte)(pword >> 16);
180 				   odp[LINE_SIZE] = (byte)(pword >> 8);
181 				   odp[LINE_SIZE*2] = (byte)(pword);
182 				 }
183 				/* Skip blank lines if any */
184 				if ( num_blank_lines > 0 )
185 				   {	/* move down from current position */
186 					fprintf(prn_stream, "\033&a+%dV",
187 						num_blank_lines * (720 / Y_DPI));
188 					num_blank_lines = 0;
189 				   }
190 
191 				/* Transfer raster graphics */
192 				/* in the order R, G, B. */
193 				for ( row = plane_data + LINE_SIZE * 2, i = 0;
194 				      i < 3; row -= LINE_SIZE, i++
195 				    )
196 				   {	byte temp[LINE_SIZE * 2];
197 					int count = compress1_row(row, row + LINE_SIZE, temp);
198 					fprintf(prn_stream, "\033*b%d%c",
199 						count, "VVW"[i]);
200 					fwrite(temp, sizeof(byte),
201 					       count, prn_stream);
202 				   }
203 			   }
204 		   }
205 	   }
206 
207 	/* end the page */
208 	fputs(end_page, prn_stream);
209 
210 	gs_free(pdev->memory, (char *)data, DATA_SIZE, 1, "paintjet_print_page(data)");
211 	gs_free(pdev->memory, (char *)plane_data, LINE_SIZE * 3, 1, "paintjet_print_page(plane_data)");
212 
213 	return 0;
214 }
215 
216 /*
217  * Row compression for the H-P PaintJet.
218  * Compresses data from row up to end_row, storing the result
219  * starting at compressed.  Returns the number of bytes stored.
220  * The compressed format consists of a byte N followed by a
221  * data byte that is to be repeated N+1 times.
222  * In the worst case, the `compressed' representation is
223  * twice as large as the input.
224  * We complement the bytes at the same time, because
225  * we accumulated the image in complemented form.
226  */
227 static int
compress1_row(const byte * row,const byte * end_row,byte * compressed)228 compress1_row(const byte *row, const byte *end_row,
229   byte *compressed)
230 {	register const byte *in = row;
231 	register byte *out = compressed;
232 	while ( in < end_row )
233 	   {	byte test = *in++;
234 		const byte *run = in;
235 		while ( in < end_row && *in == test ) in++;
236 		/* Note that in - run + 1 is the repetition count. */
237 		while ( in - run > 255 )
238 		   {	*out++ = 255;
239 			*out++ = ~test;
240 			run += 256;
241 		   }
242 		*out++ = in - run;
243 		*out++ = ~test;
244 	   }
245 	return out - compressed;
246 }
247