4 * EPSON ESC/P and ESC/P2 filter for CUPS.
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1993-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * Include necessary headers...
22 #include <cups/cups.h>
24 #include <cups/string-private.h>
25 #include <cups/language-private.h>
26 #include <cups/raster.h>
40 #define EPSON_ICOLOR 4
41 #define EPSON_IPHOTO 5
48 #define pwrite(s,n) fwrite((s), 1, (n), stdout)
55 unsigned char *Planes
[6], /* Output buffers */
56 *CompBuffer
, /* Compression buffer */
57 *LineBuffers
[2]; /* Line bitmap buffers */
58 int Model
, /* Model number */
59 EjectPage
, /* Eject the page when done? */
60 Shingling
, /* Shingle output? */
61 Canceled
; /* Has the current job been canceled? */
62 unsigned NumPlanes
, /* Number of color planes */
63 Feed
, /* Number of lines to skip */
64 DotBit
, /* Bit in buffers */
65 DotBytes
, /* # bytes in a dot column */
66 DotColumns
, /* # columns in 1/60 inch */
67 LineCount
, /* # of lines processed */
68 EvenOffset
, /* Offset into 'even' buffers */
69 OddOffset
; /* Offset into 'odd' buffers */
77 void StartPage(const ppd_file_t
*ppd
, const cups_page_header2_t
*header
);
78 void EndPage(const cups_page_header2_t
*header
);
81 void CancelJob(int sig
);
82 void CompressData(const unsigned char *line
, unsigned length
, unsigned plane
,
83 unsigned type
, unsigned xstep
, unsigned ystep
);
84 void OutputLine(const cups_page_header2_t
*header
);
85 void OutputRows(const cups_page_header2_t
*header
, int row
);
89 * 'Setup()' - Prepare the printer for printing.
95 const char *device_uri
; /* The device for the printer... */
99 * EPSON USB printers need an additional command issued at the
100 * beginning of each job to exit from "packet" mode...
103 if ((device_uri
= getenv("DEVICE_URI")) != NULL
&&
104 strncmp(device_uri
, "usb:", 4) == 0 && Model
>= EPSON_ICOLOR
)
105 pwrite("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
110 * 'StartPage()' - Start a page of graphics.
115 const ppd_file_t
*ppd
, /* I - PPD file */
116 const cups_page_header2_t
*header
) /* I - Page header */
118 int n
, t
; /* Numbers */
119 unsigned plane
; /* Looping var */
123 * Send a reset sequence.
126 if (ppd
&& ppd
->nickname
&& strstr(ppd
->nickname
, "OKIDATA") != NULL
)
127 printf("\033{A"); /* Set EPSON emulation mode */
132 * See which type of printer we are using...
139 printf("\033P\022"); /* Set 10 CPI */
141 if (header
->HWResolution
[0] == 360 || header
->HWResolution
[0] == 240)
143 printf("\033x1"); /* LQ printing */
144 printf("\033U1"); /* Unidirectional */
148 printf("\033x0"); /* Draft printing */
149 printf("\033U0"); /* Bidirectional */
152 printf("\033l%c\033Q%c", 0, /* Side margins */
153 (int)(10.0 * header
->PageSize
[0] / 72.0 + 0.5));
154 printf("\033\062\033C%c", /* Page length in 1/6th inches */
155 (int)(header
->PageSize
[1] / 12.0 + 0.5));
156 printf("\033N%c", 0); /* Bottom margin */
157 printf("\033O"); /* No perforation skip */
160 * Setup various buffer limits...
163 DotBytes
= header
->cupsRowCount
/ 8;
164 DotColumns
= header
->HWResolution
[0] / 60;
167 if (Model
== EPSON_9PIN
)
168 printf("\033\063\030"); /* Set line feed */
170 switch (header
->HWResolution
[0])
175 printf("\033\063\030"); /* Set line feed */
182 if (header
->HWResolution
[1] == 180)
183 printf("\033\063\010");/* Set line feed */
185 printf("\033+\010"); /* Set line feed */
192 * Set graphics mode...
195 pwrite("\033(G\001\000\001", 6); /* Graphics mode */
198 * Set the media size...
201 if (Model
< EPSON_ICOLOR
)
203 pwrite("\033(U\001\000", 5); /* Resolution/units */
204 putchar(3600 / header
->HWResolution
[1]);
208 pwrite("\033(U\005\000", 5);
209 putchar(1440 / header
->HWResolution
[1]);
210 putchar(1440 / header
->HWResolution
[1]);
211 putchar(1440 / header
->HWResolution
[0]);
212 putchar(0xa0); /* n/1440ths... */
216 n
= (int)(header
->PageSize
[1] * header
->HWResolution
[1] / 72.0);
218 pwrite("\033(C\002\000", 5); /* Page length */
223 t
= (int)((ppd
->sizes
[1].length
- ppd
->sizes
[1].top
) * header
->HWResolution
[1] / 72.0);
227 pwrite("\033(c\004\000", 5); /* Top & bottom margins */
233 if (header
->HWResolution
[1] == 720)
235 pwrite("\033(i\001\000\001", 6); /* Microweave */
236 pwrite("\033(e\002\000\000\001", 7); /* Small dots */
239 pwrite("\033(V\002\000\000\000", 7); /* Set absolute position 0 */
251 if (header
->cupsColorSpace
== CUPS_CSPACE_CMY
)
253 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
255 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMYcm
)
260 Feed
= 0; /* No blank lines yet */
263 * Allocate memory for a line/row of graphics...
266 if ((Planes
[0] = malloc(header
->cupsBytesPerLine
)) == NULL
)
268 fputs("ERROR: Unable to allocate memory\n", stderr
);
272 for (plane
= 1; plane
< NumPlanes
; plane
++)
273 Planes
[plane
] = Planes
[0] + plane
* header
->cupsBytesPerLine
/ NumPlanes
;
275 if (header
->cupsCompression
|| DotBytes
)
277 if ((CompBuffer
= calloc(2, header
->cupsWidth
)) == NULL
)
279 fputs("ERROR: Unable to allocate memory\n", stderr
);
288 if ((LineBuffers
[0] = calloc((size_t)DotBytes
, header
->cupsWidth
* (size_t)(Shingling
+ 1))) == NULL
)
290 fputs("ERROR: Unable to allocate memory\n", stderr
);
294 LineBuffers
[1] = LineBuffers
[0] + DotBytes
* header
->cupsWidth
;
304 * 'EndPage()' - Finish a page of graphics.
309 const cups_page_header2_t
*header
) /* I - Page header */
311 if (DotBytes
&& header
)
314 * Flush remaining graphics as needed...
319 if (DotBit
< 128 || EvenOffset
)
320 OutputRows(header
, 0);
322 else if (OddOffset
> EvenOffset
)
324 OutputRows(header
, 1);
325 OutputRows(header
, 0);
329 OutputRows(header
, 0);
330 OutputRows(header
, 1);
335 * Eject the current page...
338 putchar(12); /* Form feed */
351 free(LineBuffers
[0]);
356 * 'Shutdown()' - Shutdown the printer.
363 * Send a reset sequence.
371 * 'CancelJob()' - Cancel the current job...
375 CancelJob(int sig
) /* I - Signal */
384 * 'CompressData()' - Compress a line of graphics.
388 CompressData(const unsigned char *line
, /* I - Data to compress */
389 unsigned length
,/* I - Number of bytes */
390 unsigned plane
, /* I - Color plane */
391 unsigned type
, /* I - Type of compression */
392 unsigned xstep
, /* I - X resolution */
393 unsigned ystep
) /* I - Y resolution */
395 const unsigned char *line_ptr
, /* Current byte pointer */
396 *line_end
, /* End-of-line byte pointer */
397 *start
; /* Start of compression sequence */
398 unsigned char *comp_ptr
, /* Pointer into compression buffer */
399 temp
; /* Current byte */
400 int count
; /* Count of bytes for output */
401 static int ctable
[6] = { 0, 2, 1, 4, 18, 17 };
402 /* KCMYcm color values */
410 line_end
= line
+ length
;
413 * Do depletion for 720 DPI printing...
418 for (comp_ptr
= (unsigned char *)line
; comp_ptr
< line_end
;)
421 * Grab the current byte...
427 * Check adjacent bits...
430 if ((temp
& 0xc0) == 0xc0)
432 if ((temp
& 0x60) == 0x60)
434 if ((temp
& 0x30) == 0x30)
436 if ((temp
& 0x18) == 0x18)
438 if ((temp
& 0x0c) == 0x0c)
440 if ((temp
& 0x06) == 0x06)
442 if ((temp
& 0x03) == 0x03)
448 * Check the last bit in the current byte and the first bit in the
452 if ((temp
& 0x01) && comp_ptr
< line_end
&& *comp_ptr
& 0x80)
461 * Do no compression...
467 * Do TIFF pack-bits encoding...
470 comp_ptr
= CompBuffer
;
472 while (line_ptr
< line_end
)
474 if ((line_ptr
+ 1) >= line_end
)
477 * Single byte on the end...
481 *comp_ptr
++ = *line_ptr
++;
483 else if (line_ptr
[0] == line_ptr
[1])
486 * Repeated sequence...
492 while (line_ptr
< (line_end
- 1) &&
493 line_ptr
[0] == line_ptr
[1] &&
500 *comp_ptr
++ = (unsigned char)(257 - count
);
501 *comp_ptr
++ = *line_ptr
++;
506 * Non-repeated sequence...
513 while (line_ptr
< (line_end
- 1) &&
514 line_ptr
[0] != line_ptr
[1] &&
521 *comp_ptr
++ = (unsigned char)(count
- 1);
523 memcpy(comp_ptr
, start
, count
);
528 line_ptr
= CompBuffer
;
533 putchar(0x0d); /* Move print head to left margin */
535 if (Model
< EPSON_ICOLOR
)
538 * Do graphics the "old" way...
548 printf("\033(r%c%c%c%c", 2, 0, 1, ctable
[plane
] & 15);
549 /* Set extended color */
550 else if (NumPlanes
== 3)
551 printf("\033r%c", ctable
[plane
+ 1]);
554 printf("\033r%c", ctable
[plane
]); /* Set color */
558 * Send a raster plane...
562 printf("\033."); /* Raster graphics */
567 putchar((int)length
);
568 putchar((int)(length
>> 8));
573 * Do graphics the "new" way...
577 putchar(ctable
[plane
]);
580 putchar((int)length
);
581 putchar((int)(length
>> 8));
586 pwrite(line_ptr
, (size_t)(line_end
- line_ptr
));
592 * 'OutputLine()' - Output a line of graphics.
597 const cups_page_header2_t
*header
) /* I - Page header */
599 if (header
->cupsRowCount
)
602 unsigned char *tempptr
,
607 const unsigned char *pixel
;
612 * Collect bitmap data in the line buffers and write after each buffer.
615 for (x
= header
->cupsWidth
, bit
= 128, pixel
= Planes
[0],
637 * Copy the holding buffer to the output buffer, shingling as necessary...
640 if (Shingling
&& LineCount
!= 0)
643 * Shingle the output...
648 evenptr
= LineBuffers
[1] + OddOffset
;
649 oddptr
= LineBuffers
[0] + EvenOffset
+ DotBytes
;
653 evenptr
= LineBuffers
[0] + EvenOffset
;
654 oddptr
= LineBuffers
[1] + OddOffset
+ DotBytes
;
657 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
;
659 width
-= 2, tempptr
+= 2, oddptr
+= DotBytes
* 2,
660 evenptr
+= DotBytes
* 2)
662 evenptr
[0] = tempptr
[0];
663 oddptr
[0] = tempptr
[1];
669 * Don't shingle the output...
672 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
,
673 evenptr
= LineBuffers
[0] + EvenOffset
;
675 width
--, tempptr
++, evenptr
+= DotBytes
)
676 *evenptr
= tempptr
[0];
679 if (Shingling
&& LineCount
!= 0)
684 if (EvenOffset
== DotBytes
)
687 OutputRows(header
, 0);
690 if (OddOffset
== DotBytes
)
693 OutputRows(header
, 1);
700 if (EvenOffset
== DotBytes
)
703 OutputRows(header
, 0);
710 memset(CompBuffer
, 0, header
->cupsWidth
);
715 unsigned plane
; /* Current plane */
716 unsigned bytes
; /* Bytes per plane */
717 unsigned xstep
, ystep
; /* X & Y resolutions */
720 * Write a single line of bitmap data as needed...
723 xstep
= 3600 / header
->HWResolution
[0];
724 ystep
= 3600 / header
->HWResolution
[1];
725 bytes
= header
->cupsBytesPerLine
/ NumPlanes
;
727 for (plane
= 0; plane
< NumPlanes
; plane
++)
733 if (!Planes
[plane
][0] &&
734 memcmp(Planes
[plane
], Planes
[plane
] + 1, (size_t)bytes
- 1) == 0)
738 * Output whitespace as needed...
743 pwrite("\033(v\002\000", 5); /* Relative vertical position */
745 putchar((int)(Feed
>> 8));
750 CompressData(Planes
[plane
], bytes
, plane
, header
->cupsCompression
, xstep
, ystep
);
759 * 'OutputRows()' - Output 8, 24, or 48 rows.
764 const cups_page_header2_t
*header
, /* I - Page image header */
765 int row
) /* I - Row number (0 or 1) */
767 unsigned i
, n
, /* Looping vars */
768 dot_count
, /* Number of bytes to print */
769 dot_min
; /* Minimum number of bytes */
770 unsigned char *dot_ptr
, /* Pointer to print data */
771 *ptr
; /* Current data */
774 dot_min
= DotBytes
* DotColumns
;
776 if (LineBuffers
[row
][0] != 0 ||
777 memcmp(LineBuffers
[row
], LineBuffers
[row
] + 1, header
->cupsWidth
* DotBytes
- 1))
780 * Skip leading space...
784 dot_count
= header
->cupsWidth
* DotBytes
;
785 dot_ptr
= LineBuffers
[row
];
787 while (dot_count
>= dot_min
&& dot_ptr
[0] == 0 &&
788 memcmp(dot_ptr
, dot_ptr
+ 1, dot_min
- 1) == 0)
792 dot_count
-= dot_min
;
796 * Skip trailing space...
799 while (dot_count
>= dot_min
&& dot_ptr
[dot_count
- dot_min
] == 0 &&
800 memcmp(dot_ptr
+ dot_count
- dot_min
,
801 dot_ptr
+ dot_count
- dot_min
+ 1, dot_min
- 1) == 0)
802 dot_count
-= dot_min
;
805 * Position print head for printing...
819 * Start bitmap graphics for this line...
822 printf("\033*"); /* Select bit image */
823 switch (header
->HWResolution
[0])
825 case 60 : /* 60x60/72 DPI gfx */
828 case 120 : /* 120x60/72 DPI gfx */
831 case 180 : /* 180 DPI gfx */
834 case 240 : /* 240x72 DPI gfx */
837 case 360 : /* 360x180/360 DPI gfx */
838 if (header
->HWResolution
[1] == 180)
840 if (Shingling
&& LineCount
!= 0)
841 putchar(40); /* 360x180 fast */
843 putchar(41); /* 360x180 slow */
847 if (Shingling
&& LineCount
!= 0)
848 putchar(72); /* 360x360 fast */
850 putchar(73); /* 360x360 slow */
855 n
= dot_count
/ DotBytes
;
860 * Write the graphics data...
863 if (header
->HWResolution
[0] == 120 ||
864 header
->HWResolution
[0] == 240)
867 * Need to interleave the dots to avoid hosing the print head...
870 for (n
= dot_count
/ 2, ptr
= dot_ptr
; n
> 0; n
--, ptr
+= 2)
877 * Move the head back and print the odd bytes...
890 if (header
->HWResolution
[0] == 120)
891 printf("\033*\001"); /* Select bit image */
893 printf("\033*\003"); /* Select bit image */
895 n
= (unsigned)dot_count
/ DotBytes
;
899 for (n
= dot_count
/ 2, ptr
= dot_ptr
+ 1; n
> 0; n
--, ptr
+= 2)
906 pwrite(dot_ptr
, dot_count
);
915 if (Shingling
&& row
== 1)
917 if (header
->HWResolution
[1] == 360)
926 * Clear the buffer...
929 memset(LineBuffers
[row
], 0, header
->cupsWidth
* DotBytes
);
934 * 'main()' - Main entry and processing of driver.
937 int /* O - Exit status */
938 main(int argc
, /* I - Number of command-line arguments */
939 char *argv
[]) /* I - Command-line arguments */
941 int fd
; /* File descriptor */
942 cups_raster_t
*ras
; /* Raster stream for printing */
943 cups_page_header2_t header
; /* Page header from file */
944 ppd_file_t
*ppd
; /* PPD file */
945 int page
; /* Current page */
946 unsigned y
; /* Current line */
947 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
948 struct sigaction action
; /* Actions for POSIX signals */
949 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
953 * Make sure status messages are not buffered...
956 setbuf(stderr
, NULL
);
959 * Check command-line...
962 if (argc
< 6 || argc
> 7)
965 * We don't have the correct number of arguments; write an error message
969 _cupsLangPrintFilter(stderr
, "ERROR",
970 _("%s job-id user title copies options [file]"),
976 * Open the page stream...
981 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
983 _cupsLangPrintError("ERROR", _("Unable to open raster file"));
991 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
994 * Register a signal handler to eject the current page if the
1000 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1001 sigset(SIGTERM
, CancelJob
);
1002 #elif defined(HAVE_SIGACTION)
1003 memset(&action
, 0, sizeof(action
));
1005 sigemptyset(&action
.sa_mask
);
1006 action
.sa_handler
= CancelJob
;
1007 sigaction(SIGTERM
, &action
, NULL
);
1009 signal(SIGTERM
, CancelJob
);
1010 #endif /* HAVE_SIGSET */
1013 * Initialize the print device...
1016 ppd
= ppdOpenFile(getenv("PPD"));
1019 ppd_status_t status
; /* PPD error */
1020 int linenum
; /* Line number */
1022 _cupsLangPrintFilter(stderr
, "ERROR",
1023 _("The PPD file could not be opened."));
1025 status
= ppdLastError(&linenum
);
1027 fprintf(stderr
, "DEBUG: %s on line %d.\n", ppdErrorString(status
), linenum
);
1032 Model
= ppd
->model_number
;
1037 * Process pages as needed...
1042 while (cupsRasterReadHeader2(ras
, &header
))
1045 * Write a status message with the page number and number of copies.
1053 fprintf(stderr
, "PAGE: %d %d\n", page
, header
.NumCopies
);
1054 _cupsLangPrintFilter(stderr
, "INFO", _("Starting page %d."), page
);
1060 StartPage(ppd
, &header
);
1063 * Loop for each line on the page...
1066 for (y
= 0; y
< header
.cupsHeight
; y
++)
1069 * Let the user know how far we have progressed...
1077 _cupsLangPrintFilter(stderr
, "INFO",
1078 _("Printing page %d, %u%% complete."),
1079 page
, 100 * y
/ header
.cupsHeight
);
1080 fprintf(stderr
, "ATTR: job-media-progress=%u\n",
1081 100 * y
/ header
.cupsHeight
);
1085 * Read a line of graphics...
1088 if (cupsRasterReadPixels(ras
, Planes
[0], header
.cupsBytesPerLine
) < 1)
1092 * Write it to the printer...
1095 OutputLine(&header
);
1102 _cupsLangPrintFilter(stderr
, "INFO", _("Finished page %d."), page
);
1111 * Shutdown the printer...
1119 * Close the raster stream...
1122 cupsRasterClose(ras
);
1127 * If no pages were printed, send an error message...
1132 _cupsLangPrintFilter(stderr
, "ERROR", _("No pages were found."));