xref: /plan9/sys/src/cmd/gs/src/gdevdjtc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 1990, 1991 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: gdevdjtc.c,v 1.6 2002/06/16 05:48:54 lpd Exp $*/
18 /* HP DeskJet 500C driver */
19 #include "gdevprn.h"
20 #include "gdevpcl.h"
21 #include "malloc_.h"
22 
23 /***
24  *** Note: this driver was contributed by a user, Alfred Kayser:
25  ***       please contact AKayser@et.tudelft.nl if you have questions.
26  ***/
27 
28 #ifndef SHINGLING        /* Interlaced, multi-pass printing */
29 #define SHINGLING 1      /* 0 = none, 1 = 50%, 2 = 25%, 2 is best & slowest */
30 #endif
31 
32 #ifndef DEPLETION        /* 'Intelligent' dot-removal */
33 #define DEPLETION 1      /* 0 = none, 1 = 25%, 2 = 50%, 1 best for graphics? */
34 #endif                   /* Use 0 for transparencies */
35 
36 #define X_DPI 300
37 #define Y_DPI 300
38 /* bytes per line for DeskJet Color */
39 #define LINE_SIZE ((X_DPI * 85 / 10 + 63) / 64 * 8)
40 
41 /* The device descriptors */
42 private dev_proc_print_page(djet500c_print_page);
43 
44 private gx_device_procs djet500c_procs =
45   prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
46     gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb);
47 
48 const gx_device_printer far_data gs_djet500c_device =
49   prn_device(djet500c_procs, "djet500c",
50     85,                /* width_10ths, 8.5" */
51     120,		/* height_10ths, 12" */
52     X_DPI, Y_DPI,
53     0.25, 0.25, 0.25, 0.25,        /* margins */
54     3, djet500c_print_page);
55 
56 /* Forward references */
57 private int djet500c_print_page(gx_device_printer *, FILE *);
58 
59 static int mode2compress(byte *row, byte *end_row, byte *compressed);
60 
61 /* The DeskJet 500C uses additive colors in separate planes. */
62 /* We only keep one bit of color, with 1 = R, 2 = G, 4 = B. */
63 /* Because the buffering routines assume 0 = white, */
64 /* we complement all the color components. */
65 
66 /* Send the page to the printer.  For speed, compress each scan line, */
67 /* since computer-to-printer communication time is often a bottleneck. */
68 /* The DeskJet Color can compress (mode 2) */
69 
70 private int
djet500c_print_page(gx_device_printer * pdev,FILE * fprn)71 djet500c_print_page(gx_device_printer *pdev, FILE *fprn)
72 {
73     byte *bitData=NULL;
74     byte *plane1=NULL;
75     byte *plane2=NULL;
76     byte *plane3=NULL;
77     int bitSize=0;
78     int planeSize=0;
79 
80     /* select the most compressed mode available & clear tmp storage */
81     /* put printer in known state */
82     fputs("\033E",fprn);
83 
84     /* ends raster graphics to set raster graphics resolution */
85     fputs("\033*rbC", fprn);	/*  was \033*rB  */
86 
87     /* set raster graphics resolution -- 300 dpi */
88     fputs("\033*t300R", fprn);
89 
90     /* A4, skip perf, def. paper tray */
91     fputs("\033&l26a0l1H", fprn);
92 
93     /* RGB Mode */
94     fputs("\033*r3U", fprn);
95 
96     /* set depletion level */
97     fprintf(fprn, "\033*o%dD", DEPLETION);
98 
99     /* set shingling level */
100     fprintf(fprn, "\033*o%dQ", SHINGLING);
101 
102     /* move to top left of page & set current position */
103     fputs("\033*p0x0Y", fprn); /* cursor pos: 0,0 */
104 
105     fputs("\033*b2M", fprn);	/*  mode 2 compression for now  */
106 
107     fputs("\033*r0A", fprn);  /* start graf. left */
108 
109     /* Send each scan line in turn */
110        {    int lnum;
111 	int num_blank_lines = 0;
112 	int lineSize = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
113 	if (lineSize>bitSize)
114 	{
115             if (bitData) free(bitData);
116             bitSize=lineSize;
117             bitData=(byte*)malloc(bitSize+16);
118 	}
119 	for (lnum=0; lnum<pdev->height; lnum++)
120 	{
121             byte *endData;
122 
123             gdev_prn_copy_scan_lines(pdev, lnum, bitData, lineSize);
124 
125             /* Remove trailing 0s. */
126             endData = bitData + lineSize;
127             while ( (endData>bitData) && (endData[-1] == 0) )
128 		endData--;
129             if (endData == bitData)
130 		num_blank_lines++;
131             else
132             {    int count, k, i, lineLen;
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 /*
217  * Mode 2 Row compression routine for the HP DeskJet & LaserJet IIp.
218  * Compresses data from row up to end_row, storing the result
219  * starting at compressed.  Returns the number of bytes stored.
220  * Runs of K<=127 literal bytes are encoded as K-1 followed by
221  * the bytes; runs of 2<=K<=127 identical bytes are encoded as
222  * 257-K followed by the byte.
223  * In the worst case, the result is N+(N/127)+1 bytes long,
224  * where N is the original byte count (end_row - row).
225  * I can't use the general pcl version, because it assume even linelength's
226  */
227 
228 static int
mode2compress(byte * row,byte * end_row,byte * compressed)229 mode2compress(byte *row, byte *end_row, byte *compressed)
230 {
231     register byte *exam; /* word being examined in the row to compress */
232     register byte *cptr = compressed; /* output pointer into compressed bytes */
233     int i, count, len;
234     byte test;
235 
236     exam = row;
237     while (1)
238     {
239 	test = *exam++;
240 	/* Advance exam until test==*exam  or exam==end_row */
241 	while ((test != *exam) && (exam < end_row))
242             test = *exam++;
243 	/* row points to start of differing bytes,
244            exam points to start of consequtive series
245                     or to end of row */
246 	if (exam<end_row) exam--;
247 	len=exam-row;
248 	while (len>0)
249 	{
250             count=len;
251             if (count>127) count=127;
252             *cptr++=count-1;
253             for (i=0;i<count;i++) *cptr++ = *row++;
254             len-=count;
255 	}
256 	if (exam>=end_row) break;     /* done */
257 	exam++;     /* skip first same byte */
258 	while ((test == *exam) && (exam < end_row))  /* skip all same bytes */
259             exam++;
260 	/* exam points now first different word or to end of data */
261 	len = exam-row;
262 	while (len>0)
263 	{
264             count=len;
265             if (count>127) count=127;
266             *cptr++=(257-count);
267             *cptr++=test;
268             len-=count;
269 	}
270 	if (exam>=end_row) break;            /* end of data */
271 	row = exam;    /* row points to first dissimular byte */
272     }
273     return (cptr-compressed);
274 }
275