]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/rastertohp.c
Import cups.org releases
[thirdparty/cups.git] / filter / rastertohp.c
1 /*
2 * "$Id$"
3 *
4 * Hewlett-Packard Page Control Language filter for the Common UNIX
5 * Printing System (CUPS).
6 *
7 * Copyright 1993-2001 by Easy Software Products.
8 *
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
14 * at:
15 *
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636-3111 USA
20 *
21 * Voice: (301) 373-9603
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
24 *
25 * Contents:
26 *
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.
35 */
36
37 /*
38 * Include necessary headers...
39 */
40
41 #include <cups/cups.h>
42 #include <cups/string.h>
43 #include "raster.h"
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <signal.h>
48
49
50 /*
51 * Globals...
52 */
53
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 */
62
63
64 /*
65 * Prototypes...
66 */
67
68 void Setup(void);
69 void StartPage(ppd_file_t *ppd, cups_page_header_t *header);
70 void EndPage(void);
71 void Shutdown(void);
72
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);
76
77
78 /*
79 * 'Setup()' - Prepare the printer for printing.
80 */
81
82 void
83 Setup(void)
84 {
85 /*
86 * Send a PCL reset sequence.
87 */
88
89 putchar(0x1b);
90 putchar('E');
91 }
92
93
94 /*
95 * 'StartPage()' - Start a page of graphics.
96 */
97
98 void
99 StartPage(ppd_file_t *ppd, /* I - PPD file */
100 cups_page_header_t *header) /* I - Page header */
101 {
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 */
106
107
108 /*
109 * Register a signal handler to eject the current page if the
110 * job is cancelled.
111 */
112
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));
117
118 sigemptyset(&action.sa_mask);
119 action.sa_handler = CancelJob;
120 sigaction(SIGTERM, &action, NULL);
121 #else
122 signal(SIGTERM, CancelJob);
123 #endif /* HAVE_SIGSET */
124
125 /*
126 * Setup printer/job attributes...
127 */
128
129 Duplex = header->Duplex;
130 ColorBits = header->cupsBitsPerColor;
131
132 if (!Duplex || (Page & 1))
133 {
134 /*
135 * Set the media type, position, and size...
136 */
137
138 printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
139 printf("\033&l0O"); /* Set portrait orientation */
140
141 switch (header->PageSize[1])
142 {
143 case 540 : /* Monarch Envelope */
144 printf("\033&l80A"); /* Set page size */
145 break;
146
147 case 624 : /* DL Envelope */
148 printf("\033&l90A"); /* Set page size */
149 break;
150
151 case 649 : /* C5 Envelope */
152 printf("\033&l91A"); /* Set page size */
153 break;
154
155 case 684 : /* COM-10 Envelope */
156 printf("\033&l81A"); /* Set page size */
157 break;
158
159 case 709 : /* B5 Envelope */
160 printf("\033&l100A"); /* Set page size */
161 break;
162
163 case 756 : /* Executive */
164 printf("\033&l1A"); /* Set page size */
165 break;
166
167 case 792 : /* Letter */
168 printf("\033&l2A"); /* Set page size */
169 break;
170
171 case 842 : /* A4 */
172 printf("\033&l26A"); /* Set page size */
173 break;
174
175 case 1008 : /* Legal */
176 printf("\033&l3A"); /* Set page size */
177 break;
178
179 case 1191 : /* A3 */
180 printf("\033&l27A"); /* Set page size */
181 break;
182
183 case 1224 : /* Tabloid */
184 printf("\033&l6A"); /* Set page size */
185 break;
186 }
187
188 printf("\033&l%dP", /* Set page length */
189 header->PageSize[1] / 12);
190 printf("\033&l0E"); /* Set top margin to 0 */
191
192 printf("\033&l%dX", header->NumCopies); /* Set number copies */
193
194 if (header->MediaPosition)
195 printf("\033&l%dH", /* Set media position */
196 header->MediaPosition);
197
198 if (header->cupsMediaType)
199 printf("\033&l%dM", /* Set media type */
200 header->cupsMediaType);
201
202 if (header->Duplex)
203 printf("\033&l%dS", /* Set duplex mode */
204 header->Duplex + header->Tumble);
205
206 printf("\033&l0L"); /* Turn off perforation skip */
207
208 if (ppd && ppd->model_number == 2)
209 printf("\033&l-2H"); /* Load media */
210 }
211 else
212 printf("\033&a2G"); /* Set back side */
213
214 /*
215 * Set graphics mode...
216 */
217
218 printf("\033*t%dR", header->HWResolution[0]); /* Set resolution */
219
220 if (ppd->model_number == 2)
221 {
222 /*
223 * Figure out the number of color planes...
224 */
225
226 if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
227 NumPlanes = 4;
228 else
229 NumPlanes = 1;
230
231 /*
232 * Send 26-byte configure image data command with horizontal and
233 * vertical resolutions as well as a color count...
234 */
235
236 printf("\033*g26W");
237 putchar(2); /* Format 2 */
238 putchar(NumPlanes); /* Output planes */
239
240 putchar(header->HWResolution[0] >> 8); /* Black resolution */
241 putchar(header->HWResolution[0]);
242 putchar(header->HWResolution[1] >> 8);
243 putchar(header->HWResolution[1]);
244 putchar(0);
245 putchar(1 << ColorBits); /* # of black levels */
246
247 putchar(header->HWResolution[0] >> 8); /* Cyan resolution */
248 putchar(header->HWResolution[0]);
249 putchar(header->HWResolution[1] >> 8);
250 putchar(header->HWResolution[1]);
251 putchar(0);
252 putchar(1 << ColorBits); /* # of cyan levels */
253
254 putchar(header->HWResolution[0] >> 8); /* Magenta resolution */
255 putchar(header->HWResolution[0]);
256 putchar(header->HWResolution[1] >> 8);
257 putchar(header->HWResolution[1]);
258 putchar(0);
259 putchar(1 << ColorBits); /* # of magenta levels */
260
261 putchar(header->HWResolution[0] >> 8); /* Yellow resolution */
262 putchar(header->HWResolution[0]);
263 putchar(header->HWResolution[1] >> 8);
264 putchar(header->HWResolution[1]);
265 putchar(0);
266 putchar(1 << ColorBits); /* # of yellow levels */
267 }
268 else
269 {
270 if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
271 {
272 NumPlanes = 4;
273 printf("\033*r-4U"); /* Set KCMY graphics */
274 }
275 else if (header->cupsColorSpace == CUPS_CSPACE_CMY)
276 {
277 NumPlanes = 3;
278 printf("\033*r-3U"); /* Set CMY graphics */
279 }
280 else
281 NumPlanes = 1; /* Black&white graphics */
282 }
283
284 /*
285 * Set size and position of graphics...
286 */
287
288 printf("\033*r%dS", header->cupsWidth); /* Set width */
289 printf("\033*r%dT", header->cupsHeight); /* Set height */
290
291 printf("\033&a0H"); /* Set horizontal position */
292
293 if (ppd)
294 printf("\033&a%.0fV", /* Set vertical position */
295 10.0 * (ppd->sizes[0].length - ppd->sizes[0].top));
296 else
297 printf("\033&a0V"); /* Set top-of-page */
298
299 printf("\033*r1A"); /* Start graphics */
300
301 if (header->cupsCompression)
302 printf("\033*b%dM", /* Set compression */
303 header->cupsCompression);
304
305 Feed = 0; /* No blank lines yet */
306
307 /*
308 * Allocate memory for a line of graphics...
309 */
310
311 Planes[0] = malloc(header->cupsBytesPerLine);
312 for (plane = 1; plane < NumPlanes; plane ++)
313 Planes[plane] = Planes[0] + plane * header->cupsBytesPerLine / NumPlanes;
314
315 if (ColorBits > 1)
316 BitBuffer = malloc(ColorBits * ((header->cupsWidth + 7) / 8));
317 else
318 BitBuffer = NULL;
319
320 if (header->cupsCompression)
321 CompBuffer = malloc(header->cupsBytesPerLine * 2);
322 else
323 CompBuffer = NULL;
324 }
325
326
327 /*
328 * 'EndPage()' - Finish a page of graphics.
329 */
330
331 void
332 EndPage(void)
333 {
334 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
335 struct sigaction action; /* Actions for POSIX signals */
336 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
337
338
339 /*
340 * Eject the current page...
341 */
342
343 if (NumPlanes > 1)
344 {
345 printf("\033*rC"); /* End color GFX */
346
347 if (!(Duplex && (Page & 1)))
348 printf("\033&l0H"); /* Eject current page */
349 }
350 else
351 {
352 printf("\033*r0B"); /* End GFX */
353
354 if (!(Duplex && (Page & 1)))
355 printf("\014"); /* Eject current page */
356 }
357
358 fflush(stdout);
359
360 /*
361 * Unregister the signal handler...
362 */
363
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));
368
369 sigemptyset(&action.sa_mask);
370 action.sa_handler = SIG_IGN;
371 sigaction(SIGTERM, &action, NULL);
372 #else
373 signal(SIGTERM, SIG_IGN);
374 #endif /* HAVE_SIGSET */
375
376 /*
377 * Free memory...
378 */
379
380 free(Planes[0]);
381
382 if (BitBuffer)
383 free(BitBuffer);
384
385 if (CompBuffer)
386 free(CompBuffer);
387 }
388
389
390 /*
391 * 'Shutdown()' - Shutdown the printer.
392 */
393
394 void
395 Shutdown(void)
396 {
397 /*
398 * Send a PCL reset sequence.
399 */
400
401 putchar(0x1b);
402 putchar('E');
403 }
404
405
406 /*
407 * 'CancelJob()' - Cancel the current job...
408 */
409
410 void
411 CancelJob(int sig) /* I - Signal */
412 {
413 int i; /* Looping var */
414
415
416 (void)sig;
417
418 /*
419 * Send out lots of NUL bytes to clear out any pending raster data...
420 */
421
422 for (i = 0; i < 600; i ++)
423 putchar(0);
424
425 /*
426 * End the current page and exit...
427 */
428
429 EndPage();
430 Shutdown();
431
432 exit(0);
433 }
434
435
436 /*
437 * 'CompressData()' - Compress a line of graphics.
438 */
439
440 void
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 */
445 {
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 */
451
452
453 switch (type)
454 {
455 default :
456 /*
457 * Do no compression...
458 */
459
460 line_ptr = line;
461 line_end = line + length;
462 break;
463
464 case 1 :
465 /*
466 * Do run-length encoding...
467 */
468
469 line_end = line + length;
470 for (line_ptr = line, comp_ptr = CompBuffer;
471 line_ptr < line_end;
472 comp_ptr += 2, line_ptr += count)
473 {
474 for (count = 1;
475 (line_ptr + count) < line_end &&
476 line_ptr[0] == line_ptr[count] &&
477 count < 256;
478 count ++);
479
480 comp_ptr[0] = count - 1;
481 comp_ptr[1] = line_ptr[0];
482 }
483
484 line_ptr = CompBuffer;
485 line_end = comp_ptr;
486 break;
487
488 case 2 :
489 /*
490 * Do TIFF pack-bits encoding...
491 */
492
493 line_ptr = line;
494 line_end = line + length;
495 comp_ptr = CompBuffer;
496
497 while (line_ptr < line_end)
498 {
499 if ((line_ptr + 1) >= line_end)
500 {
501 /*
502 * Single byte on the end...
503 */
504
505 *comp_ptr++ = 0x00;
506 *comp_ptr++ = *line_ptr++;
507 }
508 else if (line_ptr[0] == line_ptr[1])
509 {
510 /*
511 * Repeated sequence...
512 */
513
514 line_ptr ++;
515 count = 2;
516
517 while (line_ptr < (line_end - 1) &&
518 line_ptr[0] == line_ptr[1] &&
519 count < 127)
520 {
521 line_ptr ++;
522 count ++;
523 }
524
525 *comp_ptr++ = 257 - count;
526 *comp_ptr++ = *line_ptr++;
527 }
528 else
529 {
530 /*
531 * Non-repeated sequence...
532 */
533
534 start = line_ptr;
535 line_ptr ++;
536 count = 1;
537
538 while (line_ptr < (line_end - 1) &&
539 line_ptr[0] != line_ptr[1] &&
540 count < 127)
541 {
542 line_ptr ++;
543 count ++;
544 }
545
546 *comp_ptr++ = count - 1;
547
548 memcpy(comp_ptr, start, count);
549 comp_ptr += count;
550 }
551 }
552
553 line_ptr = CompBuffer;
554 line_end = comp_ptr;
555 break;
556 }
557
558 /*
559 * Set the length of the data and write a raster plane...
560 */
561
562 printf("\033*b%d%c", line_end - line_ptr, plane);
563 fwrite(line_ptr, line_end - line_ptr, 1, stdout);
564 }
565
566
567 /*
568 * 'OutputLine()' - Output a line of graphics.
569 */
570
571 void
572 OutputLine(cups_page_header_t *header) /* I - Page header */
573 {
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 */
582
583
584 /*
585 * Output whitespace as needed...
586 */
587
588 if (Feed > 0)
589 {
590 printf("\033*b%dY", Feed);
591 Feed = 0;
592 }
593
594 /*
595 * Write bitmap data as needed...
596 */
597
598 bytes = (header->cupsWidth + 7) / 8;
599
600 for (plane = 0; plane < NumPlanes; plane ++)
601 if (ColorBits == 1)
602 {
603 /*
604 * Send bits as-is...
605 */
606
607 CompressData(Planes[plane], bytes, plane < (NumPlanes - 1) ? 'V' : 'W',
608 header->cupsCompression);
609 }
610 else
611 {
612 /*
613 * Separate low and high bit data into separate buffers.
614 */
615
616 for (count = header->cupsBytesPerLine / NumPlanes,
617 plane_ptr = Planes[plane], bit_ptr = BitBuffer;
618 count > 0;
619 count -= 2, plane_ptr += 2, bit_ptr ++)
620 {
621 bit = plane_ptr[0];
622
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);
625
626 if (count > 1)
627 {
628 bit = plane_ptr[1];
629
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);
632 }
633
634 bit_ptr[0] = bit0;
635 bit_ptr[bytes] = bit1;
636 }
637
638 /*
639 * Send low and high bits...
640 */
641
642 CompressData(BitBuffer, bytes, 'V', header->cupsCompression);
643 CompressData(BitBuffer + bytes, bytes, plane < (NumPlanes - 1) ? 'V' : 'W',
644 header->cupsCompression);
645 }
646
647 fflush(stdout);
648 }
649
650
651 /*
652 * 'main()' - Main entry and processing of driver.
653 */
654
655 int /* O - Exit status */
656 main(int argc, /* I - Number of command-line arguments */
657 char *argv[]) /* I - Command-line arguments */
658 {
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 */
664
665
666 /*
667 * Make sure status messages are not buffered...
668 */
669
670 setbuf(stderr, NULL);
671
672 /*
673 * Check command-line...
674 */
675
676 if (argc < 6 || argc > 7)
677 {
678 /*
679 * We don't have the correct number of arguments; write an error message
680 * and return.
681 */
682
683 fputs("ERROR: rastertopcl job-id user title copies options [file]\n", stderr);
684 return (1);
685 }
686
687 /*
688 * Open the page stream...
689 */
690
691 if (argc == 7)
692 {
693 if ((fd = open(argv[6], O_RDONLY)) == -1)
694 {
695 perror("ERROR: Unable to open raster file - ");
696 sleep(1);
697 return (1);
698 }
699 }
700 else
701 fd = 0;
702
703 ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
704
705 /*
706 * Initialize the print device...
707 */
708
709 ppd = ppdOpenFile(getenv("PPD"));
710
711 Setup();
712
713 /*
714 * Process pages as needed...
715 */
716
717 Page = 0;
718
719 while (cupsRasterReadHeader(ras, &header))
720 {
721 /*
722 * Write a status message with the page number and number of copies.
723 */
724
725 Page ++;
726
727 fprintf(stderr, "PAGE: %d %d\n", Page, header.NumCopies);
728
729 /*
730 * Start the page...
731 */
732
733 StartPage(ppd, &header);
734
735 /*
736 * Loop for each line on the page...
737 */
738
739 for (y = 0; y < header.cupsHeight; y ++)
740 {
741 /*
742 * Let the user know how far we have progressed...
743 */
744
745 if ((y & 127) == 0)
746 fprintf(stderr, "INFO: Printing page %d, %d%% complete...\n", Page,
747 100 * y / header.cupsHeight);
748
749 /*
750 * Read a line of graphics...
751 */
752
753 if (cupsRasterReadPixels(ras, Planes[0], header.cupsBytesPerLine) < 1)
754 break;
755
756 /*
757 * See if the line is blank; if not, write it to the printer...
758 */
759
760 if (Planes[0][0] ||
761 memcmp(Planes[0], Planes[0] + 1, header.cupsBytesPerLine - 1))
762 OutputLine(&header);
763 else
764 Feed ++;
765 }
766
767 /*
768 * Eject the page...
769 */
770
771 EndPage();
772 }
773
774 /*
775 * Shutdown the printer...
776 */
777
778 Shutdown();
779
780 if (ppd)
781 ppdClose(ppd);
782
783 /*
784 * Close the raster stream...
785 */
786
787 cupsRasterClose(ras);
788 if (fd != 0)
789 close(fd);
790
791 /*
792 * If no pages were printed, send an error message...
793 */
794
795 if (Page == 0)
796 fputs("ERROR: No pages found!\n", stderr);
797 else
798 fputs("INFO: " CUPS_SVERSION " is ready to print.\n", stderr);
799
800 return (Page == 0);
801 }
802
803
804 /*
805 * End of "$Id$".
806 */