2 * Generic HP PCL printer command for ippeveprinter/CUPS.
4 * Copyright © 2019 by Apple Inc.
6 * Licensed under Apache License v2.0. See the file "LICENSE" for more
11 * Include necessary headers...
14 #include "ippevecommon.h"
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 */
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
);
41 * 'main()' - Main entry for PCL printer command.
44 int /* O - Exit status */
45 main(int argc
, /* I - Number of command-line arguments */
46 char *argv
[]) /* I - Command-line arguments */
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 */
54 unsigned char *line
; /* Line buffer */
58 * First make sure we can read what is being printed.
61 if ((content_type
= getenv("CONTENT_TYPE")) == NULL
)
63 fputs("ERROR: CONTENT_TYPE environment variable not set, aborting.\n", stderr
);
66 else if (strcasecmp(content_type
, "image/pwg-raster") && strcasecmp(content_type
, "image/urf"))
68 fprintf(stderr
, "ERROR: CONTENT_TYPE %s not supported.\n", content_type
);
73 * Then get the input file...
82 if ((fd
= open(argv
[1], O_RDONLY
)) < 0)
84 fprintf(stderr
, "ERROR: Unable to open \"%s\": %s\n", argv
[1], strerror(errno
));
90 fputs("ERROR: Too many arguments provided, aborting.\n", stderr
);
95 * Open the raster stream and send pages...
98 if ((ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
)) == NULL
)
100 fputs("ERROR: Unable to read raster data, aborting.\n", stderr
);
104 fputs("\033E", stdout
);
106 while (cupsRasterReadHeader2(ras
, &header
))
110 if (header
.cupsColorSpace
!= CUPS_CSPACE_W
&& header
.cupsColorSpace
!= CUPS_CSPACE_K
)
112 fputs("ERROR: Unsupported color space, aborting.\n", stderr
);
115 else if (header
.cupsBitsPerColor
!= 1 && header
.cupsBitsPerColor
!= 8)
117 fputs("ERROR: Unsupported bit depth, aborting.\n", stderr
);
121 line
= malloc(header
.cupsBytesPerLine
);
123 pcl_start_page(&header
, page
);
124 for (y
= 0; y
< header
.cupsHeight
; y
++)
126 if (cupsRasterReadPixels(ras
, line
, header
.cupsBytesPerLine
))
127 pcl_write_line(&header
, y
, line
);
131 pcl_end_page(&header
, page
);
136 cupsRasterClose(ras
);
144 * 'pcl_end_page()' - End of PCL page.
149 cups_page_header2_t
*header
, /* I - Page header */
150 unsigned page
) /* I - Current page */
156 fputs("\033*r0B", stdout
);
159 * Formfeed as needed...
162 if (!(header
->Duplex
&& (page
& 1)))
166 * Free the output buffers...
175 * 'pcl_start_page()' - Start a PCL page.
180 cups_page_header2_t
*header
, /* I - Page header */
181 unsigned page
) /* I - Current page */
184 * Setup margins to be 1/6" top and bottom and 1/4" or .135" on the
188 pcl_top
= header
->HWResolution
[1] / 6;
189 pcl_bottom
= header
->cupsHeight
- header
->HWResolution
[1] / 6 - 1;
191 if (header
->PageSize
[1] == 842)
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;
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;
204 if (!header
->Duplex
|| (page
& 1))
207 * Set the media size...
210 printf("\033&l12D\033&k12H"); /* Set 12 LPI, 10 CPI */
211 printf("\033&l0O"); /* Set portrait orientation */
213 switch (header
->PageSize
[1])
215 case 540 : /* Monarch Envelope */
223 case 624 : /* DL Envelope */
227 case 649 : /* C5 Envelope */
231 case 684 : /* COM-10 Envelope */
235 case 709 : /* B5 Envelope */
236 printf("\033&l100A");
239 case 756 : /* Executive */
243 case 792 : /* Letter */
251 case 1008 : /* Legal */
259 case 1224 : /* Tabloid */
265 * Set top margin and turn off perforation skip...
268 printf("\033&l%uE\033&l0L", 12 * pcl_top
/ header
->HWResolution
[1]);
272 int mode
= header
->Duplex
? 1 + header
->Tumble
!= 0 : 0;
274 printf("\033&l%dS", mode
); /* Set duplex mode */
277 else if (header
->Duplex
)
278 printf("\033&a2G"); /* Print on back side */
281 * Set graphics mode...
284 printf("\033*t%uR", header
->HWResolution
[0]);
286 printf("\033*r%uS", pcl_right
- pcl_left
+ 1);
288 printf("\033*r%uT", pcl_bottom
- pcl_top
+ 1);
290 printf("\033&a0H\033&a%uV", 720 * pcl_top
/ header
->HWResolution
[1]);
293 printf("\033*b2M"); /* Use PackBits compression */
294 printf("\033*r1A"); /* Start graphics */
297 * Allocate the output buffers...
300 pcl_white
= header
->cupsBitsPerColor
== 1 ? 0 : 255;
302 pcl_line
= malloc(header
->cupsWidth
/ 8 + 1);
303 pcl_comp
= malloc(2 * header
->cupsBytesPerLine
+ 2);
308 * 'pcl_write_line()' - Write a line of raster data.
313 cups_page_header2_t
*header
, /* I - Raster information */
314 unsigned y
, /* I - Line number */
315 const unsigned char *line
) /* I - Pixels on line */
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 */
328 if (line
[0] == pcl_white
&& !memcmp(line
, line
+ 1, header
->cupsBytesPerLine
- 1))
338 if (header
->cupsBitsPerPixel
== 1)
341 * B&W bitmap data can be used directly...
344 outend
= (unsigned char *)line
+ (pcl_right
+ 7) / 8;
345 outptr
= (unsigned char *)line
+ pcl_left
/ 8;
350 * Dither 8-bit grayscale to B&W...
354 ditherline
= threshold
[y
];
356 for (x
= pcl_left
, bit
= 128, byte
= 0, outptr
= pcl_line
; x
<= pcl_right
; x
++, line
++)
358 if (*line
<= ditherline
[x
& 63])
379 * Apply compression...
384 while (outptr
< outend
)
386 if ((outptr
+ 1) >= outend
)
389 * Single byte on the end...
393 *compptr
++ = *outptr
++;
395 else if (outptr
[0] == outptr
[1])
398 * Repeated sequence...
404 while (outptr
< (outend
- 1) &&
405 outptr
[0] == outptr
[1] &&
412 *compptr
++ = (unsigned char)(257 - count
);
413 *compptr
++ = *outptr
++;
418 * Non-repeated sequence...
425 while (outptr
< (outend
- 1) &&
426 outptr
[0] != outptr
[1] &&
433 *compptr
++ = (unsigned char)(count
- 1);
435 memcpy(compptr
, start
, count
);
447 * Skip blank lines first...
450 printf("\033*b%dY", pcl_blanks
);
454 printf("\033*b%dW", (int)(compptr
- pcl_comp
));
455 fwrite(pcl_comp
, 1, (size_t)(compptr
- pcl_comp
), stdout
);