4 * EPSON ESC/P and ESC/P2 filter for the Common UNIX Printing System
7 * Copyright 1993-2005 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Easy Software Products and are protected by Federal
11 * copyright law. Distribution and use rights are outlined in the file
12 * "LICENSE.txt" which should have been included with this file. If this
13 * file is missing or damaged please contact Easy Software Products
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636 USA
21 * Voice: (301) 373-9600
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
25 * This file is subject to the Apple OS-Developed Software exception.
29 * Setup() - Prepare the printer for printing.
30 * StartPage() - Start a page of graphics.
31 * EndPage() - Finish a page of graphics.
32 * Shutdown() - Shutdown the printer.
33 * CompressData() - Compress a line of graphics.
34 * OutputLine() - Output a line of graphics.
35 * main() - Main entry and processing of driver.
39 * Include necessary headers...
42 #include <cups/cups.h>
44 #include <cups/string.h>
60 #define EPSON_ICOLOR 4
61 #define EPSON_IPHOTO 5
68 #define pwrite(s,n) fwrite((s), 1, (n), stdout)
75 unsigned char *Planes
[6], /* Output buffers */
76 *CompBuffer
, /* Compression buffer */
77 *LineBuffers
[2]; /* Line bitmap buffers */
78 int Model
, /* Model number */
79 NumPlanes
, /* Number of color planes */
80 Feed
, /* Number of lines to skip */
81 EjectPage
; /* Eject the page when done? */
82 int DotBit
, /* Bit in buffers */
83 DotBytes
, /* # bytes in a dot column */
84 DotColumns
, /* # columns in 1/60 inch */
85 LineCount
, /* # of lines processed */
86 EvenOffset
, /* Offset into 'even' buffers */
87 OddOffset
, /* Offset into 'odd' buffers */
88 Shingling
; /* Shingle output? */
96 void StartPage(const ppd_file_t
*ppd
, const cups_page_header_t
*header
);
97 void EndPage(const cups_page_header_t
*header
);
100 void CancelJob(int sig
);
101 void CompressData(const unsigned char *line
, int length
, int plane
,
102 int type
, int xstep
, int ystep
);
103 void OutputLine(const cups_page_header_t
*header
);
104 void OutputRows(const cups_page_header_t
*header
, int row
);
108 * 'Setup()' - Prepare the printer for printing.
114 const char *device_uri
; /* The device for the printer... */
118 * EPSON USB printers need an additional command issued at the
119 * beginning of each job to exit from "packet" mode...
122 if ((device_uri
= getenv("DEVICE_URI")) != NULL
&&
123 strncmp(device_uri
, "usb:", 4) == 0 && Model
>= EPSON_ICOLOR
)
124 pwrite("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
129 * 'StartPage()' - Start a page of graphics.
133 StartPage(const ppd_file_t
*ppd
, /* I - PPD file */
134 const cups_page_header_t
*header
) /* I - Page header */
136 int n
, t
; /* Numbers */
137 int plane
; /* Looping var */
138 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
139 struct sigaction action
; /* Actions for POSIX signals */
140 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
144 * Register a signal handler to eject the current page if the
148 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
149 sigset(SIGTERM
, CancelJob
);
150 #elif defined(HAVE_SIGACTION)
151 memset(&action
, 0, sizeof(action
));
153 sigemptyset(&action
.sa_mask
);
154 action
.sa_handler
= CancelJob
;
155 sigaction(SIGTERM
, &action
, NULL
);
157 signal(SIGTERM
, CancelJob
);
158 #endif /* HAVE_SIGSET */
161 * Send a reset sequence.
164 if (ppd
->nickname
&& strstr(ppd
->nickname
, "OKIDATA") != NULL
)
165 printf("\033{A"); /* Set EPSON emulation mode */
170 * See which type of printer we are using...
173 EjectPage
= header
->Margins
[0] || header
->Margins
[1];
175 switch (ppd
->model_number
)
179 printf("\033P\022"); /* Set 10 CPI */
181 if (header
->HWResolution
[0] == 360 || header
->HWResolution
[0] == 240)
183 printf("\033x1"); /* LQ printing */
184 printf("\033U1"); /* Unidirectional */
188 printf("\033x0"); /* Draft printing */
189 printf("\033U0"); /* Bidirectional */
192 printf("\033l%c\033Q%c", 0, /* Side margins */
193 (int)(10.0 * header
->PageSize
[0] / 72.0 + 0.5));
194 printf("\033C%c%c", 0, /* Page length */
195 (int)(header
->PageSize
[1] / 72.0 + 0.5));
196 printf("\033N%c", 0); /* Bottom margin */
197 printf("\033O"); /* No perforation skip */
200 * Setup various buffer limits...
203 DotBytes
= header
->cupsRowCount
/ 8;
204 DotColumns
= header
->HWResolution
[0] / 60;
207 if (ppd
->model_number
== EPSON_9PIN
)
208 printf("\033\063\030"); /* Set line feed */
210 switch (header
->HWResolution
[0])
215 printf("\033\063\030"); /* Set line feed */
222 if (header
->HWResolution
[1] == 180)
223 printf("\033\063\010");/* Set line feed */
225 printf("\033+\010"); /* Set line feed */
232 * Set graphics mode...
235 pwrite("\033(G\001\000\001", 6); /* Graphics mode */
238 * Set the media size...
241 if (Model
< EPSON_ICOLOR
)
243 pwrite("\033(U\001\000", 5); /* Resolution/units */
244 putchar(3600 / header
->HWResolution
[1]);
248 pwrite("\033(U\005\000", 5);
249 putchar(1440 / header
->HWResolution
[1]);
250 putchar(1440 / header
->HWResolution
[1]);
251 putchar(1440 / header
->HWResolution
[0]);
252 putchar(0xa0); /* n/1440ths... */
256 n
= header
->PageSize
[1] * header
->HWResolution
[1] / 72.0;
258 pwrite("\033(C\002\000", 5); /* Page length */
262 t
= (ppd
->sizes
[1].length
- ppd
->sizes
[1].top
) *
263 header
->HWResolution
[1] / 72.0;
265 pwrite("\033(c\004\000", 5); /* Top & bottom margins */
271 if (header
->HWResolution
[1] == 720)
273 pwrite("\033(i\001\000\001", 6); /* Microweave */
274 pwrite("\033(e\002\000\000\001", 7); /* Small dots */
277 pwrite("\033(V\002\000\000\000", 7); /* Set absolute position 0 */
289 if (header
->cupsColorSpace
== CUPS_CSPACE_CMY
)
291 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
293 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMYcm
)
298 Feed
= 0; /* No blank lines yet */
301 * Allocate memory for a line/row of graphics...
304 Planes
[0] = malloc(header
->cupsBytesPerLine
);
305 for (plane
= 1; plane
< NumPlanes
; plane
++)
306 Planes
[plane
] = Planes
[0] + plane
* header
->cupsBytesPerLine
/ NumPlanes
;
308 if (header
->cupsCompression
|| DotBytes
)
309 CompBuffer
= calloc(2, header
->cupsWidth
);
315 LineBuffers
[0] = calloc(DotBytes
, header
->cupsWidth
* (Shingling
+ 1));
316 LineBuffers
[1] = LineBuffers
[0] + DotBytes
* header
->cupsWidth
;
326 * 'EndPage()' - Finish a page of graphics.
330 EndPage(const cups_page_header_t
*header
) /* I - Page header */
332 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
333 struct sigaction action
; /* Actions for POSIX signals */
334 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
337 if (DotBytes
&& header
)
340 * Flush remaining graphics as needed...
345 if (DotBit
< 128 || EvenOffset
)
346 OutputRows(header
, 0);
348 else if (OddOffset
> EvenOffset
)
350 OutputRows(header
, 1);
351 OutputRows(header
, 0);
355 OutputRows(header
, 0);
356 OutputRows(header
, 1);
361 * Eject the current page...
365 putchar(12); /* Form feed */
369 * Unregister the signal handler...
372 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
373 sigset(SIGTERM
, SIG_IGN
);
374 #elif defined(HAVE_SIGACTION)
375 memset(&action
, 0, sizeof(action
));
377 sigemptyset(&action
.sa_mask
);
378 action
.sa_handler
= SIG_IGN
;
379 sigaction(SIGTERM
, &action
, NULL
);
381 signal(SIGTERM
, SIG_IGN
);
382 #endif /* HAVE_SIGSET */
394 free(LineBuffers
[0]);
399 * 'Shutdown()' - Shutdown the printer.
406 * Send a reset sequence.
414 * 'CancelJob()' - Cancel the current job...
418 CancelJob(int sig
) /* I - Signal */
420 int i
; /* Looping var */
426 * Send out lots of NUL bytes to clear out any pending raster data...
430 i
= DotBytes
* 360 * 8;
438 * End the current page and exit...
449 * 'CompressData()' - Compress a line of graphics.
453 CompressData(const unsigned char *line
, /* I - Data to compress */
454 int length
,/* I - Number of bytes */
455 int plane
, /* I - Color plane */
456 int type
, /* I - Type of compression */
457 int xstep
, /* I - X resolution */
458 int ystep
) /* I - Y resolution */
460 const unsigned char *line_ptr
, /* Current byte pointer */
461 *line_end
, /* End-of-line byte pointer */
462 *start
; /* Start of compression sequence */
463 unsigned char *comp_ptr
, /* Pointer into compression buffer */
464 temp
; /* Current byte */
465 int count
; /* Count of bytes for output */
466 static int ctable
[6] = { 0, 2, 1, 4, 18, 17 };
467 /* KCMYcm color values */
475 line_end
= line
+ length
;
478 * Do depletion for 720 DPI printing...
483 for (comp_ptr
= (unsigned char *)line
; comp_ptr
< line_end
;)
486 * Grab the current byte...
492 * Check adjacent bits...
495 if ((temp
& 0xc0) == 0xc0)
497 if ((temp
& 0x60) == 0x60)
499 if ((temp
& 0x30) == 0x30)
501 if ((temp
& 0x18) == 0x18)
503 if ((temp
& 0x0c) == 0x0c)
505 if ((temp
& 0x06) == 0x06)
507 if ((temp
& 0x03) == 0x03)
513 * Check the last bit in the current byte and the first bit in the
517 if ((temp
& 0x01) && comp_ptr
< line_end
&& *comp_ptr
& 0x80)
526 * Do no compression...
532 * Do TIFF pack-bits encoding...
535 comp_ptr
= CompBuffer
;
537 while (line_ptr
< line_end
)
539 if ((line_ptr
+ 1) >= line_end
)
542 * Single byte on the end...
546 *comp_ptr
++ = *line_ptr
++;
548 else if (line_ptr
[0] == line_ptr
[1])
551 * Repeated sequence...
557 while (line_ptr
< (line_end
- 1) &&
558 line_ptr
[0] == line_ptr
[1] &&
565 *comp_ptr
++ = 257 - count
;
566 *comp_ptr
++ = *line_ptr
++;
571 * Non-repeated sequence...
578 while (line_ptr
< (line_end
- 1) &&
579 line_ptr
[0] != line_ptr
[1] &&
586 *comp_ptr
++ = count
- 1;
588 memcpy(comp_ptr
, start
, count
);
593 line_ptr
= CompBuffer
;
598 putchar(0x0d); /* Move print head to left margin */
600 if (Model
< EPSON_ICOLOR
)
603 * Do graphics the "old" way...
613 printf("\033(r%c%c%c%c", 2, 0, 1, ctable
[plane
] & 15);
614 /* Set extended color */
615 else if (NumPlanes
== 3)
616 printf("\033r%c", ctable
[plane
+ 1]);
619 printf("\033r%c", ctable
[plane
]); /* Set color */
623 * Send a raster plane...
627 printf("\033."); /* Raster graphics */
633 putchar(length
>> 8);
638 * Do graphics the "new" way...
642 putchar(ctable
[plane
]);
645 putchar(length
& 255);
646 putchar(length
>> 8);
651 pwrite(line_ptr
, line_end
- line_ptr
);
657 * 'OutputLine()' - Output a line of graphics.
661 OutputLine(const cups_page_header_t
*header
) /* I - Page header */
663 if (header
->cupsRowCount
)
666 unsigned char *tempptr
,
671 const unsigned char *pixel
;
676 * Collect bitmap data in the line buffers and write after each buffer.
679 for (x
= header
->cupsWidth
, bit
= 128, pixel
= Planes
[0],
701 * Copy the holding buffer to the output buffer, shingling as necessary...
704 if (Shingling
&& LineCount
!= 0)
707 * Shingle the output...
712 evenptr
= LineBuffers
[1] + OddOffset
;
713 oddptr
= LineBuffers
[0] + EvenOffset
+ DotBytes
;
717 evenptr
= LineBuffers
[0] + EvenOffset
;
718 oddptr
= LineBuffers
[1] + OddOffset
+ DotBytes
;
721 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
;
723 width
-= 2, tempptr
+= 2, oddptr
+= DotBytes
* 2,
724 evenptr
+= DotBytes
* 2)
726 evenptr
[0] = tempptr
[0];
727 oddptr
[0] = tempptr
[1];
733 * Don't shingle the output...
736 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
,
737 evenptr
= LineBuffers
[0] + EvenOffset
;
739 width
--, tempptr
++, evenptr
+= DotBytes
)
740 *evenptr
= tempptr
[0];
743 if (Shingling
&& LineCount
!= 0)
748 if (EvenOffset
== DotBytes
)
751 OutputRows(header
, 0);
754 if (OddOffset
== DotBytes
)
757 OutputRows(header
, 1);
764 if (EvenOffset
== DotBytes
)
767 OutputRows(header
, 0);
774 memset(CompBuffer
, 0, header
->cupsWidth
);
779 int plane
; /* Current plane */
780 int bytes
; /* Bytes per plane */
781 int xstep
, ystep
; /* X & Y resolutions */
785 * Write a single line of bitmap data as needed...
788 xstep
= 3600 / header
->HWResolution
[0];
789 ystep
= 3600 / header
->HWResolution
[1];
790 bytes
= header
->cupsBytesPerLine
/ NumPlanes
;
792 for (plane
= 0; plane
< NumPlanes
; plane
++)
798 if (!Planes
[plane
][0] &&
799 memcmp(Planes
[plane
], Planes
[plane
] + 1, bytes
- 1) == 0)
803 * Output whitespace as needed...
808 pwrite("\033(v\002\000", 5); /* Relative vertical position */
815 CompressData(Planes
[plane
], bytes
, plane
, header
->cupsCompression
, xstep
,
825 * 'OutputRows()' - Output 8, 24, or 48 rows.
829 OutputRows(const cups_page_header_t
*header
, /* I - Page image header */
830 int row
) /* I - Row number (0 or 1) */
832 unsigned i
, n
; /* Looping vars */
833 int dot_count
, /* Number of bytes to print */
834 dot_min
; /* Minimum number of bytes */
835 unsigned char *dot_ptr
, /* Pointer to print data */
836 *ptr
; /* Current data */
839 dot_min
= DotBytes
* DotColumns
;
841 if (LineBuffers
[row
][0] != 0 ||
842 memcmp(LineBuffers
[row
], LineBuffers
[row
] + 1,
843 header
->cupsWidth
* DotBytes
- 1))
846 * Skip leading space...
850 dot_count
= header
->cupsWidth
* DotBytes
;
851 dot_ptr
= LineBuffers
[row
];
853 while (dot_count
>= dot_min
&& dot_ptr
[0] == 0 &&
854 memcmp(dot_ptr
, dot_ptr
+ 1, dot_min
- 1) == 0)
858 dot_count
-= dot_min
;
862 * Skip trailing space...
865 while (dot_count
>= dot_min
&& dot_ptr
[dot_count
- dot_min
] == 0 &&
866 memcmp(dot_ptr
+ dot_count
- dot_min
,
867 dot_ptr
+ dot_count
- dot_min
+ 1, dot_min
- 1) == 0)
868 dot_count
-= dot_min
;
871 * Position print head for printing...
885 * Start bitmap graphics for this line...
888 printf("\033*"); /* Select bit image */
889 switch (header
->HWResolution
[0])
891 case 60 : /* 60x60/72 DPI gfx */
894 case 120 : /* 120x60/72 DPI gfx */
897 case 180 : /* 180 DPI gfx */
900 case 240 : /* 240x72 DPI gfx */
903 case 360 : /* 360x180/360 DPI gfx */
904 if (header
->HWResolution
[1] == 180)
906 if (Shingling
&& LineCount
!= 0)
907 putchar(40); /* 360x180 fast */
909 putchar(41); /* 360x180 slow */
913 if (Shingling
&& LineCount
!= 0)
914 putchar(72); /* 360x360 fast */
916 putchar(73); /* 360x360 slow */
921 n
= (unsigned)dot_count
/ DotBytes
;
926 * Write the graphics data...
929 if (header
->HWResolution
[0] == 120 ||
930 header
->HWResolution
[0] == 240)
933 * Need to interleave the dots to avoid hosing the print head...
936 for (n
= dot_count
/ 2, ptr
= dot_ptr
; n
> 0; n
--, ptr
+= 2)
943 * Move the head back and print the odd bytes...
956 if (header
->HWResolution
[0] == 120)
957 printf("\033*\001"); /* Select bit image */
959 printf("\033*\003"); /* Select bit image */
961 n
= (unsigned)dot_count
/ DotBytes
;
965 for (n
= dot_count
/ 2, ptr
= dot_ptr
+ 1; n
> 0; n
--, ptr
+= 2)
972 pwrite(dot_ptr
, dot_count
);
981 if (Shingling
&& row
== 1)
983 if (header
->HWResolution
[1] == 360)
992 * Clear the buffer...
995 memset(LineBuffers
[row
], 0, header
->cupsWidth
* DotBytes
);
1000 * 'main()' - Main entry and processing of driver.
1003 int /* O - Exit status */
1004 main(int argc
, /* I - Number of command-line arguments */
1005 char *argv
[]) /* I - Command-line arguments */
1007 int fd
; /* File descriptor */
1008 cups_raster_t
*ras
; /* Raster stream for printing */
1009 cups_page_header_t header
; /* Page header from file */
1010 ppd_file_t
*ppd
; /* PPD file */
1011 int page
; /* Current page */
1012 int y
; /* Current line */
1016 * Make sure status messages are not buffered...
1019 setbuf(stderr
, NULL
);
1022 * Check command-line...
1025 if (argc
< 6 || argc
> 7)
1028 * We don't have the correct number of arguments; write an error message
1032 fputs("ERROR: rastertoepson job-id user title copies options [file]\n", stderr
);
1037 * Open the page stream...
1042 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
1044 perror("ERROR: Unable to open raster file - ");
1052 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
1055 * Initialize the print device...
1058 ppd
= ppdOpenFile(getenv("PPD"));
1060 Model
= ppd
->model_number
;
1065 * Process pages as needed...
1070 while (cupsRasterReadHeader(ras
, &header
))
1073 * Write a status message with the page number and number of copies.
1078 fprintf(stderr
, "PAGE: %d %d\n", page
, header
.NumCopies
);
1084 StartPage(ppd
, &header
);
1087 * Loop for each line on the page...
1090 for (y
= 0; y
< header
.cupsHeight
; y
++)
1093 * Let the user know how far we have progressed...
1097 fprintf(stderr
, "INFO: Printing page %d, %d%% complete...\n", page
,
1098 100 * y
/ header
.cupsHeight
);
1101 * Read a line of graphics...
1104 if (cupsRasterReadPixels(ras
, Planes
[0], header
.cupsBytesPerLine
) < 1)
1108 * Write it to the printer...
1111 OutputLine(&header
);
1122 * Shutdown the printer...
1130 * Close the raster stream...
1133 cupsRasterClose(ras
);
1138 * If no pages were printed, send an error message...
1142 fputs("ERROR: No pages found!\n", stderr
);
1144 fputs("INFO: " CUPS_SVERSION
" is ready to print.\n", stderr
);