1 /* Copyright (C) 2001-2019 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.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 /*
17  * H-P LaserJet 3100 driver
18  *
19  * This is a driver for use with the H-P LaserJet 3100 Software.
20  * It requires installed H-P LaserJet 3100 Software to print.
21  * It can be used with smbclient to print from an UNIX box
22  * to a LaserJet 3100 printer attached to a MS-Windows box.
23  *
24  * Written by Ulrich Schmid, uschmid@mail.hh.provi.de.
25  */
26 
27 #include "gdevprn.h"
28 #include "gdevmeds.h"
29 
30 #define XCORRECTION 0.11
31 #define YCORRECTION 0.12
32 
33 /* order matters!             0       1        2        3       4      5     6       7           8 */
34 const char *media[10]   =  {"a4", "letter", "legal", "com10", "c5",  "dl", "b5", "monarch", "executive", 0};
35 const int height[2][10] = {{3447,     3240,    4140,    5587, 2644,  5083, 2975,      4387,        3090, 0},
36                            {6894,     6480,    8280,   11167, 5288, 10159, 5950,      8767,        6180, 0}};
37 const int width[2]      = {2528,
38                            5056};
39 #define LARGEST_MEDIUM 2 /* legal */
40 
41 /* These codes correspond to sequences of pixels with the same color.
42  * After the code for a sequence < 64 pixels the color changes.
43  * After the code for a sequence with 64 pixels the previous color continues. */
44 static struct {
45         uint bits;
46         uint length; /* number of valid bits */
47 } code[2][65] =
48 /* White */
49 {{{0x0ac,  8}, {0x038,  6}, {0x00e,  4}, {0x001,  4}, {0x00d,  4}, {0x003,  4}, {0x007,  4}, {0x00f,  4},
50   {0x019,  5}, {0x005,  5}, {0x01c,  5}, {0x002,  5}, {0x004,  6}, {0x030,  6}, {0x00b,  6}, {0x02b,  6},
51   {0x015,  6}, {0x035,  6}, {0x072,  7}, {0x018,  7}, {0x008,  7}, {0x074,  7}, {0x060,  7}, {0x010,  7},
52   {0x00a,  7}, {0x06a,  7}, {0x064,  7}, {0x012,  7}, {0x00c,  7}, {0x040,  8}, {0x0c0,  8}, {0x058,  8},
53   {0x0d8,  8}, {0x048,  8}, {0x0c8,  8}, {0x028,  8}, {0x0a8,  8}, {0x068,  8}, {0x0e8,  8}, {0x014,  8},
54   {0x094,  8}, {0x054,  8}, {0x0d4,  8}, {0x034,  8}, {0x0b4,  8}, {0x020,  8}, {0x0a0,  8}, {0x050,  8},
55   {0x0d0,  8}, {0x04a,  8}, {0x0ca,  8}, {0x02a,  8}, {0x0aa,  8}, {0x024,  8}, {0x0a4,  8}, {0x01a,  8},
56   {0x09a,  8}, {0x05a,  8}, {0x0da,  8}, {0x052,  8}, {0x0d2,  8}, {0x04c,  8}, {0x0cc,  8}, {0x02c,  8},
57   {0x01b,  5}},
58 /* Black */
59  {{0x3b0, 10}, {0x002,  3}, {0x003,  2}, {0x001,  2}, {0x006,  3}, {0x00c,  4}, {0x004,  4}, {0x018,  5},
60   {0x028,  6}, {0x008,  6}, {0x010,  7}, {0x050,  7}, {0x070,  7}, {0x020,  8}, {0x0e0,  8}, {0x030,  9},
61   {0x3a0, 10}, {0x060, 10}, {0x040, 10}, {0x730, 11}, {0x0b0, 11}, {0x1b0, 11}, {0x760, 11}, {0x0a0, 11},
62   {0x740, 11}, {0x0c0, 11}, {0x530, 12}, {0xd30, 12}, {0x330, 12}, {0xb30, 12}, {0x160, 12}, {0x960, 12},
63   {0x560, 12}, {0xd60, 12}, {0x4b0, 12}, {0xcb0, 12}, {0x2b0, 12}, {0xab0, 12}, {0x6b0, 12}, {0xeb0, 12},
64   {0x360, 12}, {0xb60, 12}, {0x5b0, 12}, {0xdb0, 12}, {0x2a0, 12}, {0xaa0, 12}, {0x6a0, 12}, {0xea0, 12},
65   {0x260, 12}, {0xa60, 12}, {0x4a0, 12}, {0xca0, 12}, {0x240, 12}, {0xec0, 12}, {0x1c0, 12}, {0xe40, 12},
66   {0x140, 12}, {0x1a0, 12}, {0x9a0, 12}, {0xd40, 12}, {0x340, 12}, {0x5a0, 12}, {0x660, 12}, {0xe60, 12},
67   {0x3c0, 10}}};
68 
69 /* Define the default, maximum resolutions. */
70 #ifndef X_DPI
71 #  define X_DPI 600
72 #endif
73 #ifndef Y_DPI
74 #  define Y_DPI 600
75 #endif
76 
77 /* The device descriptors */
78 static dev_proc_print_page_copies(lj3100sw_print_page_copies);
79 static dev_proc_close_device(lj3100sw_close);
80 
81 /* Since the print_page doesn't alter the device, this device can print in the background */
82 static gx_device_procs prn_lj3100sw_procs =
83     prn_params_procs(gdev_prn_open, gdev_prn_bg_output_page, lj3100sw_close,
84              gdev_prn_get_params, gdev_prn_put_params);
85 
86 /* workaround to emulate the missing prn_device_margins_copies macro */
87 #define gx_default_print_page_copies lj3100sw_print_page_copies
88 gx_device_printer far_data gs_lj3100sw_device =
89     prn_device_margins/*_copies*/(prn_lj3100sw_procs, "lj3100sw",
90              DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
91              X_DPI, Y_DPI,
92              XCORRECTION, YCORRECTION,
93              0.25, 0.2, 0.25, 0.2,
94              1, 0 /* lj3100sw_print_page_copies */);
95 #undef gx_default_print_page_copies
96 
97 #define ppdev ((gx_device_printer *)pdev)
98 
99 #define BUFFERSIZE 0x1000
100 
101 static void
lj3100sw_output_section_header(gp_file * prn_stream,int type,int arg1,int arg2)102 lj3100sw_output_section_header(gp_file *prn_stream, int type, int arg1, int arg2)
103 {
104         gp_fputc(type      & 0xff, prn_stream);
105         gp_fputc(type >> 8 & 0xff, prn_stream);
106         gp_fputc(arg1      & 0xff, prn_stream);
107         gp_fputc(arg1 >> 8 & 0xff, prn_stream);
108         gp_fputc(arg2      & 0xff, prn_stream);
109         gp_fputc(arg2 >> 8 & 0xff, prn_stream);
110 }
111 
112 static void
lj3100sw_flush_buffer(gp_file * prn_stream,char * buffer,char ** pptr)113 lj3100sw_flush_buffer(gp_file *prn_stream, char *buffer, char **pptr)
114 {
115         int size = *pptr - buffer;
116         if (size) {
117                 lj3100sw_output_section_header(prn_stream, 0, size, 0);
118                 gp_fwrite(buffer, 1, size, prn_stream);
119                 *pptr = buffer;
120         }
121 }
122 
123 static void
lj3100sw_output_data_byte(gp_file * prn_stream,char * buffer,char ** pptr,int val)124 lj3100sw_output_data_byte(gp_file *prn_stream, char *buffer, char **pptr, int val)
125 {
126         if (*pptr >= buffer + BUFFERSIZE)
127                 lj3100sw_flush_buffer(prn_stream, buffer, pptr);
128         *(*pptr)++ = val;
129 }
130 
131 static void
lj3100sw_output_repeated_data_bytes(gp_file * prn_stream,char * buffer,char ** pptr,int val,int num)132 lj3100sw_output_repeated_data_bytes(gp_file *prn_stream, char *buffer, char **pptr, int val, int num)
133 {
134         int size;
135         while (num) {
136                 if (*pptr >= buffer + BUFFERSIZE)
137                         lj3100sw_flush_buffer(prn_stream, buffer, pptr);
138                 size = min(num, buffer + BUFFERSIZE - *pptr);
139                 memset(*pptr, val, size);
140                 *pptr += size;
141                 num -= size;
142         }
143 }
144 
145 static void
lj3100sw_output_newline(gp_file * prn_stream,char * buffer,char ** pptr)146 lj3100sw_output_newline(gp_file *prn_stream, char *buffer, char **pptr)
147 {
148         lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0);
149         lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0);
150         lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x80);
151 }
152 
153 static void
lj3100sw_output_empty_line(gp_file * prn_stream,char * buffer,char ** pptr,bool high_resolution)154 lj3100sw_output_empty_line(gp_file *prn_stream, char *buffer, char **pptr, bool high_resolution)
155 {
156         if (high_resolution) {
157                 lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x80);
158                 lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x0f);
159                 lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x78);
160                 lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0xac);
161         } else {
162                 lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x80);
163                 lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x87);
164                 lj3100sw_output_data_byte(prn_stream, buffer, pptr, 0x0d);
165         }
166 }
167 
168 static int
lj3100sw_print_page_copies(gx_device_printer * pdev,gp_file * prn_stream,int num_copies)169 lj3100sw_print_page_copies(gx_device_printer *pdev, gp_file *prn_stream, int num_copies /* ignored */)
170 {
171         int i, j;
172         char buffer[BUFFERSIZE], *ptr = buffer;
173         int medium_index = select_medium(pdev, media, LARGEST_MEDIUM);
174         bool high_resolution = (pdev->x_pixels_per_inch > 300);
175         int printer_height = height[high_resolution ? 1 : 0][medium_index];
176         int printer_width  = width[high_resolution ? 1 : 0];
177         int paper_height = pdev->height;
178         int paper_width  = pdev->width;
179         int line_size = gdev_prn_raster(pdev);
180         gs_memory_t *mem = pdev->memory;
181         byte *in = (byte *)gs_malloc(mem, line_size, 1, "lj3100sw_print_page");
182         byte *data;
183         int ecode = 0;
184 
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 += gs_sprintf(ptr, "\r\nBD");
191                 lj3100sw_output_repeated_data_bytes(prn_stream, buffer, &ptr, 0, 5520);
192                 ptr += gs_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 += gs_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 
217                         ecode = gdev_prn_get_bits(pdev, i, in, &data);
218                         if (ecode < 0)
219                             goto xit;
220                         for (j = 0; j <= printer_width; j++) {
221                                 int xoffset = (printer_width - paper_width) / 2;
222                                 int newcolor = 0;
223                                 if (j >= xoffset && j <  xoffset + paper_width)
224                                         newcolor = (data[(j - xoffset) / 8] >> (7 - (j - xoffset) % 8)) & 1;
225                                 if (j == printer_width)
226                                         newcolor = !color; /* force output */
227                                 if (newcolor == color)
228                                         count++;
229                                 else if (count == printer_width && color == 0) /* implies j == printer_width */
230                                         lj3100sw_output_empty_line(prn_stream, buffer, &ptr, high_resolution);
231                                 else    /* print a sequence of pixels with a uniform color */
232                                         while (newcolor != color) {
233                                                 int size = min(count, 64);
234                                                 tmp |= code[color][size].bits << bit_index;
235                                                 bit_index += code[color][size].length;
236                                                 while (bit_index >= 8)	{
237                                                         lj3100sw_output_data_byte(prn_stream, buffer, &ptr, tmp & 0xff);
238                                                         tmp >>= 8;
239                                                         bit_index -= 8;
240                                                 }
241                                                 if (size == 64)
242                                                         count -= 64;
243                                                 else {
244                                                         color = newcolor;
245                                                         count = 1;
246                                                 }
247                                         }
248                         }
249                         if (bit_index)
250                                 lj3100sw_output_data_byte(prn_stream, buffer, &ptr, tmp & 0xff);
251                 }
252                 else
253                         lj3100sw_output_empty_line(prn_stream, buffer, &ptr, high_resolution);
254                 lj3100sw_output_newline(prn_stream, buffer, &ptr);
255         }
256 
257         for (i = 0; i < 3; i++ ) {
258                 lj3100sw_output_data_byte(prn_stream, buffer, &ptr, 0x00);
259                 lj3100sw_output_data_byte(prn_stream, buffer, &ptr, 0x08);
260                 lj3100sw_output_data_byte(prn_stream, buffer, &ptr, 0x80);
261         }
262         lj3100sw_output_repeated_data_bytes(prn_stream, buffer, &ptr, 0, 520);
263         lj3100sw_flush_buffer(prn_stream, buffer, &ptr);
264 
265         lj3100sw_output_section_header(prn_stream, 4, 0, 0);
266         for (i = 0; i < 4 * ppdev->NumCopies; i++)
267                 lj3100sw_output_section_header(prn_stream, 54, 0, 0);
268 
269 xit:
270         gs_free(mem, (char *)in, line_size, 1, "lj3100sw_print_page");
271         return ecode;
272 }
273 
274 static int
lj3100sw_close(gx_device * pdev)275 lj3100sw_close(gx_device *pdev)
276 {
277         int i;
278         gp_file *prn_stream = ((gx_device_printer *)pdev)->file;
279 
280         if (prn_stream) {
281             lj3100sw_output_section_header(prn_stream, 0, 4, 0);
282             gp_fputs("XX\r\n", prn_stream);
283             for (i = 0; i < 4 * ppdev->NumCopies; i++)
284                     lj3100sw_output_section_header(prn_stream, 54, 0, 0);
285             lj3100sw_output_section_header(prn_stream, 2, 0, 0);
286         }
287         return gdev_prn_close(pdev);
288 }
289