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