]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/rastertohp.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / filter / rastertohp.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * Hewlett-Packard Page Control Language filter for CUPS.
ef416fc2 3 *
50752acb 4 * Copyright 2007-2015 by Apple Inc.
7e86f2f6 5 * Copyright 1993-2007 by Easy Software Products.
ef416fc2 6 *
e3101897 7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
ef416fc2 8 */
9
10/*
11 * Include necessary headers...
12 */
13
14#include <cups/cups.h>
aaf19ab0 15#include <cups/ppd.h>
71e16022
MS
16#include <cups/string-private.h>
17#include <cups/language-private.h>
ac884b6a 18#include <cups/raster.h>
ef416fc2 19#include <unistd.h>
20#include <fcntl.h>
21#include <signal.h>
22
23
24/*
25 * Globals...
26 */
27
28unsigned char *Planes[4], /* Output buffers */
29 *CompBuffer, /* Compression buffer */
30 *BitBuffer; /* Buffer for output bits */
7e86f2f6 31unsigned NumPlanes, /* Number of color planes */
ef416fc2 32 ColorBits, /* Number of bits per color */
7e86f2f6
MS
33 Feed; /* Number of lines to skip */
34int Duplex, /* Current duplex mode */
839a51c8
MS
35 Page, /* Current page number */
36 Canceled; /* Has the current job been canceled? */
ef416fc2 37
38
39/*
40 * Prototypes...
41 */
42
43void Setup(void);
839a51c8 44void StartPage(ppd_file_t *ppd, cups_page_header2_t *header);
ef416fc2 45void EndPage(void);
46void Shutdown(void);
47
48void CancelJob(int sig);
7e86f2f6 49void CompressData(unsigned char *line, unsigned length, unsigned plane, unsigned type);
839a51c8 50void OutputLine(cups_page_header2_t *header);
ef416fc2 51
52
53/*
54 * 'Setup()' - Prepare the printer for printing.
55 */
56
57void
58Setup(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
73void
74StartPage(ppd_file_t *ppd, /* I - PPD file */
839a51c8 75 cups_page_header2_t *header) /* I - Page header */
ef416fc2 76{
7e86f2f6 77 unsigned plane; /* Looping var */
ef416fc2 78
79
ef416fc2 80 /*
81 * Show page device dictionary...
82 */
83
84 fprintf(stderr, "DEBUG: StartPage...\n");
ef416fc2 85 fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
992d9918
MS
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]);
ef416fc2 89 fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
90 fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
ef416fc2 91 fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
92 fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
992d9918 93 fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0], header->PageSize[1]);
ef416fc2 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
ee571f26
MS
142 case 595 : /* A5 */
143 printf("\033&l25A"); /* Set page size */
144 break;
145
ef416fc2 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 {
238c3832 207 int mode = Duplex ? 1 + header->Tumble != 0 : 0;
ef416fc2 208
238c3832 209 printf("\033&l%dS", mode); /* Set duplex mode */
ef416fc2 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
91c84a35 220 if (ppd && ppd->model_number == 2)
ef416fc2 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 */
7e86f2f6 247 putchar((int)NumPlanes); /* Output planes */
ef416fc2 248
7e86f2f6
MS
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]);
ef416fc2 253 putchar(0);
254 putchar(1 << ColorBits); /* # of black levels */
255
7e86f2f6
MS
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]);
ef416fc2 260 putchar(0);
261 putchar(1 << ColorBits); /* # of cyan levels */
262
7e86f2f6
MS
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]);
ef416fc2 267 putchar(0);
268 putchar(1 << ColorBits); /* # of magenta levels */
269
7e86f2f6
MS
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]);
ef416fc2 274 putchar(0);
275 putchar(1 << ColorBits); /* # of yellow levels */
276
277 printf("\033&l0H"); /* Set media position */
278 }
279 else
280 {
7e86f2f6 281 printf("\033*t%uR", header->HWResolution[0]);
ef416fc2 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
7e86f2f6
MS
301 printf("\033*r%uS", header->cupsWidth); /* Set width */
302 printf("\033*r%uT", header->cupsHeight); /* Set height */
ef416fc2 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)
7e86f2f6 316 printf("\033*b%uM", /* Set compression */
ef416fc2 317 header->cupsCompression);
318
319 Feed = 0; /* No blank lines yet */
320
321 /*
322 * Allocate memory for a line of graphics...
323 */
324
50752acb 325 if ((Planes[0] = malloc(header->cupsBytesPerLine + NumPlanes)) == NULL)
91c84a35 326 {
4d301e69 327 fputs("ERROR: Unable to allocate memory\n", stderr);
91c84a35
MS
328 exit(1);
329 }
330
ef416fc2 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)
50752acb 340 CompBuffer = malloc(header->cupsBytesPerLine * 2 + 2);
ef416fc2 341 else
342 CompBuffer = NULL;
343}
344
345
346/*
347 * 'EndPage()' - Finish a page of graphics.
348 */
349
350void
351EndPage(void)
352{
ef416fc2 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
ef416fc2 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
392void
393Shutdown(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
408void
409CancelJob(int sig) /* I - Signal */
410{
ef416fc2 411 (void)sig;
412
839a51c8 413 Canceled = 1;
ef416fc2 414}
415
416
417/*
418 * 'CompressData()' - Compress a line of graphics.
419 */
420
421void
422CompressData(unsigned char *line, /* I - Data to compress */
7e86f2f6
MS
423 unsigned length, /* I - Number of bytes */
424 unsigned plane, /* I - Color plane */
425 unsigned type) /* I - Type of compression */
ef416fc2 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 */
7e86f2f6 431 unsigned count; /* Count of bytes for output */
ef416fc2 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
7e86f2f6 461 comp_ptr[0] = (unsigned char)(count - 1);
ef416fc2 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
7e86f2f6 506 *comp_ptr++ = (unsigned char)(257 - count);
ef416fc2 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
7e86f2f6 527 *comp_ptr++ = (unsigned char)(count - 1);
ef416fc2 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);
7e86f2f6 544 fwrite(line_ptr, (size_t)(line_end - line_ptr), 1, stdout);
ef416fc2 545}
546
547
548/*
549 * 'OutputLine()' - Output a line of graphics.
550 */
551
552void
839a51c8 553OutputLine(cups_page_header2_t *header) /* I - Page header */
ef416fc2 554{
7e86f2f6 555 unsigned plane, /* Current plane */
ef416fc2 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
7e86f2f6
MS
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));
ef416fc2 606
607 if (count > 1)
608 {
609 bit = plane_ptr[1];
610
7e86f2f6
MS
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));
ef416fc2 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
839a51c8
MS
636int /* O - Exit status */
637main(int argc, /* I - Number of command-line arguments */
638 char *argv[]) /* I - Command-line arguments */
ef416fc2 639{
839a51c8
MS
640 int fd; /* File descriptor */
641 cups_raster_t *ras; /* Raster stream for printing */
642 cups_page_header2_t header; /* Page header from file */
7e86f2f6 643 unsigned y; /* Current line */
839a51c8
MS
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 */
ef416fc2 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
0837b7e8
MS
667 _cupsLangPrintFilter(stderr, "ERROR",
668 _("%s job-id user title copies options [file]"),
669 "rastertohp");
ef416fc2 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 {
0837b7e8 681 _cupsLangPrintError("ERROR", _("Unable to open raster file"));
ef416fc2 682 sleep(1);
683 return (1);
684 }
685 }
686 else
687 fd = 0;
688
689 ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
690
839a51c8
MS
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
ef416fc2 710 /*
711 * Initialize the print device...
712 */
713
714 ppd = ppdOpenFile(getenv("PPD"));
c7017ecc
MS
715 if (!ppd)
716 {
717 ppd_status_t status; /* PPD error */
718 int linenum; /* Line number */
719
0837b7e8
MS
720 _cupsLangPrintFilter(stderr, "ERROR",
721 _("The PPD file could not be opened."));
c7017ecc
MS
722
723 status = ppdLastError(&linenum);
724
725 fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
726
727 return (1);
728 }
ef416fc2 729
730 Setup();
731
732 /*
733 * Process pages as needed...
734 */
735
736 Page = 0;
737
839a51c8 738 while (cupsRasterReadHeader2(ras, &header))
ef416fc2 739 {
740 /*
741 * Write a status message with the page number and number of copies.
742 */
743
839a51c8
MS
744 if (Canceled)
745 break;
746
ef416fc2 747 Page ++;
748
749 fprintf(stderr, "PAGE: %d %d\n", Page, header.NumCopies);
0837b7e8 750 _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), Page);
ef416fc2 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
839a51c8
MS
768 if (Canceled)
769 break;
770
ef416fc2 771 if ((y & 127) == 0)
0837b7e8
MS
772 {
773 _cupsLangPrintFilter(stderr, "INFO",
7e86f2f6 774 _("Printing page %d, %u%% complete."),
0837b7e8 775 Page, 100 * y / header.cupsHeight);
7e86f2f6 776 fprintf(stderr, "ATTR: job-media-progress=%u\n",
0837b7e8
MS
777 100 * y / header.cupsHeight);
778 }
ef416fc2 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
0837b7e8
MS
802 _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), Page);
803
ef416fc2 804 EndPage();
839a51c8
MS
805
806 if (Canceled)
807 break;
ef416fc2 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)
f0ab5bff 832 {
0837b7e8 833 _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
f0ab5bff
MS
834 return (1);
835 }
ef416fc2 836 else
f0ab5bff 837 return (0);
ef416fc2 838}