• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * EPSON ESC/P and ESC/P2 filter for CUPS.
3  *
4  * Copyright © 2020-2024 by OpenPrinting.
5  * Copyright 2007-2018 by Apple Inc.
6  * Copyright 1993-2007 by Easy Software Products.
7  *
8  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
9  * information.
10  */
11 
12 /*
13  * Include necessary headers...
14  */
15 
16 #include <cups/cups.h>
17 #include <cups/ppd.h>
18 #include <cups/string-private.h>
19 #include <cups/language-private.h>
20 #include <cups/raster.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <signal.h>
24 
25 
26 /*
27  * Model numbers...
28  */
29 
30 #define EPSON_9PIN	0
31 #define EPSON_24PIN	1
32 #define EPSON_COLOR	2
33 #define EPSON_PHOTO	3
34 #define EPSON_ICOLOR	4
35 #define EPSON_IPHOTO	5
36 
37 
38 /*
39  * Macros...
40  */
41 
42 #define pwrite(s,n) fwrite((s), 1, (n), stdout)
43 
44 
45 /*
46  * Globals...
47  */
48 
49 unsigned char	*Planes[6],		/* Output buffers */
50 		*CompBuffer,		/* Compression buffer */
51 		*LineBuffers[2];	/* Line bitmap buffers */
52 int		Model,			/* Model number */
53 		EjectPage,		/* Eject the page when done? */
54 		Shingling,		/* Shingle output? */
55 		Canceled;		/* Has the current job been canceled? */
56 unsigned	NumPlanes,		/* Number of color planes */
57 		Feed,			/* Number of lines to skip */
58 		DotBit,			/* Bit in buffers */
59 		DotBytes,		/* # bytes in a dot column */
60 		DotColumns,		/* # columns in 1/60 inch */
61 		LineCount,		/* # of lines processed */
62 		EvenOffset,		/* Offset into 'even' buffers */
63 		OddOffset;		/* Offset into 'odd' buffers */
64 
65 
66 /*
67  * Prototypes...
68  */
69 
70 void	Setup(void);
71 void	StartPage(const ppd_file_t *ppd, const cups_page_header2_t *header);
72 void	EndPage(const cups_page_header2_t *header);
73 void	Shutdown(void);
74 
75 void	CancelJob(int sig);
76 void	CompressData(const unsigned char *line, unsigned length, unsigned plane,
77 	             unsigned type, unsigned xstep, unsigned ystep);
78 void	OutputLine(const cups_page_header2_t *header);
79 void	OutputRows(const cups_page_header2_t *header, int row);
80 
81 
82 /*
83  * 'Setup()' - Prepare the printer for printing.
84  */
85 
86 void
Setup(void)87 Setup(void)
88 {
89   const char	*device_uri;		/* The device for the printer... */
90 
91 
92  /*
93   * EPSON USB printers need an additional command issued at the
94   * beginning of each job to exit from "packet" mode...
95   */
96 
97   if ((device_uri = getenv("DEVICE_URI")) != NULL &&
98       strncmp(device_uri, "usb:", 4) == 0 && Model >= EPSON_ICOLOR)
99     pwrite("\000\000\000\033\001@EJL 1284.4\n@EJL     \n\033@", 29);
100 }
101 
102 
103 /*
104  * 'StartPage()' - Start a page of graphics.
105  */
106 
107 void
StartPage(const ppd_file_t * ppd,const cups_page_header2_t * header)108 StartPage(
109     const ppd_file_t         *ppd,	/* I - PPD file */
110     const cups_page_header2_t *header)	/* I - Page header */
111 {
112   int		n, t;			/* Numbers */
113   unsigned	plane;			/* Looping var */
114 
115 
116  /*
117   * Show page device dictionary...
118   */
119 
120   fprintf(stderr, "DEBUG: StartPage...\n");
121   fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
122   fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0], header->HWResolution[1]);
123   fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", header->ImagingBoundingBox[0], header->ImagingBoundingBox[1], header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
124   fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0], header->Margins[1]);
125   fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
126   fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
127   fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
128   fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
129   fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0], header->PageSize[1]);
130   fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
131   fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
132   fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
133   fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
134   fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
135   fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
136   fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
137   fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
138   fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
139 
140  /*
141   * Send a reset sequence.
142   */
143 
144   if (ppd && ppd->nickname && strstr(ppd->nickname, "OKIDATA") != NULL)
145     printf("\033{A");	/* Set EPSON emulation mode */
146 
147   printf("\033@");
148 
149  /*
150   * See which type of printer we are using...
151   */
152 
153   switch (Model)
154   {
155     case EPSON_9PIN :
156     case EPSON_24PIN :
157         printf("\033P\022");		/* Set 10 CPI */
158 
159 	if (header->HWResolution[0] == 360 || header->HWResolution[0] == 240)
160 	{
161 	  printf("\033x1");		/* LQ printing */
162 	  printf("\033U1");		/* Unidirectional */
163 	}
164 	else
165 	{
166 	  printf("\033x0");		/* Draft printing */
167 	  printf("\033U0");		/* Bidirectional */
168 	}
169 
170 	printf("\033l%c\033Q%c", 0,	/* Side margins */
171                       (int)(10.0 * header->PageSize[0] / 72.0 + 0.5));
172 	printf("\033\062\033C%c",	/* Page length in 1/6th inches */
173 		      (int)(header->PageSize[1] / 12.0 + 0.5));
174 	printf("\033N%c", 0);		/* Bottom margin */
175         printf("\033O");		/* No perforation skip */
176 
177        /*
178 	* Setup various buffer limits...
179 	*/
180 
181         DotBytes   = header->cupsRowCount / 8;
182 	DotColumns = header->HWResolution[0] / 60;
183         Shingling  = 0;
184 
185         if (Model == EPSON_9PIN)
186 	  printf("\033\063\030");	/* Set line feed */
187 	else
188 	  switch (header->HWResolution[0])
189 	  {
190 	    case 60:
191 	    case 120 :
192 	    case 240 :
193         	printf("\033\063\030");	/* Set line feed */
194 		break;
195 
196 	    case 180 :
197 	    case 360 :
198         	Shingling = 1;
199 
200         	if (header->HWResolution[1] == 180)
201         	  printf("\033\063\010");/* Set line feed */
202 		else
203         	  printf("\033+\010");	/* Set line feed */
204         	break;
205 	  }
206         break;
207 
208     default :
209        /*
210 	* Set graphics mode...
211 	*/
212 
213 	pwrite("\033(G\001\000\001", 6);	/* Graphics mode */
214 
215        /*
216 	* Set the media size...
217 	*/
218 
219         if (Model < EPSON_ICOLOR)
220 	{
221 	  pwrite("\033(U\001\000", 5);		/* Resolution/units */
222 	  putchar((int)(3600 / header->HWResolution[1]));
223         }
224 	else
225 	{
226 	  pwrite("\033(U\005\000", 5);
227 	  putchar((int)(1440 / header->HWResolution[1]));
228 	  putchar((int)(1440 / header->HWResolution[1]));
229 	  putchar((int)(1440 / header->HWResolution[0]));
230 	  putchar(0xa0);	/* n/1440ths... */
231 	  putchar(0x05);
232 	}
233 
234 	n = (int)(header->PageSize[1] * header->HWResolution[1] / 72.0);
235 
236 	pwrite("\033(C\002\000", 5);		/* Page length */
237 	putchar(n);
238 	putchar(n >> 8);
239 
240         if (ppd)
241 	  t = (int)((ppd->sizes[1].length - ppd->sizes[1].top) * header->HWResolution[1] / 72.0);
242         else
243 	  t = 0;
244 
245 	pwrite("\033(c\004\000", 5);		/* Top & bottom margins */
246 	putchar(t);
247 	putchar(t >> 8);
248 	putchar(n);
249 	putchar(n >> 8);
250 
251 	if (header->HWResolution[1] == 720)
252 	{
253 	  pwrite("\033(i\001\000\001", 6);	/* Microweave */
254 	  pwrite("\033(e\002\000\000\001", 7);	/* Small dots */
255 	}
256 
257 	pwrite("\033(V\002\000\000\000", 7);	/* Set absolute position 0 */
258 
259         DotBytes   = 0;
260 	DotColumns = 0;
261         Shingling  = 0;
262         break;
263   }
264 
265  /*
266   * Set other stuff...
267   */
268 
269   if (header->cupsColorSpace == CUPS_CSPACE_CMY)
270     NumPlanes = 3;
271   else if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
272     NumPlanes = 4;
273   else if (header->cupsColorSpace == CUPS_CSPACE_KCMYcm)
274     NumPlanes = 6;
275   else
276     NumPlanes = 1;
277 
278   Feed = 0;				/* No blank lines yet */
279 
280  /*
281   * Allocate memory for a line/row of graphics...
282   */
283 
284   if ((Planes[0] = malloc(header->cupsBytesPerLine + NumPlanes)) == NULL)
285   {
286     fputs("ERROR: Unable to allocate memory\n", stderr);
287     exit(1);
288   }
289 
290   for (plane = 1; plane < NumPlanes; plane ++)
291     Planes[plane] = Planes[0] + plane * header->cupsBytesPerLine / NumPlanes;
292 
293   if (header->cupsCompression || DotBytes)
294   {
295     if ((CompBuffer = calloc(2, header->cupsWidth + 1)) == NULL)
296     {
297       fputs("ERROR: Unable to allocate memory\n", stderr);
298       exit(1);
299     }
300   }
301   else
302     CompBuffer = NULL;
303 
304   if (DotBytes)
305   {
306     if ((LineBuffers[0] = calloc((size_t)DotBytes, (header->cupsWidth + 7) * (size_t)(Shingling + 1))) == NULL)
307     {
308       fputs("ERROR: Unable to allocate memory\n", stderr);
309       exit(1);
310     }
311 
312     LineBuffers[1] = LineBuffers[0] + DotBytes * header->cupsWidth;
313     DotBit         = 128;
314     LineCount      = 0;
315     EvenOffset     = 0;
316     OddOffset      = 0;
317   }
318 }
319 
320 
321 /*
322  * 'EndPage()' - Finish a page of graphics.
323  */
324 
325 void
EndPage(const cups_page_header2_t * header)326 EndPage(
327     const cups_page_header2_t *header)	/* I - Page header */
328 {
329   if (DotBytes && header)
330   {
331    /*
332     * Flush remaining graphics as needed...
333     */
334 
335     if (!Shingling)
336     {
337       if (DotBit < 128 || EvenOffset)
338         OutputRows(header, 0);
339     }
340     else if (OddOffset > EvenOffset)
341     {
342       OutputRows(header, 1);
343       OutputRows(header, 0);
344     }
345     else
346     {
347       OutputRows(header, 0);
348       OutputRows(header, 1);
349     }
350   }
351 
352  /*
353   * Eject the current page...
354   */
355 
356   putchar(12);				/* Form feed */
357   fflush(stdout);
358 
359  /*
360   * Free memory...
361   */
362 
363   free(Planes[0]);
364 
365   if (CompBuffer)
366     free(CompBuffer);
367 
368   if (DotBytes)
369     free(LineBuffers[0]);
370 }
371 
372 
373 /*
374  * 'Shutdown()' - Shutdown the printer.
375  */
376 
377 void
Shutdown(void)378 Shutdown(void)
379 {
380  /*
381   * Send a reset sequence.
382   */
383 
384   printf("\033@");
385 }
386 
387 
388 /*
389  * 'CancelJob()' - Cancel the current job...
390  */
391 
392 void
CancelJob(int sig)393 CancelJob(int sig)			/* I - Signal */
394 {
395   (void)sig;
396 
397   Canceled = 1;
398 }
399 
400 
401 /*
402  * 'CompressData()' - Compress a line of graphics.
403  */
404 
405 void
CompressData(const unsigned char * line,unsigned length,unsigned plane,unsigned type,unsigned xstep,unsigned ystep)406 CompressData(const unsigned char *line,	/* I - Data to compress */
407              unsigned            length,/* I - Number of bytes */
408 	     unsigned            plane,	/* I - Color plane */
409 	     unsigned            type,	/* I - Type of compression */
410 	     unsigned            xstep,	/* I - X resolution */
411 	     unsigned            ystep)	/* I - Y resolution */
412 {
413   const unsigned char	*line_ptr,	/* Current byte pointer */
414         		*line_end,	/* End-of-line byte pointer */
415         		*start;		/* Start of compression sequence */
416   unsigned char      	*comp_ptr,	/* Pointer into compression buffer */
417 			temp;		/* Current byte */
418   int   	        count;		/* Count of bytes for output */
419   static int		ctable[6] = { 0, 2, 1, 4, 18, 17 };
420 					/* KCMYcm color values */
421 
422 
423  /*
424   * Setup pointers...
425   */
426 
427   line_ptr = line;
428   line_end = line + length;
429 
430  /*
431   * Do depletion for 720 DPI printing...
432   */
433 
434   if (ystep == 5)
435   {
436     for (comp_ptr = (unsigned char *)line; comp_ptr < line_end;)
437     {
438      /*
439       * Grab the current byte...
440       */
441 
442       temp = *comp_ptr;
443 
444      /*
445       * Check adjacent bits...
446       */
447 
448       if ((temp & 0xc0) == 0xc0)
449         temp &= 0xbf;
450       if ((temp & 0x60) == 0x60)
451         temp &= 0xdf;
452       if ((temp & 0x30) == 0x30)
453         temp &= 0xef;
454       if ((temp & 0x18) == 0x18)
455         temp &= 0xf7;
456       if ((temp & 0x0c) == 0x0c)
457         temp &= 0xfb;
458       if ((temp & 0x06) == 0x06)
459         temp &= 0xfd;
460       if ((temp & 0x03) == 0x03)
461         temp &= 0xfe;
462 
463       *comp_ptr++ = temp;
464 
465      /*
466       * Check the last bit in the current byte...
467       */
468 
469       if ((temp & 0x01) && comp_ptr < line_end)
470         *comp_ptr &= 0x7f;
471     }
472   }
473 
474   switch (type)
475   {
476     case 0 :
477        /*
478 	* Do no compression...
479 	*/
480 	break;
481 
482     case 1 :
483        /*
484         * Do TIFF pack-bits encoding...
485         */
486 
487 	comp_ptr = CompBuffer;
488 
489 	while (line_ptr < line_end)
490 	{
491 	  if ((line_ptr + 1) >= line_end)
492 	  {
493 	   /*
494 	    * Single byte on the end...
495 	    */
496 
497 	    *comp_ptr++ = 0x00;
498 	    *comp_ptr++ = *line_ptr++;
499 	  }
500 	  else if (line_ptr[0] == line_ptr[1])
501 	  {
502 	   /*
503 	    * Repeated sequence...
504 	    */
505 
506 	    line_ptr ++;
507 	    count = 2;
508 
509 	    while (line_ptr < (line_end - 1) &&
510         	   line_ptr[0] == line_ptr[1] &&
511         	   count < 127)
512 	    {
513               line_ptr ++;
514               count ++;
515 	    }
516 
517 	    *comp_ptr++ = (unsigned char)(257 - count);
518 	    *comp_ptr++ = *line_ptr++;
519 	  }
520 	  else
521 	  {
522 	   /*
523 	    * Non-repeated sequence...
524 	    */
525 
526 	    start    = line_ptr;
527 	    line_ptr ++;
528 	    count    = 1;
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)(count - 1);
539 
540 	    memcpy(comp_ptr, start, (size_t)count);
541 	    comp_ptr += count;
542 	  }
543 	}
544 
545         line_ptr = CompBuffer;
546         line_end = comp_ptr;
547 	break;
548   }
549 
550   putchar(0x0d);			/* Move print head to left margin */
551 
552   if (Model < EPSON_ICOLOR)
553   {
554    /*
555     * Do graphics the "old" way...
556     */
557 
558     if (NumPlanes > 1)
559     {
560      /*
561       * Set the color...
562       */
563 
564       if (plane > 3)
565 	printf("\033(r%c%c%c%c", 2, 0, 1, ctable[plane] & 15);
566 					  /* Set extended color */
567       else if (NumPlanes == 3)
568 	printf("\033r%c", ctable[plane + 1]);
569 					  /* Set color */
570       else
571 	printf("\033r%c", ctable[plane]);	/* Set color */
572     }
573 
574    /*
575     * Send a raster plane...
576     */
577 
578     length *= 8;
579     printf("\033.");			/* Raster graphics */
580     putchar((int)type);
581     putchar((int)ystep);
582     putchar((int)xstep);
583     putchar(1);
584     putchar((int)length);
585     putchar((int)(length >> 8));
586   }
587   else
588   {
589    /*
590     * Do graphics the "new" way...
591     */
592 
593     printf("\033i");
594     putchar(ctable[plane]);
595     putchar((int)type);
596     putchar(1);
597     putchar((int)length);
598     putchar((int)(length >> 8));
599     putchar(1);
600     putchar(0);
601   }
602 
603   pwrite(line_ptr, (size_t)(line_end - line_ptr));
604   fflush(stdout);
605 }
606 
607 
608 /*
609  * 'OutputLine()' - Output a line of graphics.
610  */
611 
612 void
OutputLine(const cups_page_header2_t * header)613 OutputLine(
614     const cups_page_header2_t *header)	/* I - Page header */
615 {
616   if (header->cupsRowCount)
617   {
618     unsigned		width;
619     unsigned char	*tempptr,
620 			*evenptr,
621 			*oddptr;
622     unsigned int	x;
623     unsigned char	bit;
624     const unsigned char	*pixel;
625     unsigned char 	*temp;
626 
627 
628    /*
629     * Collect bitmap data in the line buffers and write after each buffer.
630     */
631 
632     for (x = header->cupsWidth, bit = 128, pixel = Planes[0],
633              temp = CompBuffer;
634 	 x > 0;
635 	 x --, temp ++)
636     {
637       if (*pixel & bit)
638         *temp |= DotBit;
639 
640       if (bit > 1)
641 	bit >>= 1;
642       else
643       {
644 	bit = 128;
645 	pixel ++;
646       }
647     }
648 
649     if (DotBit > 1)
650       DotBit >>= 1;
651     else
652     {
653      /*
654       * Copy the holding buffer to the output buffer, shingling as necessary...
655       */
656 
657       if (Shingling && LineCount != 0)
658       {
659        /*
660         * Shingle the output...
661         */
662 
663         if (LineCount & 1)
664         {
665           evenptr = LineBuffers[1] + OddOffset;
666           oddptr  = LineBuffers[0] + EvenOffset + DotBytes;
667         }
668         else
669         {
670           evenptr = LineBuffers[0] + EvenOffset;
671           oddptr  = LineBuffers[1] + OddOffset + DotBytes;
672         }
673 
674         for (width = header->cupsWidth, tempptr = CompBuffer;
675              width > 1;
676              width -= 2, tempptr += 2, oddptr += DotBytes * 2,
677 	         evenptr += DotBytes * 2)
678         {
679           evenptr[0] = tempptr[0];
680           oddptr[0]  = tempptr[1];
681         }
682 
683         if (width == 1)
684         {
685           evenptr[0] = tempptr[0];
686           oddptr[0]  = tempptr[1];
687         }
688       }
689       else
690       {
691        /*
692         * Don't shingle the output...
693         */
694 
695         for (width = header->cupsWidth, tempptr = CompBuffer,
696                  evenptr = LineBuffers[0] + EvenOffset;
697              width > 0;
698              width --, tempptr ++, evenptr += DotBytes)
699           *evenptr = tempptr[0];
700       }
701 
702       if (Shingling && LineCount != 0)
703       {
704 	EvenOffset ++;
705 	OddOffset ++;
706 
707 	if (EvenOffset == DotBytes)
708 	{
709 	  EvenOffset = 0;
710 	  OutputRows(header, 0);
711 	}
712 
713 	if (OddOffset == DotBytes)
714 	{
715           OddOffset = 0;
716 	  OutputRows(header, 1);
717 	}
718       }
719       else
720       {
721 	EvenOffset ++;
722 
723 	if (EvenOffset == DotBytes)
724 	{
725           EvenOffset = 0;
726 	  OutputRows(header, 0);
727 	}
728       }
729 
730       DotBit = 128;
731       LineCount ++;
732 
733       memset(CompBuffer, 0, header->cupsWidth);
734     }
735   }
736   else
737   {
738     unsigned	plane;		/* Current plane */
739     unsigned	bytes;		/* Bytes per plane */
740     unsigned	xstep, ystep;	/* X & Y resolutions */
741 
742    /*
743     * Write a single line of bitmap data as needed...
744     */
745 
746     xstep = 3600 / header->HWResolution[0];
747     ystep = 3600 / header->HWResolution[1];
748     bytes = header->cupsBytesPerLine / NumPlanes;
749 
750     for (plane = 0; plane < NumPlanes; plane ++)
751     {
752      /*
753       * Skip blank data...
754       */
755 
756       if (!Planes[plane][0] &&
757           memcmp(Planes[plane], Planes[plane] + 1, (size_t)bytes - 1) == 0)
758 	continue;
759 
760      /*
761       * Output whitespace as needed...
762       */
763 
764       if (Feed > 0)
765       {
766 	pwrite("\033(v\002\000", 5);	/* Relative vertical position */
767 	putchar((int)Feed);
768 	putchar((int)(Feed >> 8));
769 
770 	Feed = 0;
771       }
772 
773       CompressData(Planes[plane], bytes, plane, header->cupsCompression, xstep, ystep);
774     }
775 
776     Feed ++;
777   }
778 }
779 
780 
781 /*
782  * 'OutputRows()' - Output 8, 24, or 48 rows.
783  */
784 
785 void
OutputRows(const cups_page_header2_t * header,int row)786 OutputRows(
787     const cups_page_header2_t *header,	/* I - Page image header */
788     int                      row)	/* I - Row number (0 or 1) */
789 {
790   unsigned	i, n,			/* Looping vars */
791 		dot_count,		/* Number of bytes to print */
792                 dot_min;		/* Minimum number of bytes */
793   unsigned char *dot_ptr,		/* Pointer to print data */
794 		*ptr;			/* Current data */
795 
796 
797   dot_min = DotBytes * DotColumns;
798 
799   if (LineBuffers[row][0] != 0 ||
800       memcmp(LineBuffers[row], LineBuffers[row] + 1, header->cupsWidth * DotBytes - 1))
801   {
802    /*
803     * Skip leading space...
804     */
805 
806     i         = 0;
807     dot_count = header->cupsWidth * DotBytes;
808     dot_ptr   = LineBuffers[row];
809 
810     while (dot_count >= dot_min && dot_ptr[0] == 0 &&
811            memcmp(dot_ptr, dot_ptr + 1, dot_min - 1) == 0)
812     {
813       i         ++;
814       dot_ptr   += dot_min;
815       dot_count -= dot_min;
816     }
817 
818    /*
819     * Skip trailing space...
820     */
821 
822     while (dot_count >= dot_min && dot_ptr[dot_count - dot_min] == 0 &&
823            memcmp(dot_ptr + dot_count - dot_min,
824 	          dot_ptr + dot_count - dot_min + 1, dot_min - 1) == 0)
825       dot_count -= dot_min;
826 
827    /*
828     * Position print head for printing...
829     */
830 
831     if (i == 0)
832       putchar('\r');
833     else
834     {
835       putchar(0x1b);
836       putchar('$');
837       putchar((int)(i & 255));
838       putchar((int)(i >> 8));
839     }
840 
841    /*
842     * Start bitmap graphics for this line...
843     */
844 
845     printf("\033*");			/* Select bit image */
846     switch (header->HWResolution[0])
847     {
848       case 60 : /* 60x60/72 DPI gfx */
849           putchar(0);
850           break;
851       case 120 : /* 120x60/72 DPI gfx */
852           putchar(1);
853           break;
854       case 180 : /* 180 DPI gfx */
855           putchar(39);
856           break;
857       case 240 : /* 240x72 DPI gfx */
858           putchar(3);
859           break;
860       case 360 : /* 360x180/360 DPI gfx */
861 	  if (header->HWResolution[1] == 180)
862 	  {
863             if (Shingling && LineCount != 0)
864               putchar(40);		/* 360x180 fast */
865             else
866               putchar(41);		/* 360x180 slow */
867 	  }
868 	  else
869           {
870 	    if (Shingling && LineCount != 0)
871               putchar(72);		/* 360x360 fast */
872             else
873               putchar(73);		/* 360x360 slow */
874           }
875           break;
876     }
877 
878     n = dot_count / DotBytes;
879     putchar((int)(n & 255));
880     putchar((int)(n / 256));
881 
882    /*
883     * Write the graphics data...
884     */
885 
886     if (header->HWResolution[0] == 120 ||
887         header->HWResolution[0] == 240)
888     {
889      /*
890       * Need to interleave the dots to avoid hosing the print head...
891       */
892 
893       for (n = dot_count / 2, ptr = dot_ptr; n > 0; n --, ptr += 2)
894       {
895         putchar(*ptr);
896 	putchar(0);
897       }
898 
899       if (dot_count & 1)
900         putchar(*ptr);
901 
902      /*
903       * Move the head back and print the odd bytes...
904       */
905 
906       if (i == 0)
907 	putchar('\r');
908       else
909       {
910 	putchar(0x1b);
911 	putchar('$');
912 	putchar((int)(i & 255));
913 	putchar((int)(i >> 8));
914       }
915 
916       if (header->HWResolution[0] == 120)
917       	printf("\033*\001");		/* Select bit image */
918       else
919       	printf("\033*\003");		/* Select bit image */
920 
921       n = (unsigned)dot_count / DotBytes;
922       putchar((int)(n & 255));
923       putchar((int)(n / 256));
924 
925       for (n = dot_count / 2, ptr = dot_ptr + 1; n > 0; n --, ptr += 2)
926       {
927 	putchar(0);
928         putchar(*ptr);
929       }
930 
931       if (dot_count & 1)
932         putchar(0);
933     }
934     else
935       pwrite(dot_ptr, dot_count);
936   }
937 
938  /*
939   * Feed the paper...
940   */
941 
942   putchar('\n');
943 
944   if (Shingling && row == 1)
945   {
946     if (header->HWResolution[1] == 360)
947       printf("\n\n\n\n");
948     else
949       printf("\n");
950   }
951 
952   fflush(stdout);
953 
954  /*
955   * Clear the buffer...
956   */
957 
958   memset(LineBuffers[row], 0, (size_t)header->cupsWidth * (size_t)DotBytes);
959 }
960 
961 
962 /*
963  * 'main()' - Main entry and processing of driver.
964  */
965 
966 int					/* O - Exit status */
main(int argc,char * argv[])967 main(int  argc,				/* I - Number of command-line arguments */
968      char *argv[])			/* I - Command-line arguments */
969 {
970   int			fd;		/* File descriptor */
971   cups_raster_t		*ras;		/* Raster stream for printing */
972   cups_page_header2_t	header;		/* Page header from file */
973   ppd_file_t		*ppd;		/* PPD file */
974   int			page;		/* Current page */
975   unsigned		y;		/* Current line */
976 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
977   struct sigaction action;		/* Actions for POSIX signals */
978 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
979 
980 
981  /*
982   * Make sure status messages are not buffered...
983   */
984 
985   setbuf(stderr, NULL);
986 
987  /*
988   * Check command-line...
989   */
990 
991   if (argc != 6 && argc != 7)
992   {
993    /*
994     * We don't have the correct number of arguments; write an error message
995     * and return.
996     */
997 
998     _cupsLangPrintFilter(stderr, "ERROR",
999                          _("%s job-id user title copies options [file]"),
1000                          "rastertoepson");
1001     return (1);
1002   }
1003 
1004  /*
1005   * Open the page stream...
1006   */
1007 
1008   if (argc == 7)
1009   {
1010     if ((fd = open(argv[6], O_RDONLY)) == -1)
1011     {
1012       _cupsLangPrintError("ERROR", _("Unable to open raster file"));
1013       sleep(1);
1014       return (1);
1015     }
1016   }
1017   else
1018     fd = 0;
1019 
1020   ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
1021 
1022  /*
1023   * Register a signal handler to eject the current page if the
1024   * job is cancelled.
1025   */
1026 
1027   Canceled = 0;
1028 
1029 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1030   sigset(SIGTERM, CancelJob);
1031 #elif defined(HAVE_SIGACTION)
1032   memset(&action, 0, sizeof(action));
1033 
1034   sigemptyset(&action.sa_mask);
1035   action.sa_handler = CancelJob;
1036   sigaction(SIGTERM, &action, NULL);
1037 #else
1038   signal(SIGTERM, CancelJob);
1039 #endif /* HAVE_SIGSET */
1040 
1041  /*
1042   * Initialize the print device...
1043   */
1044 
1045   ppd = ppdOpenFile(getenv("PPD"));
1046   if (!ppd)
1047   {
1048     ppd_status_t	status;		/* PPD error */
1049     int			linenum;	/* Line number */
1050 
1051     _cupsLangPrintFilter(stderr, "ERROR",
1052                          _("The PPD file could not be opened."));
1053 
1054     status = ppdLastError(&linenum);
1055 
1056     fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
1057 
1058     return (1);
1059   }
1060 
1061   Model = ppd->model_number;
1062 
1063   Setup();
1064 
1065  /*
1066   * Process pages as needed...
1067   */
1068 
1069   page = 0;
1070 
1071   while (cupsRasterReadHeader2(ras, &header))
1072   {
1073    /*
1074     * Write a status message with the page number and number of copies.
1075     */
1076 
1077     if (Canceled)
1078       break;
1079 
1080     page ++;
1081 
1082     fprintf(stderr, "PAGE: %d %d\n", page, header.NumCopies);
1083     _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), page);
1084 
1085    /*
1086     * Start the page...
1087     */
1088 
1089     StartPage(ppd, &header);
1090 
1091    /*
1092     * Loop for each line on the page...
1093     */
1094 
1095     for (y = 0; y < header.cupsHeight; y ++)
1096     {
1097      /*
1098       * Let the user know how far we have progressed...
1099       */
1100 
1101       if (Canceled)
1102 	break;
1103 
1104       if ((y & 127) == 0)
1105       {
1106         _cupsLangPrintFilter(stderr, "INFO",
1107 	                     _("Printing page %d, %u%% complete."),
1108 			     page, 100 * y / header.cupsHeight);
1109         fprintf(stderr, "ATTR: job-media-progress=%u\n",
1110 		100 * y / header.cupsHeight);
1111       }
1112 
1113      /*
1114       * Read a line of graphics...
1115       */
1116 
1117       if (cupsRasterReadPixels(ras, Planes[0], header.cupsBytesPerLine) < 1)
1118         break;
1119 
1120      /*
1121       * Write it to the printer...
1122       */
1123 
1124       OutputLine(&header);
1125     }
1126 
1127    /*
1128     * Eject the page...
1129     */
1130 
1131     _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), page);
1132 
1133     EndPage(&header);
1134 
1135     if (Canceled)
1136       break;
1137   }
1138 
1139  /*
1140   * Shutdown the printer...
1141   */
1142 
1143   Shutdown();
1144 
1145   ppdClose(ppd);
1146 
1147  /*
1148   * Close the raster stream...
1149   */
1150 
1151   cupsRasterClose(ras);
1152   if (fd != 0)
1153     close(fd);
1154 
1155  /*
1156   * If no pages were printed, send an error message...
1157   */
1158 
1159   if (page == 0)
1160   {
1161     _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
1162     return (1);
1163   }
1164   else
1165     return (0);
1166 }
1167