Home | History | Annotate | Download | only in filter
      1 /*
      2  * EPSON ESC/P and ESC/P2 filter for CUPS.
      3  *
      4  * Copyright 2007-2015 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
     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
    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 * (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
    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
    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
    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
    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
    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
    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 */
    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