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