]> git.ipfire.org Git - thirdparty/cups.git/blob - test/ippevepcl.c
Update ipp documentation to reflect the behavior of configuring WiFi on IPP USB printers.
[thirdparty/cups.git] / test / ippevepcl.c
1 /*
2 * Generic HP PCL printer command for ippeveprinter/CUPS.
3 *
4 * Copyright © 2019 by Apple Inc.
5 *
6 * Licensed under Apache License v2.0. See the file "LICENSE" for more
7 * information.
8 */
9
10 /*
11 * Include necessary headers...
12 */
13
14 #include "ippevecommon.h"
15 #include "dither.h"
16
17
18 /*
19 * Local globals...
20 */
21
22 static unsigned pcl_bottom, /* Bottom line */
23 pcl_left, /* Left offset in line */
24 pcl_right, /* Right offset in line */
25 pcl_top, /* Top line */
26 pcl_blanks; /* Number of blank lines to skip */
27 static unsigned char pcl_white, /* White color */
28 *pcl_line, /* Line buffer */
29 *pcl_comp; /* Compression buffer */
30
31 /*
32 * Local functions...
33 */
34
35 static void pcl_end_page(cups_page_header2_t *header, unsigned page);
36 static void pcl_start_page(cups_page_header2_t *header, unsigned page);
37 static void pcl_write_line(cups_page_header2_t *header, unsigned y, const unsigned char *line);
38
39
40 /*
41 * 'main()' - Main entry for PCL printer command.
42 */
43
44 int /* O - Exit status */
45 main(int argc, /* I - Number of command-line arguments */
46 char *argv[]) /* I - Command-line arguments */
47 {
48 const char *content_type; /* Content type to print */
49 int fd; /* Input file */
50 cups_raster_t *ras; /* Raster stream */
51 cups_page_header2_t header; /* Page header */
52 unsigned page = 0, /* Current page */
53 y; /* Current line */
54 unsigned char *line; /* Line buffer */
55
56
57 /*
58 * First make sure we can read what is being printed.
59 */
60
61 if ((content_type = getenv("CONTENT_TYPE")) == NULL)
62 {
63 fputs("ERROR: CONTENT_TYPE environment variable not set, aborting.\n", stderr);
64 return (1);
65 }
66 else if (strcasecmp(content_type, "image/pwg-raster") && strcasecmp(content_type, "image/urf"))
67 {
68 fprintf(stderr, "ERROR: CONTENT_TYPE %s not supported.\n", content_type);
69 return (1);
70 }
71
72 /*
73 * Then get the input file...
74 */
75
76 if (argc == 1)
77 {
78 fd = 0;
79 }
80 else if (argc == 2)
81 {
82 if ((fd = open(argv[1], O_RDONLY)) < 0)
83 {
84 fprintf(stderr, "ERROR: Unable to open \"%s\": %s\n", argv[1], strerror(errno));
85 return (1);
86 }
87 }
88 else
89 {
90 fputs("ERROR: Too many arguments provided, aborting.\n", stderr);
91 return (1);
92 }
93
94 /*
95 * Open the raster stream and send pages...
96 */
97
98 if ((ras = cupsRasterOpen(fd, CUPS_RASTER_READ)) == NULL)
99 {
100 fputs("ERROR: Unable to read raster data, aborting.\n", stderr);
101 return (1);
102 }
103
104 fputs("\033E", stdout);
105
106 while (cupsRasterReadHeader2(ras, &header))
107 {
108 page ++;
109
110 if (header.cupsColorSpace != CUPS_CSPACE_W && header.cupsColorSpace != CUPS_CSPACE_K)
111 {
112 fputs("ERROR: Unsupported color space, aborting.\n", stderr);
113 break;
114 }
115 else if (header.cupsBitsPerColor != 1 && header.cupsBitsPerColor != 8)
116 {
117 fputs("ERROR: Unsupported bit depth, aborting.\n", stderr);
118 break;
119 }
120
121 line = malloc(header.cupsBytesPerLine);
122
123 pcl_start_page(&header, page);
124 for (y = 0; y < header.cupsHeight; y ++)
125 {
126 if (cupsRasterReadPixels(ras, line, header.cupsBytesPerLine))
127 pcl_write_line(&header, y, line);
128 else
129 break;
130 }
131 pcl_end_page(&header, page);
132
133 free(line);
134 }
135
136 cupsRasterClose(ras);
137
138 return (0);
139 }
140
141
142
143 /*
144 * 'pcl_end_page()' - End of PCL page.
145 */
146
147 static void
148 pcl_end_page(
149 cups_page_header2_t *header, /* I - Page header */
150 unsigned page) /* I - Current page */
151 {
152 /*
153 * End graphics...
154 */
155
156 fputs("\033*r0B", stdout);
157
158 /*
159 * Formfeed as needed...
160 */
161
162 if (!(header->Duplex && (page & 1)))
163 putchar('\f');
164
165 /*
166 * Free the output buffers...
167 */
168
169 free(pcl_line);
170 free(pcl_comp);
171 }
172
173
174 /*
175 * 'pcl_start_page()' - Start a PCL page.
176 */
177
178 static void
179 pcl_start_page(
180 cups_page_header2_t *header, /* I - Page header */
181 unsigned page) /* I - Current page */
182 {
183 /*
184 * Setup margins to be 1/6" top and bottom and 1/4" or .135" on the
185 * left and right.
186 */
187
188 pcl_top = header->HWResolution[1] / 6;
189 pcl_bottom = header->cupsHeight - header->HWResolution[1] / 6 - 1;
190
191 if (header->PageSize[1] == 842)
192 {
193 /* A4 gets special side margins to expose an 8" print area */
194 pcl_left = (header->cupsWidth - 8 * header->HWResolution[0]) / 2;
195 pcl_right = pcl_left + 8 * header->HWResolution[0] - 1;
196 }
197 else
198 {
199 /* All other sizes get 1/4" margins */
200 pcl_left = header->HWResolution[0] / 4;
201 pcl_right = header->cupsWidth - header->HWResolution[0] / 4 - 1;
202 }
203
204 if (!header->Duplex || (page & 1))
205 {
206 /*
207 * Set the media size...
208 */
209
210 printf("\033&l12D\033&k12H"); /* Set 12 LPI, 10 CPI */
211 printf("\033&l0O"); /* Set portrait orientation */
212
213 switch (header->PageSize[1])
214 {
215 case 540 : /* Monarch Envelope */
216 printf("\033&l80A");
217 break;
218
219 case 595 : /* A5 */
220 printf("\033&l25A");
221 break;
222
223 case 624 : /* DL Envelope */
224 printf("\033&l90A");
225 break;
226
227 case 649 : /* C5 Envelope */
228 printf("\033&l91A");
229 break;
230
231 case 684 : /* COM-10 Envelope */
232 printf("\033&l81A");
233 break;
234
235 case 709 : /* B5 Envelope */
236 printf("\033&l100A");
237 break;
238
239 case 756 : /* Executive */
240 printf("\033&l1A");
241 break;
242
243 case 792 : /* Letter */
244 printf("\033&l2A");
245 break;
246
247 case 842 : /* A4 */
248 printf("\033&l26A");
249 break;
250
251 case 1008 : /* Legal */
252 printf("\033&l3A");
253 break;
254
255 case 1191 : /* A3 */
256 printf("\033&l27A");
257 break;
258
259 case 1224 : /* Tabloid */
260 printf("\033&l6A");
261 break;
262 }
263
264 /*
265 * Set top margin and turn off perforation skip...
266 */
267
268 printf("\033&l%uE\033&l0L", 12 * pcl_top / header->HWResolution[1]);
269
270 if (header->Duplex)
271 {
272 int mode = header->Duplex ? 1 + header->Tumble != 0 : 0;
273
274 printf("\033&l%dS", mode); /* Set duplex mode */
275 }
276 }
277 else if (header->Duplex)
278 printf("\033&a2G"); /* Print on back side */
279
280 /*
281 * Set graphics mode...
282 */
283
284 printf("\033*t%uR", header->HWResolution[0]);
285 /* Set resolution */
286 printf("\033*r%uS", pcl_right - pcl_left + 1);
287 /* Set width */
288 printf("\033*r%uT", pcl_bottom - pcl_top + 1);
289 /* Set height */
290 printf("\033&a0H\033&a%uV", 720 * pcl_top / header->HWResolution[1]);
291 /* Set position */
292
293 printf("\033*b2M"); /* Use PackBits compression */
294 printf("\033*r1A"); /* Start graphics */
295
296 /*
297 * Allocate the output buffers...
298 */
299
300 pcl_white = header->cupsBitsPerColor == 1 ? 0 : 255;
301 pcl_blanks = 0;
302 pcl_line = malloc(header->cupsWidth / 8 + 1);
303 pcl_comp = malloc(2 * header->cupsBytesPerLine + 2);
304 }
305
306
307 /*
308 * 'pcl_write_line()' - Write a line of raster data.
309 */
310
311 static void
312 pcl_write_line(
313 cups_page_header2_t *header, /* I - Raster information */
314 unsigned y, /* I - Line number */
315 const unsigned char *line) /* I - Pixels on line */
316 {
317 unsigned x; /* Column number */
318 unsigned char bit, /* Current bit */
319 byte, /* Current byte */
320 *outptr, /* Pointer into output buffer */
321 *outend, /* End of output buffer */
322 *start, /* Start of sequence */
323 *compptr; /* Pointer into compression buffer */
324 unsigned count; /* Count of bytes for output */
325 const unsigned char *ditherline; /* Pointer into dither table */
326
327
328 if (line[0] == pcl_white && !memcmp(line, line + 1, header->cupsBytesPerLine - 1))
329 {
330 /*
331 * Skip blank line...
332 */
333
334 pcl_blanks ++;
335 return;
336 }
337
338 if (header->cupsBitsPerPixel == 1)
339 {
340 /*
341 * B&W bitmap data can be used directly...
342 */
343
344 outend = (unsigned char *)line + (pcl_right + 7) / 8;
345 outptr = (unsigned char *)line + pcl_left / 8;
346 }
347 else
348 {
349 /*
350 * Dither 8-bit grayscale to B&W...
351 */
352
353 y &= 63;
354 ditherline = threshold[y];
355
356 for (x = pcl_left, bit = 128, byte = 0, outptr = pcl_line; x <= pcl_right; x ++, line ++)
357 {
358 if (*line <= ditherline[x & 63])
359 byte |= bit;
360
361 if (bit == 1)
362 {
363 *outptr++ = byte;
364 byte = 0;
365 bit = 128;
366 }
367 else
368 bit >>= 1;
369 }
370
371 if (bit != 128)
372 *outptr++ = byte;
373
374 outend = outptr;
375 outptr = pcl_line;
376 }
377
378 /*
379 * Apply compression...
380 */
381
382 compptr = pcl_comp;
383
384 while (outptr < outend)
385 {
386 if ((outptr + 1) >= outend)
387 {
388 /*
389 * Single byte on the end...
390 */
391
392 *compptr++ = 0x00;
393 *compptr++ = *outptr++;
394 }
395 else if (outptr[0] == outptr[1])
396 {
397 /*
398 * Repeated sequence...
399 */
400
401 outptr ++;
402 count = 2;
403
404 while (outptr < (outend - 1) &&
405 outptr[0] == outptr[1] &&
406 count < 127)
407 {
408 outptr ++;
409 count ++;
410 }
411
412 *compptr++ = (unsigned char)(257 - count);
413 *compptr++ = *outptr++;
414 }
415 else
416 {
417 /*
418 * Non-repeated sequence...
419 */
420
421 start = outptr;
422 outptr ++;
423 count = 1;
424
425 while (outptr < (outend - 1) &&
426 outptr[0] != outptr[1] &&
427 count < 127)
428 {
429 outptr ++;
430 count ++;
431 }
432
433 *compptr++ = (unsigned char)(count - 1);
434
435 memcpy(compptr, start, count);
436 compptr += count;
437 }
438 }
439
440 /*
441 * Output the line...
442 */
443
444 if (pcl_blanks > 0)
445 {
446 /*
447 * Skip blank lines first...
448 */
449
450 printf("\033*b%dY", pcl_blanks);
451 pcl_blanks = 0;
452 }
453
454 printf("\033*b%dW", (int)(compptr - pcl_comp));
455 fwrite(pcl_comp, 1, (size_t)(compptr - pcl_comp), stdout);
456 }