2 * "$Id: rastertohp.c 6420 2007-03-30 20:00:59Z mike $"
4 * Hewlett-Packard Page Control Language filter for the Common UNIX
5 * Printing System (CUPS).
7 * Copyright 1993-2007 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>
45 #include <cups/i18n.h>
57 unsigned char *Planes
[4], /* Output buffers */
58 *CompBuffer
, /* Compression buffer */
59 *BitBuffer
; /* Buffer for output bits */
60 int NumPlanes
, /* Number of color planes */
61 ColorBits
, /* Number of bits per color */
62 Feed
, /* Number of lines to skip */
63 Duplex
, /* Current duplex mode */
64 Page
; /* Current page number */
72 void StartPage(ppd_file_t
*ppd
, cups_page_header_t
*header
);
76 void CancelJob(int sig
);
77 void CompressData(unsigned char *line
, int length
, int plane
, int type
);
78 void OutputLine(cups_page_header_t
*header
);
82 * 'Setup()' - Prepare the printer for printing.
89 * Send a PCL reset sequence.
98 * 'StartPage()' - Start a page of graphics.
102 StartPage(ppd_file_t
*ppd
, /* I - PPD file */
103 cups_page_header_t
*header
) /* I - Page header */
105 int plane
; /* Looping var */
106 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
107 struct sigaction action
; /* Actions for POSIX signals */
108 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
112 * Register a signal handler to eject the current page if the
116 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
117 sigset(SIGTERM
, CancelJob
);
118 #elif defined(HAVE_SIGACTION)
119 memset(&action
, 0, sizeof(action
));
121 sigemptyset(&action
.sa_mask
);
122 action
.sa_handler
= CancelJob
;
123 sigaction(SIGTERM
, &action
, NULL
);
125 signal(SIGTERM
, CancelJob
);
126 #endif /* HAVE_SIGSET */
129 * Show page device dictionary...
132 fprintf(stderr
, "DEBUG: StartPage...\n");
133 fprintf(stderr
, "DEBUG: MediaClass = \"%s\"\n", header
->MediaClass
);
134 fprintf(stderr
, "DEBUG: MediaColor = \"%s\"\n", header
->MediaColor
);
135 fprintf(stderr
, "DEBUG: MediaType = \"%s\"\n", header
->MediaType
);
136 fprintf(stderr
, "DEBUG: OutputType = \"%s\"\n", header
->OutputType
);
138 fprintf(stderr
, "DEBUG: AdvanceDistance = %d\n", header
->AdvanceDistance
);
139 fprintf(stderr
, "DEBUG: AdvanceMedia = %d\n", header
->AdvanceMedia
);
140 fprintf(stderr
, "DEBUG: Collate = %d\n", header
->Collate
);
141 fprintf(stderr
, "DEBUG: CutMedia = %d\n", header
->CutMedia
);
142 fprintf(stderr
, "DEBUG: Duplex = %d\n", header
->Duplex
);
143 fprintf(stderr
, "DEBUG: HWResolution = [ %d %d ]\n", header
->HWResolution
[0],
144 header
->HWResolution
[1]);
145 fprintf(stderr
, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
146 header
->ImagingBoundingBox
[0], header
->ImagingBoundingBox
[1],
147 header
->ImagingBoundingBox
[2], header
->ImagingBoundingBox
[3]);
148 fprintf(stderr
, "DEBUG: InsertSheet = %d\n", header
->InsertSheet
);
149 fprintf(stderr
, "DEBUG: Jog = %d\n", header
->Jog
);
150 fprintf(stderr
, "DEBUG: LeadingEdge = %d\n", header
->LeadingEdge
);
151 fprintf(stderr
, "DEBUG: Margins = [ %d %d ]\n", header
->Margins
[0],
153 fprintf(stderr
, "DEBUG: ManualFeed = %d\n", header
->ManualFeed
);
154 fprintf(stderr
, "DEBUG: MediaPosition = %d\n", header
->MediaPosition
);
155 fprintf(stderr
, "DEBUG: MediaWeight = %d\n", header
->MediaWeight
);
156 fprintf(stderr
, "DEBUG: MirrorPrint = %d\n", header
->MirrorPrint
);
157 fprintf(stderr
, "DEBUG: NegativePrint = %d\n", header
->NegativePrint
);
158 fprintf(stderr
, "DEBUG: NumCopies = %d\n", header
->NumCopies
);
159 fprintf(stderr
, "DEBUG: Orientation = %d\n", header
->Orientation
);
160 fprintf(stderr
, "DEBUG: OutputFaceUp = %d\n", header
->OutputFaceUp
);
161 fprintf(stderr
, "DEBUG: PageSize = [ %d %d ]\n", header
->PageSize
[0],
162 header
->PageSize
[1]);
163 fprintf(stderr
, "DEBUG: Separations = %d\n", header
->Separations
);
164 fprintf(stderr
, "DEBUG: TraySwitch = %d\n", header
->TraySwitch
);
165 fprintf(stderr
, "DEBUG: Tumble = %d\n", header
->Tumble
);
166 fprintf(stderr
, "DEBUG: cupsWidth = %d\n", header
->cupsWidth
);
167 fprintf(stderr
, "DEBUG: cupsHeight = %d\n", header
->cupsHeight
);
168 fprintf(stderr
, "DEBUG: cupsMediaType = %d\n", header
->cupsMediaType
);
169 fprintf(stderr
, "DEBUG: cupsBitsPerColor = %d\n", header
->cupsBitsPerColor
);
170 fprintf(stderr
, "DEBUG: cupsBitsPerPixel = %d\n", header
->cupsBitsPerPixel
);
171 fprintf(stderr
, "DEBUG: cupsBytesPerLine = %d\n", header
->cupsBytesPerLine
);
172 fprintf(stderr
, "DEBUG: cupsColorOrder = %d\n", header
->cupsColorOrder
);
173 fprintf(stderr
, "DEBUG: cupsColorSpace = %d\n", header
->cupsColorSpace
);
174 fprintf(stderr
, "DEBUG: cupsCompression = %d\n", header
->cupsCompression
);
177 * Setup printer/job attributes...
180 Duplex
= header
->Duplex
;
181 ColorBits
= header
->cupsBitsPerColor
;
183 if ((!Duplex
|| (Page
& 1)) && header
->MediaPosition
)
184 printf("\033&l%dH", /* Set media position */
185 header
->MediaPosition
);
187 if (Duplex
&& ppd
&& ppd
->model_number
== 2)
190 * Handle duplexing on new DeskJet printers...
193 printf("\033&l-2H"); /* Load media */
196 printf("\033&l2S"); /* Set duplex mode */
199 if (!Duplex
|| (Page
& 1) || (ppd
&& ppd
->model_number
== 2))
202 * Set the media size...
205 printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
206 printf("\033&l0O"); /* Set portrait orientation */
208 switch (header
->PageSize
[1])
210 case 540 : /* Monarch Envelope */
211 printf("\033&l80A"); /* Set page size */
214 case 624 : /* DL Envelope */
215 printf("\033&l90A"); /* Set page size */
218 case 649 : /* C5 Envelope */
219 printf("\033&l91A"); /* Set page size */
222 case 684 : /* COM-10 Envelope */
223 printf("\033&l81A"); /* Set page size */
226 case 709 : /* B5 Envelope */
227 printf("\033&l100A"); /* Set page size */
230 case 756 : /* Executive */
231 printf("\033&l1A"); /* Set page size */
234 case 792 : /* Letter */
235 printf("\033&l2A"); /* Set page size */
239 printf("\033&l26A"); /* Set page size */
242 case 1008 : /* Legal */
243 printf("\033&l3A"); /* Set page size */
247 printf("\033&l27A"); /* Set page size */
250 case 1224 : /* Tabloid */
251 printf("\033&l6A"); /* Set page size */
255 printf("\033&l%dP", /* Set page length */
256 header
->PageSize
[1] / 12);
257 printf("\033&l0E"); /* Set top margin to 0 */
260 if (!Duplex
|| (Page
& 1))
263 * Set other job options...
266 printf("\033&l%dX", header
->NumCopies
); /* Set number copies */
268 if (header
->cupsMediaType
&&
269 (!ppd
|| ppd
->model_number
!= 2 || header
->HWResolution
[0] == 600))
270 printf("\033&l%dM", /* Set media type */
271 header
->cupsMediaType
);
273 if (!ppd
|| ppd
->model_number
!= 2)
276 printf("\033&l%dS", /* Set duplex mode */
277 header
->Duplex
+ header
->Tumble
);
279 printf("\033&l0L"); /* Turn off perforation skip */
282 else if (!ppd
|| ppd
->model_number
!= 2)
283 printf("\033&a2G"); /* Set back side */
286 * Set graphics mode...
289 if (ppd
->model_number
== 2)
292 * Figure out the number of color planes...
295 if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
301 * Set the resolution and top-of-form...
304 printf("\033&u%dD", header
->HWResolution
[0]);
306 printf("\033&l0e0L"); /* Reset top and don't skip */
307 printf("\033*p0Y\033*p0X"); /* Set top of form */
310 * Send 26-byte configure image data command with horizontal and
311 * vertical resolutions as well as a color count...
315 putchar(2); /* Format 2 */
316 putchar(NumPlanes
); /* Output planes */
318 putchar(header
->HWResolution
[0] >> 8); /* Black resolution */
319 putchar(header
->HWResolution
[0]);
320 putchar(header
->HWResolution
[1] >> 8);
321 putchar(header
->HWResolution
[1]);
323 putchar(1 << ColorBits
); /* # of black levels */
325 putchar(header
->HWResolution
[0] >> 8); /* Cyan resolution */
326 putchar(header
->HWResolution
[0]);
327 putchar(header
->HWResolution
[1] >> 8);
328 putchar(header
->HWResolution
[1]);
330 putchar(1 << ColorBits
); /* # of cyan levels */
332 putchar(header
->HWResolution
[0] >> 8); /* Magenta resolution */
333 putchar(header
->HWResolution
[0]);
334 putchar(header
->HWResolution
[1] >> 8);
335 putchar(header
->HWResolution
[1]);
337 putchar(1 << ColorBits
); /* # of magenta levels */
339 putchar(header
->HWResolution
[0] >> 8); /* Yellow resolution */
340 putchar(header
->HWResolution
[0]);
341 putchar(header
->HWResolution
[1] >> 8);
342 putchar(header
->HWResolution
[1]);
344 putchar(1 << ColorBits
); /* # of yellow levels */
346 printf("\033&l0H"); /* Set media position */
350 printf("\033*t%dR", header
->HWResolution
[0]);
353 if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
356 printf("\033*r-4U"); /* Set KCMY graphics */
358 else if (header
->cupsColorSpace
== CUPS_CSPACE_CMY
)
361 printf("\033*r-3U"); /* Set CMY graphics */
364 NumPlanes
= 1; /* Black&white graphics */
367 * Set size and position of graphics...
370 printf("\033*r%dS", header
->cupsWidth
); /* Set width */
371 printf("\033*r%dT", header
->cupsHeight
); /* Set height */
373 printf("\033&a0H"); /* Set horizontal position */
376 printf("\033&a%.0fV", /* Set vertical position */
377 10.0 * (ppd
->sizes
[0].length
- ppd
->sizes
[0].top
));
379 printf("\033&a0V"); /* Set top-of-page */
382 printf("\033*r1A"); /* Start graphics */
384 if (header
->cupsCompression
)
385 printf("\033*b%dM", /* Set compression */
386 header
->cupsCompression
);
388 Feed
= 0; /* No blank lines yet */
391 * Allocate memory for a line of graphics...
394 Planes
[0] = malloc(header
->cupsBytesPerLine
);
395 for (plane
= 1; plane
< NumPlanes
; plane
++)
396 Planes
[plane
] = Planes
[0] + plane
* header
->cupsBytesPerLine
/ NumPlanes
;
399 BitBuffer
= malloc(ColorBits
* ((header
->cupsWidth
+ 7) / 8));
403 if (header
->cupsCompression
)
404 CompBuffer
= malloc(header
->cupsBytesPerLine
* 2);
411 * 'EndPage()' - Finish a page of graphics.
417 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
418 struct sigaction action
; /* Actions for POSIX signals */
419 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
423 * Eject the current page...
428 printf("\033*rC"); /* End color GFX */
430 if (!(Duplex
&& (Page
& 1)))
431 printf("\033&l0H"); /* Eject current page */
435 printf("\033*r0B"); /* End GFX */
437 if (!(Duplex
&& (Page
& 1)))
438 printf("\014"); /* Eject current page */
444 * Unregister the signal handler...
447 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
448 sigset(SIGTERM
, SIG_IGN
);
449 #elif defined(HAVE_SIGACTION)
450 memset(&action
, 0, sizeof(action
));
452 sigemptyset(&action
.sa_mask
);
453 action
.sa_handler
= SIG_IGN
;
454 sigaction(SIGTERM
, &action
, NULL
);
456 signal(SIGTERM
, SIG_IGN
);
457 #endif /* HAVE_SIGSET */
474 * 'Shutdown()' - Shutdown the printer.
481 * Send a PCL reset sequence.
490 * 'CancelJob()' - Cancel the current job...
494 CancelJob(int sig
) /* I - Signal */
496 int i
; /* Looping var */
502 * Send out lots of NUL bytes to clear out any pending raster data...
505 for (i
= 0; i
< 600; i
++)
509 * End the current page and exit...
520 * 'CompressData()' - Compress a line of graphics.
524 CompressData(unsigned char *line
, /* I - Data to compress */
525 int length
, /* I - Number of bytes */
526 int plane
, /* I - Color plane */
527 int type
) /* I - Type of compression */
529 unsigned char *line_ptr
, /* Current byte pointer */
530 *line_end
, /* End-of-line byte pointer */
531 *comp_ptr
, /* Pointer into compression buffer */
532 *start
; /* Start of compression sequence */
533 int count
; /* Count of bytes for output */
540 * Do no compression...
544 line_end
= line
+ length
;
549 * Do run-length encoding...
552 line_end
= line
+ length
;
553 for (line_ptr
= line
, comp_ptr
= CompBuffer
;
555 comp_ptr
+= 2, line_ptr
+= count
)
558 (line_ptr
+ count
) < line_end
&&
559 line_ptr
[0] == line_ptr
[count
] &&
563 comp_ptr
[0] = count
- 1;
564 comp_ptr
[1] = line_ptr
[0];
567 line_ptr
= CompBuffer
;
573 * Do TIFF pack-bits encoding...
577 line_end
= line
+ length
;
578 comp_ptr
= CompBuffer
;
580 while (line_ptr
< line_end
)
582 if ((line_ptr
+ 1) >= line_end
)
585 * Single byte on the end...
589 *comp_ptr
++ = *line_ptr
++;
591 else if (line_ptr
[0] == line_ptr
[1])
594 * Repeated sequence...
600 while (line_ptr
< (line_end
- 1) &&
601 line_ptr
[0] == line_ptr
[1] &&
608 *comp_ptr
++ = 257 - count
;
609 *comp_ptr
++ = *line_ptr
++;
614 * Non-repeated sequence...
621 while (line_ptr
< (line_end
- 1) &&
622 line_ptr
[0] != line_ptr
[1] &&
629 *comp_ptr
++ = count
- 1;
631 memcpy(comp_ptr
, start
, count
);
636 line_ptr
= CompBuffer
;
642 * Set the length of the data and write a raster plane...
645 printf("\033*b%d%c", (int)(line_end
- line_ptr
), plane
);
646 fwrite(line_ptr
, line_end
- line_ptr
, 1, stdout
);
651 * 'OutputLine()' - Output a line of graphics.
655 OutputLine(cups_page_header_t
*header
) /* I - Page header */
657 int plane
, /* Current plane */
658 bytes
, /* Bytes to write */
659 count
; /* Bytes to convert */
660 unsigned char bit
, /* Current plane data */
661 bit0
, /* Current low bit data */
662 bit1
, /* Current high bit data */
663 *plane_ptr
, /* Pointer into Planes */
664 *bit_ptr
; /* Pointer into BitBuffer */
668 * Output whitespace as needed...
673 printf("\033*b%dY", Feed
);
678 * Write bitmap data as needed...
681 bytes
= (header
->cupsWidth
+ 7) / 8;
683 for (plane
= 0; plane
< NumPlanes
; plane
++)
690 CompressData(Planes
[plane
], bytes
, plane
< (NumPlanes
- 1) ? 'V' : 'W',
691 header
->cupsCompression
);
696 * Separate low and high bit data into separate buffers.
699 for (count
= header
->cupsBytesPerLine
/ NumPlanes
,
700 plane_ptr
= Planes
[plane
], bit_ptr
= BitBuffer
;
702 count
-= 2, plane_ptr
+= 2, bit_ptr
++)
706 bit0
= ((bit
& 64) << 1) | ((bit
& 16) << 2) | ((bit
& 4) << 3) | ((bit
& 1) << 4);
707 bit1
= (bit
& 128) | ((bit
& 32) << 1) | ((bit
& 8) << 2) | ((bit
& 2) << 3);
713 bit0
|= (bit
& 1) | ((bit
& 4) >> 1) | ((bit
& 16) >> 2) | ((bit
& 64) >> 3);
714 bit1
|= ((bit
& 2) >> 1) | ((bit
& 8) >> 2) | ((bit
& 32) >> 3) | ((bit
& 128) >> 4);
718 bit_ptr
[bytes
] = bit1
;
722 * Send low and high bits...
725 CompressData(BitBuffer
, bytes
, 'V', header
->cupsCompression
);
726 CompressData(BitBuffer
+ bytes
, bytes
, plane
< (NumPlanes
- 1) ? 'V' : 'W',
727 header
->cupsCompression
);
735 * 'main()' - Main entry and processing of driver.
738 int /* O - Exit status */
739 main(int argc
, /* I - Number of command-line arguments */
740 char *argv
[]) /* I - Command-line arguments */
742 int fd
; /* File descriptor */
743 cups_raster_t
*ras
; /* Raster stream for printing */
744 cups_page_header_t header
; /* Page header from file */
745 int y
; /* Current line */
746 ppd_file_t
*ppd
; /* PPD file */
750 * Make sure status messages are not buffered...
753 setbuf(stderr
, NULL
);
756 * Check command-line...
759 if (argc
< 6 || argc
> 7)
762 * We don't have the correct number of arguments; write an error message
766 fprintf(stderr
, _("Usage: %s job-id user title copies options [file]\n"),
772 * Open the page stream...
777 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
779 perror("ERROR: Unable to open raster file - ");
787 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
790 * Initialize the print device...
793 ppd
= ppdOpenFile(getenv("PPD"));
798 * Process pages as needed...
803 while (cupsRasterReadHeader(ras
, &header
))
806 * Write a status message with the page number and number of copies.
811 fprintf(stderr
, "PAGE: %d %d\n", Page
, header
.NumCopies
);
817 StartPage(ppd
, &header
);
820 * Loop for each line on the page...
823 for (y
= 0; y
< header
.cupsHeight
; y
++)
826 * Let the user know how far we have progressed...
830 fprintf(stderr
, _("INFO: Printing page %d, %d%% complete...\n"), Page
,
831 100 * y
/ header
.cupsHeight
);
834 * Read a line of graphics...
837 if (cupsRasterReadPixels(ras
, Planes
[0], header
.cupsBytesPerLine
) < 1)
841 * See if the line is blank; if not, write it to the printer...
845 memcmp(Planes
[0], Planes
[0] + 1, header
.cupsBytesPerLine
- 1))
859 * Shutdown the printer...
868 * Close the raster stream...
871 cupsRasterClose(ras
);
876 * If no pages were printed, send an error message...
880 fputs(_("ERROR: No pages found!\n"), stderr
);
882 fputs(_("INFO: Ready to print.\n"), stderr
);
889 * End of "$Id: rastertohp.c 6420 2007-03-30 20:00:59Z mike $".