1 /*
2  * EPSON ESC/P and ESC/P2 filter for CUPS.
3  *
4  * Copyright 2007-2018 by Apple Inc.
5  * Copyright 1993-2007 by Easy Software Products.
6  *
7  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8  * information.
9  */
10 
11 /*
12  * Include necessary headers...
13  */
14 
15 #include <cups/cups.h>
16 #include <cups/ppd.h>
17 #include <cups/string-private.h>
18 #include <cups/language-private.h>
19 #include <cups/raster.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 
24 
25 /*
26  * Model numbers...
27  */
28 
29 #define EPSON_9PIN	0
30 #define EPSON_24PIN	1
31 #define EPSON_COLOR	2
32 #define EPSON_PHOTO	3
33 #define EPSON_ICOLOR	4
34 #define EPSON_IPHOTO	5
35 
36 
37 /*
38  * Macros...
39  */
40 
41 #define pwrite(s,n) fwrite((s), 1, (n), stdout)
42 
43 
44 /*
45  * Globals...
46  */
47 
48 unsigned char	*Planes[6],		/* Output buffers */
49 		*CompBuffer,		/* Compression buffer */
50 		*LineBuffers[2];	/* Line bitmap buffers */
51 int		Model,			/* Model number */
52 		EjectPage,		/* Eject the page when done? */
53 		Shingling,		/* Shingle output? */
54 		Canceled;		/* Has the current job been canceled? */
55 unsigned	NumPlanes,		/* Number of color planes */
56 		Feed,			/* Number of lines to skip */
57 		DotBit,			/* Bit in buffers */
58 		DotBytes,		/* # bytes in a dot column */
59 		DotColumns,		/* # columns in 1/60 inch */
60 		LineCount,		/* # of lines processed */
61 		EvenOffset,		/* Offset into 'even' buffers */
62 		OddOffset;		/* Offset into 'odd' buffers */
63 
64 
65 /*
66  * Prototypes...
67  */
68 
69 void	Setup(void);
70 void	StartPage(const ppd_file_t *ppd, const cups_page_header2_t *header);
71 void	EndPage(const cups_page_header2_t *header);
72 void	Shutdown(void);
73 
74 void	CancelJob(int sig);
75 void	CompressData(const unsigned char *line, unsigned length, unsigned plane,
76 	             unsigned type, unsigned xstep, unsigned ystep);
77 void	OutputLine(const cups_page_header2_t *header);
78 void	OutputRows(const cups_page_header2_t *header, int row);
79 
80 
81 /*
82  * 'Setup()' - Prepare the printer for printing.
83  */
84 
85 void
Setup(void)86 Setup(void)
87 {
88   const char	*device_uri;		/* The device for the printer... */
89 
90 
91  /*
92   * EPSON USB printers need an additional command issued at the
93   * beginning of each job to exit from "packet" mode...
94   */
95 
96   if ((device_uri = getenv("DEVICE_URI")) != NULL &&
97       strncmp(device_uri, "usb:", 4) == 0 && Model >= EPSON_ICOLOR)
98     pwrite("\000\000\000\033\001@EJL 1284.4\n@EJL     \n\033@", 29);
99 }
100 
101 
102 /*
103  * 'StartPage()' - Start a page of graphics.
104  */
105 
106 void
StartPage(const ppd_file_t * ppd,const cups_page_header2_t * header)107 StartPage(
108     const ppd_file_t         *ppd,	/* I - PPD file */
109     const cups_page_header2_t *header)	/* I - Page header */
110 {
111   int		n, t;			/* Numbers */
112   unsigned	plane;			/* Looping var */
113 
114 
115  /*
116   * Show page device dictionary...
117   */
118 
119   fprintf(stderr, "DEBUG: StartPage...\n");
120   fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
121   fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0], header->HWResolution[1]);
122   fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", header->ImagingBoundingBox[0], header->ImagingBoundingBox[1], header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
123   fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0], 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: NumCopies = %d\n", header->NumCopies);
127   fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
128   fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0], header->PageSize[1]);
129   fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
130   fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
131   fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
132   fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
133   fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
134   fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
135   fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
136   fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
137   fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
138 
139  /*
140   * Send a reset sequence.
141   */
142 
143   if (ppd && ppd->nickname && strstr(ppd->nickname, "OKIDATA") != NULL)
144     printf("\033{A");	/* Set EPSON emulation mode */
145 
146   printf("\033@");
147 
148  /*
149   * See which type of printer we are using...
150   */
151 
152   switch (Model)
153   {
154     case EPSON_9PIN :
155     case EPSON_24PIN :
156         printf("\033P\022");		/* Set 10 CPI */
157 
158 	if (header->HWResolution[0] == 360 || header->HWResolution[0] == 240)
159 	{
160 	  printf("\033x1");		/* LQ printing */
161 	  printf("\033U1");		/* Unidirectional */
162 	}
163 	else
164 	{
165 	  printf("\033x0");		/* Draft printing */
166 	  printf("\033U0");		/* Bidirectional */
167 	}
168 
169 	printf("\033l%c\033Q%c", 0,	/* Side margins */
170                       (int)(10.0 * header->PageSize[0] / 72.0 + 0.5));
171 	printf("\033\062\033C%c",	/* Page length in 1/6th inches */
172 		      (int)(header->PageSize[1] / 12.0 + 0.5));
173 	printf("\033N%c", 0);		/* Bottom margin */
174         printf("\033O");		/* No perforation skip */
175 
176        /*
177 	* Setup various buffer limits...
178 	*/
179 
180         DotBytes   = header->cupsRowCount / 8;
181 	DotColumns = header->HWResolution[0] / 60;
182         Shingling  = 0;
183 
184         if (Model == EPSON_9PIN)
185 	  printf("\033\063\030");	/* Set line feed */
186 	else
187 	  switch (header->HWResolution[0])
188 	  {
189 	    case 60:
190 	    case 120 :
191 	    case 240 :
192         	printf("\033\063\030");	/* Set line feed */
193 		break;
194 
195 	    case 180 :
196 	    case 360 :
197         	Shingling = 1;
198 
199         	if (header->HWResolution[1] == 180)
200         	  printf("\033\063\010");/* Set line feed */
201 		else
202         	  printf("\033+\010");	/* Set line feed */
203         	break;
204 	  }
205         break;
206 
207     default :
208        /*
209 	* Set graphics mode...
210 	*/
211 
212 	pwrite("\033(G\001\000\001", 6);	/* Graphics mode */
213 
214        /*
215 	* Set the media size...
216 	*/
217 
218         if (Model < EPSON_ICOLOR)
219 	{
220 	  pwrite("\033(U\001\000", 5);		/* Resolution/units */
221 	  putchar((int)(3600 / header->HWResolution[1]));
222         }
223 	else
224 	{
225 	  pwrite("\033(U\005\000", 5);
226 	  putchar((int)(1440 / header->HWResolution[1]));
227 	  putchar((int)(1440 / header->HWResolution[1]));
228 	  putchar((int)(1440 / header->HWResolution[0]));
229 	  putchar(0xa0);	/* n/1440ths... */
230 	  putchar(0x05);
231 	}
232 
233 	n = (int)(header->PageSize[1] * header->HWResolution[1] / 72.0);
234 
235 	pwrite("\033(C\002\000", 5);		/* Page length */
236 	putchar(n);
237 	putchar(n >> 8);
238 
239         if (ppd)
240 	  t = (int)((ppd->sizes[1].length - ppd->sizes[1].top) * header->HWResolution[1] / 72.0);
241         else
242 	  t = 0;
243 
244 	pwrite("\033(c\004\000", 5);		/* Top & bottom margins */
245 	putchar(t);
246 	putchar(t >> 8);
247 	putchar(n);
248 	putchar(n >> 8);
249 
250 	if (header->HWResolution[1] == 720)
251 	{
252 	  pwrite("\033(i\001\000\001", 6);	/* Microweave */
253 	  pwrite("\033(e\002\000\000\001", 7);	/* Small dots */
254 	}
255 
256 	pwrite("\033(V\002\000\000\000", 7);	/* Set absolute position 0 */
257 
258         DotBytes   = 0;
259 	DotColumns = 0;
260         Shingling  = 0;
261         break;
262   }
263 
264  /*
265   * Set other stuff...
266   */
267 
268   if (header->cupsColorSpace == CUPS_CSPACE_CMY)
269     NumPlanes = 3;
270   else if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
271     NumPlanes = 4;
272   else if (header->cupsColorSpace == CUPS_CSPACE_KCMYcm)
273     NumPlanes = 6;
274   else
275     NumPlanes = 1;
276 
277   Feed = 0;				/* No blank lines yet */
278 
279  /*
280   * Allocate memory for a line/row of graphics...
281   */
282 
283   if ((Planes[0] = malloc(header->cupsBytesPerLine + NumPlanes)) == NULL)
284   {
285     fputs("ERROR: Unable to allocate memory\n", stderr);
286     exit(1);
287   }
288 
289   for (plane = 1; plane < NumPlanes; plane ++)
290     Planes[plane] = Planes[0] + plane * header->cupsBytesPerLine / NumPlanes;
291 
292   if (header->cupsCompression || DotBytes)
293   {
294     if ((CompBuffer = calloc(2, header->cupsWidth + 1)) == NULL)
295     {
296       fputs("ERROR: Unable to allocate memory\n", stderr);
297       exit(1);
298     }
299   }
300   else
301     CompBuffer = NULL;
302 
303   if (DotBytes)
304   {
305     if ((LineBuffers[0] = calloc((size_t)DotBytes, (header->cupsWidth + 7) * (size_t)(Shingling + 1))) == NULL)
306     {
307       fputs("ERROR: Unable to allocate memory\n", stderr);
308       exit(1);
309     }
310 
311     LineBuffers[1] = LineBuffers[0] + DotBytes * header->cupsWidth;
312     DotBit         = 128;
313     LineCount      = 0;
314     EvenOffset     = 0;
315     OddOffset      = 0;
316   }
317 }
318 
319 
320 /*
321  * 'EndPage()' - Finish a page of graphics.
322  */
323 
324 void
EndPage(const cups_page_header2_t * header)325 EndPage(
326     const cups_page_header2_t *header)	/* I - Page header */
327 {
328   if (DotBytes && header)
329   {
330    /*
331     * Flush remaining graphics as needed...
332     */
333 
334     if (!Shingling)
335     {
336       if (DotBit < 128 || EvenOffset)
337         OutputRows(header, 0);
338     }
339     else if (OddOffset > EvenOffset)
340     {
341       OutputRows(header, 1);
342       OutputRows(header, 0);
343     }
344     else
345     {
346       OutputRows(header, 0);
347       OutputRows(header, 1);
348     }
349   }
350 
351  /*
352   * Eject the current page...
353   */
354 
355   putchar(12);				/* Form feed */
356   fflush(stdout);
357 
358  /*
359   * Free memory...
360   */
361 
362   free(Planes[0]);
363 
364   if (CompBuffer)
365     free(CompBuffer);
366 
367   if (DotBytes)
368     free(LineBuffers[0]);
369 }
370 
371 
372 /*
373  * 'Shutdown()' - Shutdown the printer.
374  */
375 
376 void
Shutdown(void)377 Shutdown(void)
378 {
379  /*
380   * Send a reset sequence.
381   */
382 
383   printf("\033@");
384 }
385 
386 
387 /*
388  * 'CancelJob()' - Cancel the current job...
389  */
390 
391 void
CancelJob(int sig)392 CancelJob(int sig)			/* I - Signal */
393 {
394   (void)sig;
395 
396   Canceled = 1;
397 }
398 
399 
400 /*
401  * 'CompressData()' - Compress a line of graphics.
402  */
403 
404 void
CompressData(const unsigned char * line,unsigned length,unsigned plane,unsigned type,unsigned xstep,unsigned ystep)405 CompressData(const unsigned char *line,	/* I - Data to compress */
406              unsigned            length,/* I - Number of bytes */
407 	     unsigned            plane,	/* I - Color plane */
408 	     unsigned            type,	/* I - Type of compression */
409 	     unsigned            xstep,	/* I - X resolution */
410 	     unsigned            ystep)	/* I - Y resolution */
411 {
412   const unsigned char	*line_ptr,	/* Current byte pointer */
413         		*line_end,	/* End-of-line byte pointer */
414         		*start;		/* Start of compression sequence */
415   unsigned char      	*comp_ptr,	/* Pointer into compression buffer */
416 			temp;		/* Current byte */
417   int   	        count;		/* Count of bytes for output */
418   static int		ctable[6] = { 0, 2, 1, 4, 18, 17 };
419 					/* KCMYcm color values */
420 
421 
422  /*
423   * Setup pointers...
424   */
425 
426   line_ptr = line;
427   line_end = line + length;
428 
429  /*
430   * Do depletion for 720 DPI printing...
431   */
432 
433   if (ystep == 5)
434   {
435     for (comp_ptr = (unsigned char *)line; comp_ptr < line_end;)
436     {
437      /*
438       * Grab the current byte...
439       */
440 
441       temp = *comp_ptr;
442 
443      /*
444       * Check adjacent bits...
445       */
446 
447       if ((temp & 0xc0) == 0xc0)
448         temp &= 0xbf;
449       if ((temp & 0x60) == 0x60)
450         temp &= 0xdf;
451       if ((temp & 0x30) == 0x30)
452         temp &= 0xef;
453       if ((temp & 0x18) == 0x18)
454         temp &= 0xf7;
455       if ((temp & 0x0c) == 0x0c)
456         temp &= 0xfb;
457       if ((temp & 0x06) == 0x06)
458         temp &= 0xfd;
459       if ((temp & 0x03) == 0x03)
460         temp &= 0xfe;
461 
462       *comp_ptr++ = temp;
463 
464      /*
465       * Check the last bit in the current byte and the first bit in the
466       * next byte...
467       */
468 
469       if ((temp & 0x01) && comp_ptr < line_end && *comp_ptr & 0x80)
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, header->cupsWidth * 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