1 /* Copyright (C) 2001-2012 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,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16 /* HP DeskJet 500C driver */
17 #include "gdevprn.h"
18 #include "gdevpcl.h"
19 #include "malloc_.h"
20
21 /***
22 *** Note: this driver was contributed by a user, Alfred Kayser:
23 *** please contact AKayser@et.tudelft.nl if you have questions.
24 ***/
25
26 #ifndef SHINGLING /* Interlaced, multi-pass printing */
27 #define SHINGLING 1 /* 0 = none, 1 = 50%, 2 = 25%, 2 is best & slowest */
28 #endif
29
30 #ifndef DEPLETION /* 'Intelligent' dot-removal */
31 #define DEPLETION 1 /* 0 = none, 1 = 25%, 2 = 50%, 1 best for graphics? */
32 #endif /* Use 0 for transparencies */
33
34 #define X_DPI 300
35 #define Y_DPI 300
36 /* bytes per line for DeskJet Color */
37 #define LINE_SIZE ((X_DPI * 85 / 10 + 63) / 64 * 8)
38
39 /* The device descriptors */
40 static dev_proc_print_page(djet500c_print_page);
41
42 static gx_device_procs djet500c_procs =
43 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
44 gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb);
45
46 const gx_device_printer far_data gs_djet500c_device =
47 prn_device(djet500c_procs, "djet500c",
48 85, /* width_10ths, 8.5" */
49 120, /* height_10ths, 12" */
50 X_DPI, Y_DPI,
51 0.25, 0.25, 0.25, 0.25, /* margins */
52 3, djet500c_print_page);
53
54 /* Forward references */
55 static int djet500c_print_page(gx_device_printer *, FILE *);
56
57 static int mode2compress(byte *row, byte *end_row, byte *compressed);
58
59 /* The DeskJet 500C uses additive colors in separate planes. */
60 /* We only keep one bit of color, with 1 = R, 2 = G, 4 = B. */
61 /* Because the buffering routines assume 0 = white, */
62 /* we complement all the color components. */
63
64 /* Send the page to the printer. For speed, compress each scan line, */
65 /* since computer-to-printer communication time is often a bottleneck. */
66 /* The DeskJet Color can compress (mode 2) */
67
68 static int
djet500c_print_page(gx_device_printer * pdev,FILE * fprn)69 djet500c_print_page(gx_device_printer *pdev, FILE *fprn)
70 {
71 byte *bitData=NULL;
72 byte *plane1=NULL;
73 byte *plane2=NULL;
74 byte *plane3=NULL;
75 int bitSize=0;
76 int planeSize=0;
77
78 /* select the most compressed mode available & clear tmp storage */
79 /* put printer in known state */
80 fputs("\033E",fprn);
81
82 /* ends raster graphics to set raster graphics resolution */
83 fputs("\033*rbC", fprn); /* was \033*rB */
84
85 /* set raster graphics resolution -- 300 dpi */
86 fputs("\033*t300R", fprn);
87
88 /* A4, skip perf, def. paper tray */
89 fputs("\033&l26a0l1H", fprn);
90
91 /* RGB Mode */
92 fputs("\033*r3U", fprn);
93
94 /* set depletion level */
95 fprintf(fprn, "\033*o%dD", DEPLETION);
96
97 /* set shingling level */
98 fprintf(fprn, "\033*o%dQ", SHINGLING);
99
100 /* move to top left of page & set current position */
101 fputs("\033*p0x0Y", fprn); /* cursor pos: 0,0 */
102
103 fputs("\033*b2M", fprn); /* mode 2 compression for now */
104
105 fputs("\033*r0A", fprn); /* start graf. left */
106
107 /* Send each scan line in turn */
108 { int lnum;
109 int num_blank_lines = 0;
110 int lineSize = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
111 if (lineSize>bitSize)
112 {
113 if (bitData) free(bitData);
114 bitSize=lineSize;
115 bitData=(byte*)malloc(bitSize+16);
116 }
117 for (lnum=0; lnum<pdev->height; lnum++)
118 {
119 byte *endData;
120
121 gdev_prn_copy_scan_lines(pdev, lnum, bitData, lineSize);
122
123 /* Identify and skip blank lines */
124 endData = bitData + lineSize;
125 while ( (endData>bitData) && (endData[-1] == 0) )
126 endData--;
127 if (endData == bitData)
128 num_blank_lines++;
129 else
130 {
131 int count, k, i, lineLen;
132 endData = bitData + lineSize;
133
134 /* Pad with 0s to fill out the last */
135 /* block of 8 bytes. */
136 memset(endData, 0, 7);
137
138 lineLen=((endData-bitData)+7)/8; /* Round to next 8multiple */
139 if (planeSize<lineLen)
140 {
141 if (plane1) free(plane1);
142 if (plane2) free(plane2);
143 if (plane3) free(plane3);
144 planeSize=lineLen;
145 plane1=(byte*)malloc(planeSize+8);
146 plane2=(byte*)malloc(planeSize+8);
147 plane3=(byte*)malloc(planeSize+8);
148 }
149 /* Transpose the data to get pixel planes. */
150 for (k=i=0; k<lineLen; i+=8, k++)
151 {
152 register ushort t, c;
153
154 /* Three smaller loops are better optimizable and use less
155 vars, so most of them can be in registers even on pc's */
156 for (c=t=0;t<8;t++)
157 c = (c<<1) | (bitData[t+i]&4);
158 plane3[k] = ~(byte)(c>>2);
159 for (c=t=0;t<8;t++)
160 c = (c<<1) | (bitData[t+i]&2);
161 plane2[k] = ~(byte)(c>>1);
162 for (c=t=0;t<8;t++)
163 c = (c<<1) | (bitData[t+i]&1);
164 plane1[k] = ~(byte)(c);
165 }
166
167 /* Skip blank lines if any */
168 if (num_blank_lines > 0)
169 { /* move down from current position */
170 fprintf(fprn, "\033*b%dY", num_blank_lines);
171 num_blank_lines = 0;
172 }
173
174 /* Transfer raster graphics */
175 /* in the order R, G, B. */
176 /* lineLen is at least bitSize/8, so bitData can easily be used to store
177 lineLen of bytes */
178 /* P.s. mode9 compression is akward(??) to use, because the lineLenght's
179 are different, so we are stuck with mode 2, which is good enough */
180
181 /* set the line width */
182 fprintf(fprn, "\033*r%dS", lineLen*8);
183
184 count = mode2compress(plane1, plane1 + lineLen, bitData);
185 fprintf(fprn, "\033*b%dV", count);
186 fwrite(bitData, sizeof(byte), count, fprn);
187 count = mode2compress(plane2, plane2 + lineLen, bitData);
188 fprintf(fprn, "\033*b%dV", count);
189 fwrite(bitData, sizeof(byte), count, fprn);
190 count = mode2compress(plane3, plane3 + lineLen, bitData);
191 fprintf(fprn, "\033*b%dW", count);
192 fwrite(bitData, sizeof(byte), count, fprn);
193 }
194 }
195 }
196 /* end raster graphics */
197 fputs("\033*rbC", fprn); /* was \033*rB */
198 fputs("\033*r1U", fprn); /* back to 1 plane */
199
200 /* put printer in known state */
201 fputs("\033E",fprn);
202
203 /* eject page */
204 fputs("\033&l0H", fprn);
205
206 /* release allocated memory */
207 if (bitData) free(bitData);
208 if (plane1) free(plane1);
209 if (plane2) free(plane2);
210 if (plane3) free(plane3);
211
212 return 0;
213 }
214
215 /*
216 * Mode 2 Row compression routine for the HP DeskJet & LaserJet IIp.
217 * Compresses data from row up to end_row, storing the result
218 * starting at compressed. Returns the number of bytes stored.
219 * Runs of K<=127 literal bytes are encoded as K-1 followed by
220 * the bytes; runs of 2<=K<=127 identical bytes are encoded as
221 * 257-K followed by the byte.
222 * In the worst case, the result is N+(N/127)+1 bytes long,
223 * where N is the original byte count (end_row - row).
224 * I can't use the general pcl version, because it assume even linelength's
225 */
226
227 static int
mode2compress(byte * row,byte * end_row,byte * compressed)228 mode2compress(byte *row, byte *end_row, byte *compressed)
229 {
230 register byte *exam; /* word being examined in the row to compress */
231 register byte *cptr = compressed; /* output pointer into compressed bytes */
232 int i, count, len;
233 byte test;
234
235 exam = row;
236 while (1)
237 {
238 test = *exam++;
239 /* Advance exam until test==*exam or exam==end_row */
240 while ((test != *exam) && (exam < end_row))
241 test = *exam++;
242 /* row points to start of differing bytes,
243 exam points to start of consequtive series
244 or to end of row */
245 if (exam<end_row) exam--;
246 len=exam-row;
247 while (len>0)
248 {
249 count=len;
250 if (count>127) count=127;
251 *cptr++=count-1;
252 for (i=0;i<count;i++) *cptr++ = *row++;
253 len-=count;
254 }
255 if (exam>=end_row) break; /* done */
256 exam++; /* skip first same byte */
257 while ((test == *exam) && (exam < end_row)) /* skip all same bytes */
258 exam++;
259 /* exam points now first different word or to end of data */
260 len = exam-row;
261 while (len>0)
262 {
263 count=len;
264 if (count>127) count=127;
265 *cptr++=(257-count);
266 *cptr++=test;
267 len-=count;
268 }
269 if (exam>=end_row) break; /* end of data */
270 row = exam; /* row points to first dissimular byte */
271 }
272 return (cptr-compressed);
273 }
274