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