2 * "$Id: rastertohp.c 4493 2005-02-18 02:09:53Z mike $"
4 * Hewlett-Packard Page Control Language filter for the Common UNIX
5 * Printing System (CUPS).
7 * Copyright 1993-2005 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 USA
21 * Voice: (301) 373-9600
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
25 * This file is subject to the Apple OS-Developed Software exception.
29 * Setup() - Prepare the printer for printing.
30 * StartPage() - Start a page of graphics.
31 * EndPage() - Finish a page of graphics.
32 * Shutdown() - Shutdown the printer.
33 * CancelJob() - Cancel the current job...
34 * CompressData() - Compress a line of graphics.
35 * OutputLine() - Output a line of graphics.
36 * main() - Main entry and processing of driver.
40 * Include necessary headers...
43 #include <cups/cups.h>
44 #include <cups/string.h>
56 unsigned char *Planes
[4], /* Output buffers */
57 *CompBuffer
, /* Compression buffer */
58 *BitBuffer
; /* Buffer for output bits */
59 int NumPlanes
, /* Number of color planes */
60 ColorBits
, /* Number of bits per color */
61 Feed
, /* Number of lines to skip */
62 Duplex
, /* Current duplex mode */
63 Page
; /* Current page number */
71 void StartPage(ppd_file_t
*ppd
, cups_page_header_t
*header
);
75 void CancelJob(int sig
);
76 void CompressData(unsigned char *line
, int length
, int plane
, int type
);
77 void OutputLine(cups_page_header_t
*header
);
81 * 'Setup()' - Prepare the printer for printing.
88 * Send a PCL reset sequence.
97 * 'StartPage()' - Start a page of graphics.
101 StartPage(ppd_file_t
*ppd
, /* I - PPD file */
102 cups_page_header_t
*header
) /* I - Page header */
104 int plane
; /* Looping var */
105 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
106 struct sigaction action
; /* Actions for POSIX signals */
107 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
111 * Register a signal handler to eject the current page if the
115 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
116 sigset(SIGTERM
, CancelJob
);
117 #elif defined(HAVE_SIGACTION)
118 memset(&action
, 0, sizeof(action
));
120 sigemptyset(&action
.sa_mask
);
121 action
.sa_handler
= CancelJob
;
122 sigaction(SIGTERM
, &action
, NULL
);
124 signal(SIGTERM
, CancelJob
);
125 #endif /* HAVE_SIGSET */
128 * Show page device dictionary...
131 fprintf(stderr
, "DEBUG: StartPage...\n");
132 fprintf(stderr
, "DEBUG: MediaClass = \"%s\"\n", header
->MediaClass
);
133 fprintf(stderr
, "DEBUG: MediaColor = \"%s\"\n", header
->MediaColor
);
134 fprintf(stderr
, "DEBUG: MediaType = \"%s\"\n", header
->MediaType
);
135 fprintf(stderr
, "DEBUG: OutputType = \"%s\"\n", header
->OutputType
);
137 fprintf(stderr
, "DEBUG: AdvanceDistance = %d\n", header
->AdvanceDistance
);
138 fprintf(stderr
, "DEBUG: AdvanceMedia = %d\n", header
->AdvanceMedia
);
139 fprintf(stderr
, "DEBUG: Collate = %d\n", header
->Collate
);
140 fprintf(stderr
, "DEBUG: CutMedia = %d\n", header
->CutMedia
);
141 fprintf(stderr
, "DEBUG: Duplex = %d\n", header
->Duplex
);
142 fprintf(stderr
, "DEBUG: HWResolution = [ %d %d ]\n", header
->HWResolution
[0],
143 header
->HWResolution
[1]);
144 fprintf(stderr
, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
145 header
->ImagingBoundingBox
[0], header
->ImagingBoundingBox
[1],
146 header
->ImagingBoundingBox
[2], header
->ImagingBoundingBox
[3]);
147 fprintf(stderr
, "DEBUG: InsertSheet = %d\n", header
->InsertSheet
);
148 fprintf(stderr
, "DEBUG: Jog = %d\n", header
->Jog
);
149 fprintf(stderr
, "DEBUG: LeadingEdge = %d\n", header
->LeadingEdge
);
150 fprintf(stderr
, "DEBUG: Margins = [ %d %d ]\n", header
->Margins
[0],
152 fprintf(stderr
, "DEBUG: ManualFeed = %d\n", header
->ManualFeed
);
153 fprintf(stderr
, "DEBUG: MediaPosition = %d\n", header
->MediaPosition
);
154 fprintf(stderr
, "DEBUG: MediaWeight = %d\n", header
->MediaWeight
);
155 fprintf(stderr
, "DEBUG: MirrorPrint = %d\n", header
->MirrorPrint
);
156 fprintf(stderr
, "DEBUG: NegativePrint = %d\n", header
->NegativePrint
);
157 fprintf(stderr
, "DEBUG: NumCopies = %d\n", header
->NumCopies
);
158 fprintf(stderr
, "DEBUG: Orientation = %d\n", header
->Orientation
);
159 fprintf(stderr
, "DEBUG: OutputFaceUp = %d\n", header
->OutputFaceUp
);
160 fprintf(stderr
, "DEBUG: PageSize = [ %d %d ]\n", header
->PageSize
[0],
161 header
->PageSize
[1]);
162 fprintf(stderr
, "DEBUG: Separations = %d\n", header
->Separations
);
163 fprintf(stderr
, "DEBUG: TraySwitch = %d\n", header
->TraySwitch
);
164 fprintf(stderr
, "DEBUG: Tumble = %d\n", header
->Tumble
);
165 fprintf(stderr
, "DEBUG: cupsWidth = %d\n", header
->cupsWidth
);
166 fprintf(stderr
, "DEBUG: cupsHeight = %d\n", header
->cupsHeight
);
167 fprintf(stderr
, "DEBUG: cupsMediaType = %d\n", header
->cupsMediaType
);
168 fprintf(stderr
, "DEBUG: cupsBitsPerColor = %d\n", header
->cupsBitsPerColor
);
169 fprintf(stderr
, "DEBUG: cupsBitsPerPixel = %d\n", header
->cupsBitsPerPixel
);
170 fprintf(stderr
, "DEBUG: cupsBytesPerLine = %d\n", header
->cupsBytesPerLine
);
171 fprintf(stderr
, "DEBUG: cupsColorOrder = %d\n", header
->cupsColorOrder
);
172 fprintf(stderr
, "DEBUG: cupsColorSpace = %d\n", header
->cupsColorSpace
);
173 fprintf(stderr
, "DEBUG: cupsCompression = %d\n", header
->cupsCompression
);
176 * Setup printer/job attributes...
179 Duplex
= header
->Duplex
;
180 ColorBits
= header
->cupsBitsPerColor
;
182 if ((!Duplex
|| (Page
& 1)) && header
->MediaPosition
)
183 printf("\033&l%dH", /* Set media position */
184 header
->MediaPosition
);
186 if (Duplex
&& ppd
&& ppd
->model_number
== 2)
189 * Handle duplexing on new DeskJet printers...
192 printf("\033&l-2H"); /* Load media */
195 printf("\033&l2S"); /* Set duplex mode */
198 if (!Duplex
|| (Page
& 1) || (ppd
&& ppd
->model_number
== 2))
201 * Set the media size...
204 printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
205 printf("\033&l0O"); /* Set portrait orientation */
207 switch (header
->PageSize
[1])
209 case 540 : /* Monarch Envelope */
210 printf("\033&l80A"); /* Set page size */
213 case 624 : /* DL Envelope */
214 printf("\033&l90A"); /* Set page size */
217 case 649 : /* C5 Envelope */
218 printf("\033&l91A"); /* Set page size */
221 case 684 : /* COM-10 Envelope */
222 printf("\033&l81A"); /* Set page size */
225 case 709 : /* B5 Envelope */
226 printf("\033&l100A"); /* Set page size */
229 case 756 : /* Executive */
230 printf("\033&l1A"); /* Set page size */
233 case 792 : /* Letter */
234 printf("\033&l2A"); /* Set page size */
238 printf("\033&l26A"); /* Set page size */
241 case 1008 : /* Legal */
242 printf("\033&l3A"); /* Set page size */
246 printf("\033&l27A"); /* Set page size */
249 case 1224 : /* Tabloid */
250 printf("\033&l6A"); /* Set page size */
254 printf("\033&l%dP", /* Set page length */
255 header
->PageSize
[1] / 12);
256 printf("\033&l0E"); /* Set top margin to 0 */
259 if (!Duplex
|| (Page
& 1))
262 * Set other job options...
265 printf("\033&l%dX", header
->NumCopies
); /* Set number copies */
267 if (header
->cupsMediaType
&&
268 (!ppd
|| ppd
->model_number
!= 2 || header
->HWResolution
[0] == 600))
269 printf("\033&l%dM", /* Set media type */
270 header
->cupsMediaType
);
272 if (!ppd
|| ppd
->model_number
!= 2)
275 printf("\033&l%dS", /* Set duplex mode */
276 header
->Duplex
+ header
->Tumble
);
278 printf("\033&l0L"); /* Turn off perforation skip */
281 else if (!ppd
|| ppd
->model_number
!= 2)
282 printf("\033&a2G"); /* Set back side */
285 * Set graphics mode...
288 if (ppd
->model_number
== 2)
291 * Figure out the number of color planes...
294 if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
300 * Set the resolution and top-of-form...
303 printf("\033&u%dD", header
->HWResolution
[0]);
305 printf("\033&l0e0L"); /* Reset top and don't skip */
306 printf("\033*p0Y\033*p0X"); /* Set top of form */
309 * Send 26-byte configure image data command with horizontal and
310 * vertical resolutions as well as a color count...
314 putchar(2); /* Format 2 */
315 putchar(NumPlanes
); /* Output planes */
317 putchar(header
->HWResolution
[0] >> 8); /* Black resolution */
318 putchar(header
->HWResolution
[0]);
319 putchar(header
->HWResolution
[1] >> 8);
320 putchar(header
->HWResolution
[1]);
322 putchar(1 << ColorBits
); /* # of black levels */
324 putchar(header
->HWResolution
[0] >> 8); /* Cyan resolution */
325 putchar(header
->HWResolution
[0]);
326 putchar(header
->HWResolution
[1] >> 8);
327 putchar(header
->HWResolution
[1]);
329 putchar(1 << ColorBits
); /* # of cyan levels */
331 putchar(header
->HWResolution
[0] >> 8); /* Magenta resolution */
332 putchar(header
->HWResolution
[0]);
333 putchar(header
->HWResolution
[1] >> 8);
334 putchar(header
->HWResolution
[1]);
336 putchar(1 << ColorBits
); /* # of magenta levels */
338 putchar(header
->HWResolution
[0] >> 8); /* Yellow resolution */
339 putchar(header
->HWResolution
[0]);
340 putchar(header
->HWResolution
[1] >> 8);
341 putchar(header
->HWResolution
[1]);
343 putchar(1 << ColorBits
); /* # of yellow levels */
345 printf("\033&l0H"); /* Set media position */
349 printf("\033*t%dR", header
->HWResolution
[0]);
352 if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
355 printf("\033*r-4U"); /* Set KCMY graphics */
357 else if (header
->cupsColorSpace
== CUPS_CSPACE_CMY
)
360 printf("\033*r-3U"); /* Set CMY graphics */
363 NumPlanes
= 1; /* Black&white graphics */
366 * Set size and position of graphics...
369 printf("\033*r%dS", header
->cupsWidth
); /* Set width */
370 printf("\033*r%dT", header
->cupsHeight
); /* Set height */
372 printf("\033&a0H"); /* Set horizontal position */
375 printf("\033&a%.0fV", /* Set vertical position */
376 10.0 * (ppd
->sizes
[0].length
- ppd
->sizes
[0].top
));
378 printf("\033&a0V"); /* Set top-of-page */
381 printf("\033*r1A"); /* Start graphics */
383 if (header
->cupsCompression
)
384 printf("\033*b%dM", /* Set compression */
385 header
->cupsCompression
);
387 Feed
= 0; /* No blank lines yet */
390 * Allocate memory for a line of graphics...
393 Planes
[0] = malloc(header
->cupsBytesPerLine
);
394 for (plane
= 1; plane
< NumPlanes
; plane
++)
395 Planes
[plane
] = Planes
[0] + plane
* header
->cupsBytesPerLine
/ NumPlanes
;
398 BitBuffer
= malloc(ColorBits
* ((header
->cupsWidth
+ 7) / 8));
402 if (header
->cupsCompression
)
403 CompBuffer
= malloc(header
->cupsBytesPerLine
* 2);
410 * 'EndPage()' - Finish a page of graphics.
416 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
417 struct sigaction action
; /* Actions for POSIX signals */
418 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
422 * Eject the current page...
427 printf("\033*rC"); /* End color GFX */
429 if (!(Duplex
&& (Page
& 1)))
430 printf("\033&l0H"); /* Eject current page */
434 printf("\033*r0B"); /* End GFX */
436 if (!(Duplex
&& (Page
& 1)))
437 printf("\014"); /* Eject current page */
443 * Unregister the signal handler...
446 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
447 sigset(SIGTERM
, SIG_IGN
);
448 #elif defined(HAVE_SIGACTION)
449 memset(&action
, 0, sizeof(action
));
451 sigemptyset(&action
.sa_mask
);
452 action
.sa_handler
= SIG_IGN
;
453 sigaction(SIGTERM
, &action
, NULL
);
455 signal(SIGTERM
, SIG_IGN
);
456 #endif /* HAVE_SIGSET */
473 * 'Shutdown()' - Shutdown the printer.
480 * Send a PCL reset sequence.
489 * 'CancelJob()' - Cancel the current job...
493 CancelJob(int sig
) /* I - Signal */
495 int i
; /* Looping var */
501 * Send out lots of NUL bytes to clear out any pending raster data...
504 for (i
= 0; i
< 600; i
++)
508 * End the current page and exit...
519 * 'CompressData()' - Compress a line of graphics.
523 CompressData(unsigned char *line
, /* I - Data to compress */
524 int length
, /* I - Number of bytes */
525 int plane
, /* I - Color plane */
526 int type
) /* I - Type of compression */
528 unsigned char *line_ptr
, /* Current byte pointer */
529 *line_end
, /* End-of-line byte pointer */
530 *comp_ptr
, /* Pointer into compression buffer */
531 *start
; /* Start of compression sequence */
532 int count
; /* Count of bytes for output */
539 * Do no compression...
543 line_end
= line
+ length
;
548 * Do run-length encoding...
551 line_end
= line
+ length
;
552 for (line_ptr
= line
, comp_ptr
= CompBuffer
;
554 comp_ptr
+= 2, line_ptr
+= count
)
557 (line_ptr
+ count
) < line_end
&&
558 line_ptr
[0] == line_ptr
[count
] &&
562 comp_ptr
[0] = count
- 1;
563 comp_ptr
[1] = line_ptr
[0];
566 line_ptr
= CompBuffer
;
572 * Do TIFF pack-bits encoding...
576 line_end
= line
+ length
;
577 comp_ptr
= CompBuffer
;
579 while (line_ptr
< line_end
)
581 if ((line_ptr
+ 1) >= line_end
)
584 * Single byte on the end...
588 *comp_ptr
++ = *line_ptr
++;
590 else if (line_ptr
[0] == line_ptr
[1])
593 * Repeated sequence...
599 while (line_ptr
< (line_end
- 1) &&
600 line_ptr
[0] == line_ptr
[1] &&
607 *comp_ptr
++ = 257 - count
;
608 *comp_ptr
++ = *line_ptr
++;
613 * Non-repeated sequence...
620 while (line_ptr
< (line_end
- 1) &&
621 line_ptr
[0] != line_ptr
[1] &&
628 *comp_ptr
++ = count
- 1;
630 memcpy(comp_ptr
, start
, count
);
635 line_ptr
= CompBuffer
;
641 * Set the length of the data and write a raster plane...
644 printf("\033*b%d%c", (int)(line_end
- line_ptr
), plane
);
645 fwrite(line_ptr
, line_end
- line_ptr
, 1, stdout
);
650 * 'OutputLine()' - Output a line of graphics.
654 OutputLine(cups_page_header_t
*header
) /* I - Page header */
656 int plane
, /* Current plane */
657 bytes
, /* Bytes to write */
658 count
; /* Bytes to convert */
659 unsigned char bit
, /* Current plane data */
660 bit0
, /* Current low bit data */
661 bit1
, /* Current high bit data */
662 *plane_ptr
, /* Pointer into Planes */
663 *bit_ptr
; /* Pointer into BitBuffer */
667 * Output whitespace as needed...
672 printf("\033*b%dY", Feed
);
677 * Write bitmap data as needed...
680 bytes
= (header
->cupsWidth
+ 7) / 8;
682 for (plane
= 0; plane
< NumPlanes
; plane
++)
689 CompressData(Planes
[plane
], bytes
, plane
< (NumPlanes
- 1) ? 'V' : 'W',
690 header
->cupsCompression
);
695 * Separate low and high bit data into separate buffers.
698 for (count
= header
->cupsBytesPerLine
/ NumPlanes
,
699 plane_ptr
= Planes
[plane
], bit_ptr
= BitBuffer
;
701 count
-= 2, plane_ptr
+= 2, bit_ptr
++)
705 bit0
= ((bit
& 64) << 1) | ((bit
& 16) << 2) | ((bit
& 4) << 3) | ((bit
& 1) << 4);
706 bit1
= (bit
& 128) | ((bit
& 32) << 1) | ((bit
& 8) << 2) | ((bit
& 2) << 3);
712 bit0
|= (bit
& 1) | ((bit
& 4) >> 1) | ((bit
& 16) >> 2) | ((bit
& 64) >> 3);
713 bit1
|= ((bit
& 2) >> 1) | ((bit
& 8) >> 2) | ((bit
& 32) >> 3) | ((bit
& 128) >> 4);
717 bit_ptr
[bytes
] = bit1
;
721 * Send low and high bits...
724 CompressData(BitBuffer
, bytes
, 'V', header
->cupsCompression
);
725 CompressData(BitBuffer
+ bytes
, bytes
, plane
< (NumPlanes
- 1) ? 'V' : 'W',
726 header
->cupsCompression
);
734 * 'main()' - Main entry and processing of driver.
737 int /* O - Exit status */
738 main(int argc
, /* I - Number of command-line arguments */
739 char *argv
[]) /* I - Command-line arguments */
741 int fd
; /* File descriptor */
742 cups_raster_t
*ras
; /* Raster stream for printing */
743 cups_page_header_t header
; /* Page header from file */
744 int y
; /* Current line */
745 ppd_file_t
*ppd
; /* PPD file */
749 * Make sure status messages are not buffered...
752 setbuf(stderr
, NULL
);
755 * Check command-line...
758 if (argc
< 6 || argc
> 7)
761 * We don't have the correct number of arguments; write an error message
765 fputs("ERROR: rastertopcl job-id user title copies options [file]\n", stderr
);
770 * Open the page stream...
775 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
777 perror("ERROR: Unable to open raster file - ");
785 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
788 * Initialize the print device...
791 ppd
= ppdOpenFile(getenv("PPD"));
796 * Process pages as needed...
801 while (cupsRasterReadHeader(ras
, &header
))
804 * Write a status message with the page number and number of copies.
809 fprintf(stderr
, "PAGE: %d %d\n", Page
, header
.NumCopies
);
815 StartPage(ppd
, &header
);
818 * Loop for each line on the page...
821 for (y
= 0; y
< header
.cupsHeight
; y
++)
824 * Let the user know how far we have progressed...
828 fprintf(stderr
, "INFO: Printing page %d, %d%% complete...\n", Page
,
829 100 * y
/ header
.cupsHeight
);
832 * Read a line of graphics...
835 if (cupsRasterReadPixels(ras
, Planes
[0], header
.cupsBytesPerLine
) < 1)
839 * See if the line is blank; if not, write it to the printer...
843 memcmp(Planes
[0], Planes
[0] + 1, header
.cupsBytesPerLine
- 1))
857 * Shutdown the printer...
866 * Close the raster stream...
869 cupsRasterClose(ras
);
874 * If no pages were printed, send an error message...
878 fputs("ERROR: No pages found!\n", stderr
);
880 fputs("INFO: " CUPS_SVERSION
" is ready to print.\n", stderr
);
887 * End of "$Id: rastertohp.c 4493 2005-02-18 02:09:53Z mike $".