4 * Hewlett-Packard Page Control Language filter for the Common UNIX
5 * Printing System (CUPS).
7 * Copyright 1993-2001 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Easy Software Products and are protected by Federal
11 * copyright law. Distribution and use rights are outlined in the file
12 * "LICENSE.txt" which should have been included with this file. If this
13 * file is missing or damaged please contact Easy Software Products
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636-3111 USA
21 * Voice: (301) 373-9603
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
27 * Setup() - Prepare the printer for printing.
28 * StartPage() - Start a page of graphics.
29 * EndPage() - Finish a page of graphics.
30 * Shutdown() - Shutdown the printer.
31 * CancelJob() - Cancel the current job...
32 * CompressData() - Compress a line of graphics.
33 * OutputLine() - Output a line of graphics.
34 * main() - Main entry and processing of driver.
38 * Include necessary headers...
41 #include <cups/cups.h>
42 #include <cups/string.h>
54 unsigned char *Planes
[4], /* Output buffers */
55 *CompBuffer
, /* Compression buffer */
56 *BitBuffer
; /* Buffer for output bits */
57 int NumPlanes
, /* Number of color planes */
58 ColorBits
, /* Number of bits per color */
59 Feed
, /* Number of lines to skip */
60 Duplex
, /* Current duplex mode */
61 Page
; /* Current page number */
69 void StartPage(ppd_file_t
*ppd
, cups_page_header_t
*header
);
73 void CancelJob(int sig
);
74 void CompressData(unsigned char *line
, int length
, int plane
, int type
);
75 void OutputLine(cups_page_header_t
*header
);
79 * 'Setup()' - Prepare the printer for printing.
86 * Send a PCL reset sequence.
95 * 'StartPage()' - Start a page of graphics.
99 StartPage(ppd_file_t
*ppd
, /* I - PPD file */
100 cups_page_header_t
*header
) /* I - Page header */
102 int plane
; /* Looping var */
103 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
104 struct sigaction action
; /* Actions for POSIX signals */
105 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
109 * Register a signal handler to eject the current page if the
113 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
114 sigset(SIGTERM
, CancelJob
);
115 #elif defined(HAVE_SIGACTION)
116 memset(&action
, 0, sizeof(action
));
118 sigemptyset(&action
.sa_mask
);
119 action
.sa_handler
= CancelJob
;
120 sigaction(SIGTERM
, &action
, NULL
);
122 signal(SIGTERM
, CancelJob
);
123 #endif /* HAVE_SIGSET */
126 * Setup printer/job attributes...
129 Duplex
= header
->Duplex
;
130 ColorBits
= header
->cupsBitsPerColor
;
132 if (!Duplex
|| (Page
& 1))
135 * Set the media type, position, and size...
138 printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
139 printf("\033&l0O"); /* Set portrait orientation */
141 switch (header
->PageSize
[1])
143 case 540 : /* Monarch Envelope */
144 printf("\033&l80A"); /* Set page size */
147 case 624 : /* DL Envelope */
148 printf("\033&l90A"); /* Set page size */
151 case 649 : /* C5 Envelope */
152 printf("\033&l91A"); /* Set page size */
155 case 684 : /* COM-10 Envelope */
156 printf("\033&l81A"); /* Set page size */
159 case 709 : /* B5 Envelope */
160 printf("\033&l100A"); /* Set page size */
163 case 756 : /* Executive */
164 printf("\033&l1A"); /* Set page size */
167 case 792 : /* Letter */
168 printf("\033&l2A"); /* Set page size */
172 printf("\033&l26A"); /* Set page size */
175 case 1008 : /* Legal */
176 printf("\033&l3A"); /* Set page size */
180 printf("\033&l27A"); /* Set page size */
183 case 1224 : /* Tabloid */
184 printf("\033&l6A"); /* Set page size */
188 printf("\033&l%dP", /* Set page length */
189 header
->PageSize
[1] / 12);
190 printf("\033&l0E"); /* Set top margin to 0 */
192 printf("\033&l%dX", header
->NumCopies
); /* Set number copies */
194 if (header
->MediaPosition
)
195 printf("\033&l%dH", /* Set media position */
196 header
->MediaPosition
);
198 if (header
->cupsMediaType
)
199 printf("\033&l%dM", /* Set media type */
200 header
->cupsMediaType
);
203 printf("\033&l%dS", /* Set duplex mode */
204 header
->Duplex
+ header
->Tumble
);
206 printf("\033&l0L"); /* Turn off perforation skip */
208 if (ppd
&& ppd
->model_number
== 2)
209 printf("\033&l-2H"); /* Load media */
212 printf("\033&a2G"); /* Set back side */
215 * Set graphics mode...
218 printf("\033*t%dR", header
->HWResolution
[0]); /* Set resolution */
220 if (ppd
->model_number
== 2)
223 * Figure out the number of color planes...
226 if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
232 * Send 26-byte configure image data command with horizontal and
233 * vertical resolutions as well as a color count...
237 putchar(2); /* Format 2 */
238 putchar(NumPlanes
); /* Output planes */
240 putchar(header
->HWResolution
[0] >> 8); /* Black resolution */
241 putchar(header
->HWResolution
[0]);
242 putchar(header
->HWResolution
[1] >> 8);
243 putchar(header
->HWResolution
[1]);
245 putchar(1 << ColorBits
); /* # of black levels */
247 putchar(header
->HWResolution
[0] >> 8); /* Cyan resolution */
248 putchar(header
->HWResolution
[0]);
249 putchar(header
->HWResolution
[1] >> 8);
250 putchar(header
->HWResolution
[1]);
252 putchar(1 << ColorBits
); /* # of cyan levels */
254 putchar(header
->HWResolution
[0] >> 8); /* Magenta resolution */
255 putchar(header
->HWResolution
[0]);
256 putchar(header
->HWResolution
[1] >> 8);
257 putchar(header
->HWResolution
[1]);
259 putchar(1 << ColorBits
); /* # of magenta levels */
261 putchar(header
->HWResolution
[0] >> 8); /* Yellow resolution */
262 putchar(header
->HWResolution
[0]);
263 putchar(header
->HWResolution
[1] >> 8);
264 putchar(header
->HWResolution
[1]);
266 putchar(1 << ColorBits
); /* # of yellow levels */
270 if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
273 printf("\033*r-4U"); /* Set KCMY graphics */
275 else if (header
->cupsColorSpace
== CUPS_CSPACE_CMY
)
278 printf("\033*r-3U"); /* Set CMY graphics */
281 NumPlanes
= 1; /* Black&white graphics */
285 * Set size and position of graphics...
288 printf("\033*r%dS", header
->cupsWidth
); /* Set width */
289 printf("\033*r%dT", header
->cupsHeight
); /* Set height */
291 printf("\033&a0H"); /* Set horizontal position */
294 printf("\033&a%.0fV", /* Set vertical position */
295 10.0 * (ppd
->sizes
[0].length
- ppd
->sizes
[0].top
));
297 printf("\033&a0V"); /* Set top-of-page */
299 printf("\033*r1A"); /* Start graphics */
301 if (header
->cupsCompression
)
302 printf("\033*b%dM", /* Set compression */
303 header
->cupsCompression
);
305 Feed
= 0; /* No blank lines yet */
308 * Allocate memory for a line of graphics...
311 Planes
[0] = malloc(header
->cupsBytesPerLine
);
312 for (plane
= 1; plane
< NumPlanes
; plane
++)
313 Planes
[plane
] = Planes
[0] + plane
* header
->cupsBytesPerLine
/ NumPlanes
;
316 BitBuffer
= malloc(ColorBits
* ((header
->cupsWidth
+ 7) / 8));
320 if (header
->cupsCompression
)
321 CompBuffer
= malloc(header
->cupsBytesPerLine
* 2);
328 * 'EndPage()' - Finish a page of graphics.
334 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
335 struct sigaction action
; /* Actions for POSIX signals */
336 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
340 * Eject the current page...
345 printf("\033*rC"); /* End color GFX */
347 if (!(Duplex
&& (Page
& 1)))
348 printf("\033&l0H"); /* Eject current page */
352 printf("\033*r0B"); /* End GFX */
354 if (!(Duplex
&& (Page
& 1)))
355 printf("\014"); /* Eject current page */
361 * Unregister the signal handler...
364 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
365 sigset(SIGTERM
, SIG_IGN
);
366 #elif defined(HAVE_SIGACTION)
367 memset(&action
, 0, sizeof(action
));
369 sigemptyset(&action
.sa_mask
);
370 action
.sa_handler
= SIG_IGN
;
371 sigaction(SIGTERM
, &action
, NULL
);
373 signal(SIGTERM
, SIG_IGN
);
374 #endif /* HAVE_SIGSET */
391 * 'Shutdown()' - Shutdown the printer.
398 * Send a PCL reset sequence.
407 * 'CancelJob()' - Cancel the current job...
411 CancelJob(int sig
) /* I - Signal */
413 int i
; /* Looping var */
419 * Send out lots of NUL bytes to clear out any pending raster data...
422 for (i
= 0; i
< 600; i
++)
426 * End the current page and exit...
437 * 'CompressData()' - Compress a line of graphics.
441 CompressData(unsigned char *line
, /* I - Data to compress */
442 int length
, /* I - Number of bytes */
443 int plane
, /* I - Color plane */
444 int type
) /* I - Type of compression */
446 unsigned char *line_ptr
, /* Current byte pointer */
447 *line_end
, /* End-of-line byte pointer */
448 *comp_ptr
, /* Pointer into compression buffer */
449 *start
; /* Start of compression sequence */
450 int count
; /* Count of bytes for output */
457 * Do no compression...
461 line_end
= line
+ length
;
466 * Do run-length encoding...
469 line_end
= line
+ length
;
470 for (line_ptr
= line
, comp_ptr
= CompBuffer
;
472 comp_ptr
+= 2, line_ptr
+= count
)
475 (line_ptr
+ count
) < line_end
&&
476 line_ptr
[0] == line_ptr
[count
] &&
480 comp_ptr
[0] = count
- 1;
481 comp_ptr
[1] = line_ptr
[0];
484 line_ptr
= CompBuffer
;
490 * Do TIFF pack-bits encoding...
494 line_end
= line
+ length
;
495 comp_ptr
= CompBuffer
;
497 while (line_ptr
< line_end
)
499 if ((line_ptr
+ 1) >= line_end
)
502 * Single byte on the end...
506 *comp_ptr
++ = *line_ptr
++;
508 else if (line_ptr
[0] == line_ptr
[1])
511 * Repeated sequence...
517 while (line_ptr
< (line_end
- 1) &&
518 line_ptr
[0] == line_ptr
[1] &&
525 *comp_ptr
++ = 257 - count
;
526 *comp_ptr
++ = *line_ptr
++;
531 * Non-repeated sequence...
538 while (line_ptr
< (line_end
- 1) &&
539 line_ptr
[0] != line_ptr
[1] &&
546 *comp_ptr
++ = count
- 1;
548 memcpy(comp_ptr
, start
, count
);
553 line_ptr
= CompBuffer
;
559 * Set the length of the data and write a raster plane...
562 printf("\033*b%d%c", line_end
- line_ptr
, plane
);
563 fwrite(line_ptr
, line_end
- line_ptr
, 1, stdout
);
568 * 'OutputLine()' - Output a line of graphics.
572 OutputLine(cups_page_header_t
*header
) /* I - Page header */
574 int plane
, /* Current plane */
575 bytes
, /* Bytes to write */
576 count
; /* Bytes to convert */
577 unsigned char bit
, /* Current plane data */
578 bit0
, /* Current low bit data */
579 bit1
, /* Current high bit data */
580 *plane_ptr
, /* Pointer into Planes */
581 *bit_ptr
; /* Pointer into BitBuffer */
585 * Output whitespace as needed...
590 printf("\033*b%dY", Feed
);
595 * Write bitmap data as needed...
598 bytes
= (header
->cupsWidth
+ 7) / 8;
600 for (plane
= 0; plane
< NumPlanes
; plane
++)
607 CompressData(Planes
[plane
], bytes
, plane
< (NumPlanes
- 1) ? 'V' : 'W',
608 header
->cupsCompression
);
613 * Separate low and high bit data into separate buffers.
616 for (count
= header
->cupsBytesPerLine
/ NumPlanes
,
617 plane_ptr
= Planes
[plane
], bit_ptr
= BitBuffer
;
619 count
-= 2, plane_ptr
+= 2, bit_ptr
++)
623 bit0
= ((bit
& 64) << 1) | ((bit
& 16) << 2) | ((bit
& 4) << 3) | ((bit
& 1) << 4);
624 bit1
= (bit
& 128) | ((bit
& 32) << 1) | ((bit
& 8) << 2) | ((bit
& 2) << 3);
630 bit0
|= (bit
& 1) | ((bit
& 4) >> 1) | ((bit
& 16) >> 2) | ((bit
& 64) >> 3);
631 bit1
|= ((bit
& 2) >> 1) | ((bit
& 8) >> 2) | ((bit
& 32) >> 3) | ((bit
& 128) >> 4);
635 bit_ptr
[bytes
] = bit1
;
639 * Send low and high bits...
642 CompressData(BitBuffer
, bytes
, 'V', header
->cupsCompression
);
643 CompressData(BitBuffer
+ bytes
, bytes
, plane
< (NumPlanes
- 1) ? 'V' : 'W',
644 header
->cupsCompression
);
652 * 'main()' - Main entry and processing of driver.
655 int /* O - Exit status */
656 main(int argc
, /* I - Number of command-line arguments */
657 char *argv
[]) /* I - Command-line arguments */
659 int fd
; /* File descriptor */
660 cups_raster_t
*ras
; /* Raster stream for printing */
661 cups_page_header_t header
; /* Page header from file */
662 int y
; /* Current line */
663 ppd_file_t
*ppd
; /* PPD file */
667 * Make sure status messages are not buffered...
670 setbuf(stderr
, NULL
);
673 * Check command-line...
676 if (argc
< 6 || argc
> 7)
679 * We don't have the correct number of arguments; write an error message
683 fputs("ERROR: rastertopcl job-id user title copies options [file]\n", stderr
);
688 * Open the page stream...
693 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
695 perror("ERROR: Unable to open raster file - ");
703 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
706 * Initialize the print device...
709 ppd
= ppdOpenFile(getenv("PPD"));
714 * Process pages as needed...
719 while (cupsRasterReadHeader(ras
, &header
))
722 * Write a status message with the page number and number of copies.
727 fprintf(stderr
, "PAGE: %d %d\n", Page
, header
.NumCopies
);
733 StartPage(ppd
, &header
);
736 * Loop for each line on the page...
739 for (y
= 0; y
< header
.cupsHeight
; y
++)
742 * Let the user know how far we have progressed...
746 fprintf(stderr
, "INFO: Printing page %d, %d%% complete...\n", Page
,
747 100 * y
/ header
.cupsHeight
);
750 * Read a line of graphics...
753 if (cupsRasterReadPixels(ras
, Planes
[0], header
.cupsBytesPerLine
) < 1)
757 * See if the line is blank; if not, write it to the printer...
761 memcmp(Planes
[0], Planes
[0] + 1, header
.cupsBytesPerLine
- 1))
775 * Shutdown the printer...
784 * Close the raster stream...
787 cupsRasterClose(ras
);
792 * If no pages were printed, send an error message...
796 fputs("ERROR: No pages found!\n", stderr
);
798 fputs("INFO: " CUPS_SVERSION
" is ready to print.\n", stderr
);