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