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