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