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