2 * EPSON ESC/P and ESC/P2 filter for CUPS.
4 * Copyright 2007-2015 by Apple Inc.
5 * Copyright 1993-2007 by Easy Software Products.
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 * file is missing or damaged, see the license at "http://www.cups.org/".
13 * This file is subject to the Apple OS-Developed Software exception.
17 * Include necessary headers...
20 #include <cups/cups.h>
22 #include <cups/string-private.h>
23 #include <cups/language-private.h>
24 #include <cups/raster.h>
38 #define EPSON_ICOLOR 4
39 #define EPSON_IPHOTO 5
46 #define pwrite(s,n) fwrite((s), 1, (n), stdout)
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 */
75 void StartPage(const ppd_file_t
*ppd
, const cups_page_header2_t
*header
);
76 void EndPage(const cups_page_header2_t
*header
);
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
);
87 * 'Setup()' - Prepare the printer for printing.
93 const char *device_uri
; /* The device for the printer... */
97 * EPSON USB printers need an additional command issued at the
98 * beginning of each job to exit from "packet" mode...
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);
108 * 'StartPage()' - Start a page of graphics.
113 const ppd_file_t
*ppd
, /* I - PPD file */
114 const cups_page_header2_t
*header
) /* I - Page header */
116 int n
, t
; /* Numbers */
117 unsigned plane
; /* Looping var */
121 * Show page device dictionary...
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
);
145 * Send a reset sequence.
148 if (ppd
&& ppd
->nickname
&& strstr(ppd
->nickname
, "OKIDATA") != NULL
)
149 printf("\033{A"); /* Set EPSON emulation mode */
154 * See which type of printer we are using...
161 printf("\033P\022"); /* Set 10 CPI */
163 if (header
->HWResolution
[0] == 360 || header
->HWResolution
[0] == 240)
165 printf("\033x1"); /* LQ printing */
166 printf("\033U1"); /* Unidirectional */
170 printf("\033x0"); /* Draft printing */
171 printf("\033U0"); /* Bidirectional */
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 */
182 * Setup various buffer limits...
185 DotBytes
= header
->cupsRowCount
/ 8;
186 DotColumns
= header
->HWResolution
[0] / 60;
189 if (Model
== EPSON_9PIN
)
190 printf("\033\063\030"); /* Set line feed */
192 switch (header
->HWResolution
[0])
197 printf("\033\063\030"); /* Set line feed */
204 if (header
->HWResolution
[1] == 180)
205 printf("\033\063\010");/* Set line feed */
207 printf("\033+\010"); /* Set line feed */
214 * Set graphics mode...
217 pwrite("\033(G\001\000\001", 6); /* Graphics mode */
220 * Set the media size...
223 if (Model
< EPSON_ICOLOR
)
225 pwrite("\033(U\001\000", 5); /* Resolution/units */
226 putchar((int)(3600 / header
->HWResolution
[1]));
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... */
238 n
= (int)(header
->PageSize
[1] * header
->HWResolution
[1] / 72.0);
240 pwrite("\033(C\002\000", 5); /* Page length */
245 t
= (int)((ppd
->sizes
[1].length
- ppd
->sizes
[1].top
) * header
->HWResolution
[1] / 72.0);
249 pwrite("\033(c\004\000", 5); /* Top & bottom margins */
255 if (header
->HWResolution
[1] == 720)
257 pwrite("\033(i\001\000\001", 6); /* Microweave */
258 pwrite("\033(e\002\000\000\001", 7); /* Small dots */
261 pwrite("\033(V\002\000\000\000", 7); /* Set absolute position 0 */
273 if (header
->cupsColorSpace
== CUPS_CSPACE_CMY
)
275 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
277 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMYcm
)
282 Feed
= 0; /* No blank lines yet */
285 * Allocate memory for a line/row of graphics...
288 if ((Planes
[0] = malloc(header
->cupsBytesPerLine
+ NumPlanes
)) == NULL
)
290 fputs("ERROR: Unable to allocate memory\n", stderr
);
294 for (plane
= 1; plane
< NumPlanes
; plane
++)
295 Planes
[plane
] = Planes
[0] + plane
* header
->cupsBytesPerLine
/ NumPlanes
;
297 if (header
->cupsCompression
|| DotBytes
)
299 if ((CompBuffer
= calloc(2, header
->cupsWidth
+ 1)) == NULL
)
301 fputs("ERROR: Unable to allocate memory\n", stderr
);
310 if ((LineBuffers
[0] = calloc((size_t)DotBytes
, header
->cupsWidth
* (size_t)(Shingling
+ 1))) == NULL
)
312 fputs("ERROR: Unable to allocate memory\n", stderr
);
316 LineBuffers
[1] = LineBuffers
[0] + DotBytes
* header
->cupsWidth
;
326 * 'EndPage()' - Finish a page of graphics.
331 const cups_page_header2_t
*header
) /* I - Page header */
333 if (DotBytes
&& header
)
336 * Flush remaining graphics as needed...
341 if (DotBit
< 128 || EvenOffset
)
342 OutputRows(header
, 0);
344 else if (OddOffset
> EvenOffset
)
346 OutputRows(header
, 1);
347 OutputRows(header
, 0);
351 OutputRows(header
, 0);
352 OutputRows(header
, 1);
357 * Eject the current page...
360 putchar(12); /* Form feed */
373 free(LineBuffers
[0]);
378 * 'Shutdown()' - Shutdown the printer.
385 * Send a reset sequence.
393 * 'CancelJob()' - Cancel the current job...
397 CancelJob(int sig
) /* I - Signal */
406 * 'CompressData()' - Compress a line of graphics.
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 */
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 */
432 line_end
= line
+ length
;
435 * Do depletion for 720 DPI printing...
440 for (comp_ptr
= (unsigned char *)line
; comp_ptr
< line_end
;)
443 * Grab the current byte...
449 * Check adjacent bits...
452 if ((temp
& 0xc0) == 0xc0)
454 if ((temp
& 0x60) == 0x60)
456 if ((temp
& 0x30) == 0x30)
458 if ((temp
& 0x18) == 0x18)
460 if ((temp
& 0x0c) == 0x0c)
462 if ((temp
& 0x06) == 0x06)
464 if ((temp
& 0x03) == 0x03)
470 * Check the last bit in the current byte and the first bit in the
474 if ((temp
& 0x01) && comp_ptr
< line_end
&& *comp_ptr
& 0x80)
483 * Do no compression...
489 * Do TIFF pack-bits encoding...
492 comp_ptr
= CompBuffer
;
494 while (line_ptr
< line_end
)
496 if ((line_ptr
+ 1) >= line_end
)
499 * Single byte on the end...
503 *comp_ptr
++ = *line_ptr
++;
505 else if (line_ptr
[0] == line_ptr
[1])
508 * Repeated sequence...
514 while (line_ptr
< (line_end
- 1) &&
515 line_ptr
[0] == line_ptr
[1] &&
522 *comp_ptr
++ = (unsigned char)(257 - count
);
523 *comp_ptr
++ = *line_ptr
++;
528 * Non-repeated sequence...
535 while (line_ptr
< (line_end
- 1) &&
536 line_ptr
[0] != line_ptr
[1] &&
543 *comp_ptr
++ = (unsigned char)(count
- 1);
545 memcpy(comp_ptr
, start
, (size_t)count
);
550 line_ptr
= CompBuffer
;
555 putchar(0x0d); /* Move print head to left margin */
557 if (Model
< EPSON_ICOLOR
)
560 * Do graphics the "old" way...
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]);
576 printf("\033r%c", ctable
[plane
]); /* Set color */
580 * Send a raster plane...
584 printf("\033."); /* Raster graphics */
589 putchar((int)length
);
590 putchar((int)(length
>> 8));
595 * Do graphics the "new" way...
599 putchar(ctable
[plane
]);
602 putchar((int)length
);
603 putchar((int)(length
>> 8));
608 pwrite(line_ptr
, (size_t)(line_end
- line_ptr
));
614 * 'OutputLine()' - Output a line of graphics.
619 const cups_page_header2_t
*header
) /* I - Page header */
621 if (header
->cupsRowCount
)
624 unsigned char *tempptr
,
629 const unsigned char *pixel
;
634 * Collect bitmap data in the line buffers and write after each buffer.
637 for (x
= header
->cupsWidth
, bit
= 128, pixel
= Planes
[0],
659 * Copy the holding buffer to the output buffer, shingling as necessary...
662 if (Shingling
&& LineCount
!= 0)
665 * Shingle the output...
670 evenptr
= LineBuffers
[1] + OddOffset
;
671 oddptr
= LineBuffers
[0] + EvenOffset
+ DotBytes
;
675 evenptr
= LineBuffers
[0] + EvenOffset
;
676 oddptr
= LineBuffers
[1] + OddOffset
+ DotBytes
;
679 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
;
681 width
-= 2, tempptr
+= 2, oddptr
+= DotBytes
* 2,
682 evenptr
+= DotBytes
* 2)
684 evenptr
[0] = tempptr
[0];
685 oddptr
[0] = tempptr
[1];
690 evenptr
[0] = tempptr
[0];
691 oddptr
[0] = tempptr
[1];
697 * Don't shingle the output...
700 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
,
701 evenptr
= LineBuffers
[0] + EvenOffset
;
703 width
--, tempptr
++, evenptr
+= DotBytes
)
704 *evenptr
= tempptr
[0];
707 if (Shingling
&& LineCount
!= 0)
712 if (EvenOffset
== DotBytes
)
715 OutputRows(header
, 0);
718 if (OddOffset
== DotBytes
)
721 OutputRows(header
, 1);
728 if (EvenOffset
== DotBytes
)
731 OutputRows(header
, 0);
738 memset(CompBuffer
, 0, header
->cupsWidth
);
743 unsigned plane
; /* Current plane */
744 unsigned bytes
; /* Bytes per plane */
745 unsigned xstep
, ystep
; /* X & Y resolutions */
748 * Write a single line of bitmap data as needed...
751 xstep
= 3600 / header
->HWResolution
[0];
752 ystep
= 3600 / header
->HWResolution
[1];
753 bytes
= header
->cupsBytesPerLine
/ NumPlanes
;
755 for (plane
= 0; plane
< NumPlanes
; plane
++)
761 if (!Planes
[plane
][0] &&
762 memcmp(Planes
[plane
], Planes
[plane
] + 1, (size_t)bytes
- 1) == 0)
766 * Output whitespace as needed...
771 pwrite("\033(v\002\000", 5); /* Relative vertical position */
773 putchar((int)(Feed
>> 8));
778 CompressData(Planes
[plane
], bytes
, plane
, header
->cupsCompression
, xstep
, ystep
);
787 * 'OutputRows()' - Output 8, 24, or 48 rows.
792 const cups_page_header2_t
*header
, /* I - Page image header */
793 int row
) /* I - Row number (0 or 1) */
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 */
802 dot_min
= DotBytes
* DotColumns
;
804 if (LineBuffers
[row
][0] != 0 ||
805 memcmp(LineBuffers
[row
], LineBuffers
[row
] + 1, header
->cupsWidth
* DotBytes
- 1))
808 * Skip leading space...
812 dot_count
= header
->cupsWidth
* DotBytes
;
813 dot_ptr
= LineBuffers
[row
];
815 while (dot_count
>= dot_min
&& dot_ptr
[0] == 0 &&
816 memcmp(dot_ptr
, dot_ptr
+ 1, dot_min
- 1) == 0)
820 dot_count
-= dot_min
;
824 * Skip trailing space...
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
;
833 * Position print head for printing...
842 putchar((int)(i
& 255));
843 putchar((int)(i
>> 8));
847 * Start bitmap graphics for this line...
850 printf("\033*"); /* Select bit image */
851 switch (header
->HWResolution
[0])
853 case 60 : /* 60x60/72 DPI gfx */
856 case 120 : /* 120x60/72 DPI gfx */
859 case 180 : /* 180 DPI gfx */
862 case 240 : /* 240x72 DPI gfx */
865 case 360 : /* 360x180/360 DPI gfx */
866 if (header
->HWResolution
[1] == 180)
868 if (Shingling
&& LineCount
!= 0)
869 putchar(40); /* 360x180 fast */
871 putchar(41); /* 360x180 slow */
875 if (Shingling
&& LineCount
!= 0)
876 putchar(72); /* 360x360 fast */
878 putchar(73); /* 360x360 slow */
883 n
= dot_count
/ DotBytes
;
884 putchar((int)(n
& 255));
885 putchar((int)(n
/ 256));
888 * Write the graphics data...
891 if (header
->HWResolution
[0] == 120 ||
892 header
->HWResolution
[0] == 240)
895 * Need to interleave the dots to avoid hosing the print head...
898 for (n
= dot_count
/ 2, ptr
= dot_ptr
; n
> 0; n
--, ptr
+= 2)
908 * Move the head back and print the odd bytes...
917 putchar((int)(i
& 255));
918 putchar((int)(i
>> 8));
921 if (header
->HWResolution
[0] == 120)
922 printf("\033*\001"); /* Select bit image */
924 printf("\033*\003"); /* Select bit image */
926 n
= (unsigned)dot_count
/ DotBytes
;
927 putchar((int)(n
& 255));
928 putchar((int)(n
/ 256));
930 for (n
= dot_count
/ 2, ptr
= dot_ptr
+ 1; n
> 0; n
--, ptr
+= 2)
940 pwrite(dot_ptr
, dot_count
);
949 if (Shingling
&& row
== 1)
951 if (header
->HWResolution
[1] == 360)
960 * Clear the buffer...
963 memset(LineBuffers
[row
], 0, header
->cupsWidth
* DotBytes
);
968 * 'main()' - Main entry and processing of driver.
971 int /* O - Exit status */
972 main(int argc
, /* I - Number of command-line arguments */
973 char *argv
[]) /* I - Command-line arguments */
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 */
987 * Make sure status messages are not buffered...
990 setbuf(stderr
, NULL
);
993 * Check command-line...
996 if (argc
< 6 || argc
> 7)
999 * We don't have the correct number of arguments; write an error message
1003 _cupsLangPrintFilter(stderr
, "ERROR",
1004 _("%s job-id user title copies options [file]"),
1010 * Open the page stream...
1015 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
1017 _cupsLangPrintError("ERROR", _("Unable to open raster file"));
1025 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
1028 * Register a signal handler to eject the current page if the
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
));
1039 sigemptyset(&action
.sa_mask
);
1040 action
.sa_handler
= CancelJob
;
1041 sigaction(SIGTERM
, &action
, NULL
);
1043 signal(SIGTERM
, CancelJob
);
1044 #endif /* HAVE_SIGSET */
1047 * Initialize the print device...
1050 ppd
= ppdOpenFile(getenv("PPD"));
1053 ppd_status_t status
; /* PPD error */
1054 int linenum
; /* Line number */
1056 _cupsLangPrintFilter(stderr
, "ERROR",
1057 _("The PPD file could not be opened."));
1059 status
= ppdLastError(&linenum
);
1061 fprintf(stderr
, "DEBUG: %s on line %d.\n", ppdErrorString(status
), linenum
);
1066 Model
= ppd
->model_number
;
1071 * Process pages as needed...
1076 while (cupsRasterReadHeader2(ras
, &header
))
1079 * Write a status message with the page number and number of copies.
1087 fprintf(stderr
, "PAGE: %d %d\n", page
, header
.NumCopies
);
1088 _cupsLangPrintFilter(stderr
, "INFO", _("Starting page %d."), page
);
1094 StartPage(ppd
, &header
);
1097 * Loop for each line on the page...
1100 for (y
= 0; y
< header
.cupsHeight
; y
++)
1103 * Let the user know how far we have progressed...
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
);
1119 * Read a line of graphics...
1122 if (cupsRasterReadPixels(ras
, Planes
[0], header
.cupsBytesPerLine
) < 1)
1126 * Write it to the printer...
1129 OutputLine(&header
);
1136 _cupsLangPrintFilter(stderr
, "INFO", _("Finished page %d."), page
);
1145 * Shutdown the printer...
1153 * Close the raster stream...
1156 cupsRasterClose(ras
);
1161 * If no pages were printed, send an error message...
1166 _cupsLangPrintFilter(stderr
, "ERROR", _("No pages were found."));