2 * EPSON ESC/P and ESC/P2 filter for CUPS.
4 * Copyright 2007-2018 by Apple Inc.
5 * Copyright 1993-2007 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 * Include necessary headers...
15 #include <cups/cups.h>
17 #include <cups/string-private.h>
18 #include <cups/language-private.h>
19 #include <cups/raster.h>
33 #define EPSON_ICOLOR 4
34 #define EPSON_IPHOTO 5
41 #define pwrite(s,n) fwrite((s), 1, (n), stdout)
48 unsigned char *Planes
[6], /* Output buffers */
49 *CompBuffer
, /* Compression buffer */
50 *LineBuffers
[2]; /* Line bitmap buffers */
51 int Model
, /* Model number */
52 EjectPage
, /* Eject the page when done? */
53 Shingling
, /* Shingle output? */
54 Canceled
; /* Has the current job been canceled? */
55 unsigned NumPlanes
, /* Number of color planes */
56 Feed
, /* Number of lines to skip */
57 DotBit
, /* Bit in buffers */
58 DotBytes
, /* # bytes in a dot column */
59 DotColumns
, /* # columns in 1/60 inch */
60 LineCount
, /* # of lines processed */
61 EvenOffset
, /* Offset into 'even' buffers */
62 OddOffset
; /* Offset into 'odd' buffers */
70 void StartPage(const ppd_file_t
*ppd
, const cups_page_header2_t
*header
);
71 void EndPage(const cups_page_header2_t
*header
);
74 void CancelJob(int sig
);
75 void CompressData(const unsigned char *line
, unsigned length
, unsigned plane
,
76 unsigned type
, unsigned xstep
, unsigned ystep
);
77 void OutputLine(const cups_page_header2_t
*header
);
78 void OutputRows(const cups_page_header2_t
*header
, int row
);
82 * 'Setup()' - Prepare the printer for printing.
88 const char *device_uri
; /* The device for the printer... */
92 * EPSON USB printers need an additional command issued at the
93 * beginning of each job to exit from "packet" mode...
96 if ((device_uri
= getenv("DEVICE_URI")) != NULL
&&
97 strncmp(device_uri
, "usb:", 4) == 0 && Model
>= EPSON_ICOLOR
)
98 pwrite("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
103 * 'StartPage()' - Start a page of graphics.
108 const ppd_file_t
*ppd
, /* I - PPD file */
109 const cups_page_header2_t
*header
) /* I - Page header */
111 int n
, t
; /* Numbers */
112 unsigned plane
; /* Looping var */
116 * Show page device dictionary...
119 fprintf(stderr
, "DEBUG: StartPage...\n");
120 fprintf(stderr
, "DEBUG: Duplex = %d\n", header
->Duplex
);
121 fprintf(stderr
, "DEBUG: HWResolution = [ %d %d ]\n", header
->HWResolution
[0], header
->HWResolution
[1]);
122 fprintf(stderr
, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", header
->ImagingBoundingBox
[0], header
->ImagingBoundingBox
[1], header
->ImagingBoundingBox
[2], header
->ImagingBoundingBox
[3]);
123 fprintf(stderr
, "DEBUG: Margins = [ %d %d ]\n", header
->Margins
[0], header
->Margins
[1]);
124 fprintf(stderr
, "DEBUG: ManualFeed = %d\n", header
->ManualFeed
);
125 fprintf(stderr
, "DEBUG: MediaPosition = %d\n", header
->MediaPosition
);
126 fprintf(stderr
, "DEBUG: NumCopies = %d\n", header
->NumCopies
);
127 fprintf(stderr
, "DEBUG: Orientation = %d\n", header
->Orientation
);
128 fprintf(stderr
, "DEBUG: PageSize = [ %d %d ]\n", header
->PageSize
[0], header
->PageSize
[1]);
129 fprintf(stderr
, "DEBUG: cupsWidth = %d\n", header
->cupsWidth
);
130 fprintf(stderr
, "DEBUG: cupsHeight = %d\n", header
->cupsHeight
);
131 fprintf(stderr
, "DEBUG: cupsMediaType = %d\n", header
->cupsMediaType
);
132 fprintf(stderr
, "DEBUG: cupsBitsPerColor = %d\n", header
->cupsBitsPerColor
);
133 fprintf(stderr
, "DEBUG: cupsBitsPerPixel = %d\n", header
->cupsBitsPerPixel
);
134 fprintf(stderr
, "DEBUG: cupsBytesPerLine = %d\n", header
->cupsBytesPerLine
);
135 fprintf(stderr
, "DEBUG: cupsColorOrder = %d\n", header
->cupsColorOrder
);
136 fprintf(stderr
, "DEBUG: cupsColorSpace = %d\n", header
->cupsColorSpace
);
137 fprintf(stderr
, "DEBUG: cupsCompression = %d\n", header
->cupsCompression
);
140 * Send a reset sequence.
143 if (ppd
&& ppd
->nickname
&& strstr(ppd
->nickname
, "OKIDATA") != NULL
)
144 printf("\033{A"); /* Set EPSON emulation mode */
149 * See which type of printer we are using...
156 printf("\033P\022"); /* Set 10 CPI */
158 if (header
->HWResolution
[0] == 360 || header
->HWResolution
[0] == 240)
160 printf("\033x1"); /* LQ printing */
161 printf("\033U1"); /* Unidirectional */
165 printf("\033x0"); /* Draft printing */
166 printf("\033U0"); /* Bidirectional */
169 printf("\033l%c\033Q%c", 0, /* Side margins */
170 (int)(10.0 * header
->PageSize
[0] / 72.0 + 0.5));
171 printf("\033\062\033C%c", /* Page length in 1/6th inches */
172 (int)(header
->PageSize
[1] / 12.0 + 0.5));
173 printf("\033N%c", 0); /* Bottom margin */
174 printf("\033O"); /* No perforation skip */
177 * Setup various buffer limits...
180 DotBytes
= header
->cupsRowCount
/ 8;
181 DotColumns
= header
->HWResolution
[0] / 60;
184 if (Model
== EPSON_9PIN
)
185 printf("\033\063\030"); /* Set line feed */
187 switch (header
->HWResolution
[0])
192 printf("\033\063\030"); /* Set line feed */
199 if (header
->HWResolution
[1] == 180)
200 printf("\033\063\010");/* Set line feed */
202 printf("\033+\010"); /* Set line feed */
209 * Set graphics mode...
212 pwrite("\033(G\001\000\001", 6); /* Graphics mode */
215 * Set the media size...
218 if (Model
< EPSON_ICOLOR
)
220 pwrite("\033(U\001\000", 5); /* Resolution/units */
221 putchar((int)(3600 / header
->HWResolution
[1]));
225 pwrite("\033(U\005\000", 5);
226 putchar((int)(1440 / header
->HWResolution
[1]));
227 putchar((int)(1440 / header
->HWResolution
[1]));
228 putchar((int)(1440 / header
->HWResolution
[0]));
229 putchar(0xa0); /* n/1440ths... */
233 n
= (int)(header
->PageSize
[1] * header
->HWResolution
[1] / 72.0);
235 pwrite("\033(C\002\000", 5); /* Page length */
240 t
= (int)((ppd
->sizes
[1].length
- ppd
->sizes
[1].top
) * header
->HWResolution
[1] / 72.0);
244 pwrite("\033(c\004\000", 5); /* Top & bottom margins */
250 if (header
->HWResolution
[1] == 720)
252 pwrite("\033(i\001\000\001", 6); /* Microweave */
253 pwrite("\033(e\002\000\000\001", 7); /* Small dots */
256 pwrite("\033(V\002\000\000\000", 7); /* Set absolute position 0 */
268 if (header
->cupsColorSpace
== CUPS_CSPACE_CMY
)
270 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
272 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMYcm
)
277 Feed
= 0; /* No blank lines yet */
280 * Allocate memory for a line/row of graphics...
283 if ((Planes
[0] = malloc(header
->cupsBytesPerLine
+ NumPlanes
)) == NULL
)
285 fputs("ERROR: Unable to allocate memory\n", stderr
);
289 for (plane
= 1; plane
< NumPlanes
; plane
++)
290 Planes
[plane
] = Planes
[0] + plane
* header
->cupsBytesPerLine
/ NumPlanes
;
292 if (header
->cupsCompression
|| DotBytes
)
294 if ((CompBuffer
= calloc(2, header
->cupsWidth
+ 1)) == NULL
)
296 fputs("ERROR: Unable to allocate memory\n", stderr
);
305 if ((LineBuffers
[0] = calloc((size_t)DotBytes
, (header
->cupsWidth
+ 7) * (size_t)(Shingling
+ 1))) == NULL
)
307 fputs("ERROR: Unable to allocate memory\n", stderr
);
311 LineBuffers
[1] = LineBuffers
[0] + DotBytes
* header
->cupsWidth
;
321 * 'EndPage()' - Finish a page of graphics.
326 const cups_page_header2_t
*header
) /* I - Page header */
328 if (DotBytes
&& header
)
331 * Flush remaining graphics as needed...
336 if (DotBit
< 128 || EvenOffset
)
337 OutputRows(header
, 0);
339 else if (OddOffset
> EvenOffset
)
341 OutputRows(header
, 1);
342 OutputRows(header
, 0);
346 OutputRows(header
, 0);
347 OutputRows(header
, 1);
352 * Eject the current page...
355 putchar(12); /* Form feed */
368 free(LineBuffers
[0]);
373 * 'Shutdown()' - Shutdown the printer.
380 * Send a reset sequence.
388 * 'CancelJob()' - Cancel the current job...
392 CancelJob(int sig
) /* I - Signal */
401 * 'CompressData()' - Compress a line of graphics.
405 CompressData(const unsigned char *line
, /* I - Data to compress */
406 unsigned length
,/* I - Number of bytes */
407 unsigned plane
, /* I - Color plane */
408 unsigned type
, /* I - Type of compression */
409 unsigned xstep
, /* I - X resolution */
410 unsigned ystep
) /* I - Y resolution */
412 const unsigned char *line_ptr
, /* Current byte pointer */
413 *line_end
, /* End-of-line byte pointer */
414 *start
; /* Start of compression sequence */
415 unsigned char *comp_ptr
, /* Pointer into compression buffer */
416 temp
; /* Current byte */
417 int count
; /* Count of bytes for output */
418 static int ctable
[6] = { 0, 2, 1, 4, 18, 17 };
419 /* KCMYcm color values */
427 line_end
= line
+ length
;
430 * Do depletion for 720 DPI printing...
435 for (comp_ptr
= (unsigned char *)line
; comp_ptr
< line_end
;)
438 * Grab the current byte...
444 * Check adjacent bits...
447 if ((temp
& 0xc0) == 0xc0)
449 if ((temp
& 0x60) == 0x60)
451 if ((temp
& 0x30) == 0x30)
453 if ((temp
& 0x18) == 0x18)
455 if ((temp
& 0x0c) == 0x0c)
457 if ((temp
& 0x06) == 0x06)
459 if ((temp
& 0x03) == 0x03)
465 * Check the last bit in the current byte and the first bit in the
469 if ((temp
& 0x01) && comp_ptr
< line_end
&& *comp_ptr
& 0x80)
478 * Do no compression...
484 * Do TIFF pack-bits encoding...
487 comp_ptr
= CompBuffer
;
489 while (line_ptr
< line_end
)
491 if ((line_ptr
+ 1) >= line_end
)
494 * Single byte on the end...
498 *comp_ptr
++ = *line_ptr
++;
500 else if (line_ptr
[0] == line_ptr
[1])
503 * Repeated sequence...
509 while (line_ptr
< (line_end
- 1) &&
510 line_ptr
[0] == line_ptr
[1] &&
517 *comp_ptr
++ = (unsigned char)(257 - count
);
518 *comp_ptr
++ = *line_ptr
++;
523 * Non-repeated sequence...
530 while (line_ptr
< (line_end
- 1) &&
531 line_ptr
[0] != line_ptr
[1] &&
538 *comp_ptr
++ = (unsigned char)(count
- 1);
540 memcpy(comp_ptr
, start
, (size_t)count
);
545 line_ptr
= CompBuffer
;
550 putchar(0x0d); /* Move print head to left margin */
552 if (Model
< EPSON_ICOLOR
)
555 * Do graphics the "old" way...
565 printf("\033(r%c%c%c%c", 2, 0, 1, ctable
[plane
] & 15);
566 /* Set extended color */
567 else if (NumPlanes
== 3)
568 printf("\033r%c", ctable
[plane
+ 1]);
571 printf("\033r%c", ctable
[plane
]); /* Set color */
575 * Send a raster plane...
579 printf("\033."); /* Raster graphics */
584 putchar((int)length
);
585 putchar((int)(length
>> 8));
590 * Do graphics the "new" way...
594 putchar(ctable
[plane
]);
597 putchar((int)length
);
598 putchar((int)(length
>> 8));
603 pwrite(line_ptr
, (size_t)(line_end
- line_ptr
));
609 * 'OutputLine()' - Output a line of graphics.
614 const cups_page_header2_t
*header
) /* I - Page header */
616 if (header
->cupsRowCount
)
619 unsigned char *tempptr
,
624 const unsigned char *pixel
;
629 * Collect bitmap data in the line buffers and write after each buffer.
632 for (x
= header
->cupsWidth
, bit
= 128, pixel
= Planes
[0],
654 * Copy the holding buffer to the output buffer, shingling as necessary...
657 if (Shingling
&& LineCount
!= 0)
660 * Shingle the output...
665 evenptr
= LineBuffers
[1] + OddOffset
;
666 oddptr
= LineBuffers
[0] + EvenOffset
+ DotBytes
;
670 evenptr
= LineBuffers
[0] + EvenOffset
;
671 oddptr
= LineBuffers
[1] + OddOffset
+ DotBytes
;
674 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
;
676 width
-= 2, tempptr
+= 2, oddptr
+= DotBytes
* 2,
677 evenptr
+= DotBytes
* 2)
679 evenptr
[0] = tempptr
[0];
680 oddptr
[0] = tempptr
[1];
685 evenptr
[0] = tempptr
[0];
686 oddptr
[0] = tempptr
[1];
692 * Don't shingle the output...
695 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
,
696 evenptr
= LineBuffers
[0] + EvenOffset
;
698 width
--, tempptr
++, evenptr
+= DotBytes
)
699 *evenptr
= tempptr
[0];
702 if (Shingling
&& LineCount
!= 0)
707 if (EvenOffset
== DotBytes
)
710 OutputRows(header
, 0);
713 if (OddOffset
== DotBytes
)
716 OutputRows(header
, 1);
723 if (EvenOffset
== DotBytes
)
726 OutputRows(header
, 0);
733 memset(CompBuffer
, 0, header
->cupsWidth
);
738 unsigned plane
; /* Current plane */
739 unsigned bytes
; /* Bytes per plane */
740 unsigned xstep
, ystep
; /* X & Y resolutions */
743 * Write a single line of bitmap data as needed...
746 xstep
= 3600 / header
->HWResolution
[0];
747 ystep
= 3600 / header
->HWResolution
[1];
748 bytes
= header
->cupsBytesPerLine
/ NumPlanes
;
750 for (plane
= 0; plane
< NumPlanes
; plane
++)
756 if (!Planes
[plane
][0] &&
757 memcmp(Planes
[plane
], Planes
[plane
] + 1, (size_t)bytes
- 1) == 0)
761 * Output whitespace as needed...
766 pwrite("\033(v\002\000", 5); /* Relative vertical position */
768 putchar((int)(Feed
>> 8));
773 CompressData(Planes
[plane
], bytes
, plane
, header
->cupsCompression
, xstep
, ystep
);
782 * 'OutputRows()' - Output 8, 24, or 48 rows.
787 const cups_page_header2_t
*header
, /* I - Page image header */
788 int row
) /* I - Row number (0 or 1) */
790 unsigned i
, n
, /* Looping vars */
791 dot_count
, /* Number of bytes to print */
792 dot_min
; /* Minimum number of bytes */
793 unsigned char *dot_ptr
, /* Pointer to print data */
794 *ptr
; /* Current data */
797 dot_min
= DotBytes
* DotColumns
;
799 if (LineBuffers
[row
][0] != 0 ||
800 memcmp(LineBuffers
[row
], LineBuffers
[row
] + 1, header
->cupsWidth
* DotBytes
- 1))
803 * Skip leading space...
807 dot_count
= header
->cupsWidth
* DotBytes
;
808 dot_ptr
= LineBuffers
[row
];
810 while (dot_count
>= dot_min
&& dot_ptr
[0] == 0 &&
811 memcmp(dot_ptr
, dot_ptr
+ 1, dot_min
- 1) == 0)
815 dot_count
-= dot_min
;
819 * Skip trailing space...
822 while (dot_count
>= dot_min
&& dot_ptr
[dot_count
- dot_min
] == 0 &&
823 memcmp(dot_ptr
+ dot_count
- dot_min
,
824 dot_ptr
+ dot_count
- dot_min
+ 1, dot_min
- 1) == 0)
825 dot_count
-= dot_min
;
828 * Position print head for printing...
837 putchar((int)(i
& 255));
838 putchar((int)(i
>> 8));
842 * Start bitmap graphics for this line...
845 printf("\033*"); /* Select bit image */
846 switch (header
->HWResolution
[0])
848 case 60 : /* 60x60/72 DPI gfx */
851 case 120 : /* 120x60/72 DPI gfx */
854 case 180 : /* 180 DPI gfx */
857 case 240 : /* 240x72 DPI gfx */
860 case 360 : /* 360x180/360 DPI gfx */
861 if (header
->HWResolution
[1] == 180)
863 if (Shingling
&& LineCount
!= 0)
864 putchar(40); /* 360x180 fast */
866 putchar(41); /* 360x180 slow */
870 if (Shingling
&& LineCount
!= 0)
871 putchar(72); /* 360x360 fast */
873 putchar(73); /* 360x360 slow */
878 n
= dot_count
/ DotBytes
;
879 putchar((int)(n
& 255));
880 putchar((int)(n
/ 256));
883 * Write the graphics data...
886 if (header
->HWResolution
[0] == 120 ||
887 header
->HWResolution
[0] == 240)
890 * Need to interleave the dots to avoid hosing the print head...
893 for (n
= dot_count
/ 2, ptr
= dot_ptr
; n
> 0; n
--, ptr
+= 2)
903 * Move the head back and print the odd bytes...
912 putchar((int)(i
& 255));
913 putchar((int)(i
>> 8));
916 if (header
->HWResolution
[0] == 120)
917 printf("\033*\001"); /* Select bit image */
919 printf("\033*\003"); /* Select bit image */
921 n
= (unsigned)dot_count
/ DotBytes
;
922 putchar((int)(n
& 255));
923 putchar((int)(n
/ 256));
925 for (n
= dot_count
/ 2, ptr
= dot_ptr
+ 1; n
> 0; n
--, ptr
+= 2)
935 pwrite(dot_ptr
, dot_count
);
944 if (Shingling
&& row
== 1)
946 if (header
->HWResolution
[1] == 360)
955 * Clear the buffer...
958 memset(LineBuffers
[row
], 0, header
->cupsWidth
* DotBytes
);
963 * 'main()' - Main entry and processing of driver.
966 int /* O - Exit status */
967 main(int argc
, /* I - Number of command-line arguments */
968 char *argv
[]) /* I - Command-line arguments */
970 int fd
; /* File descriptor */
971 cups_raster_t
*ras
; /* Raster stream for printing */
972 cups_page_header2_t header
; /* Page header from file */
973 ppd_file_t
*ppd
; /* PPD file */
974 int page
; /* Current page */
975 unsigned y
; /* Current line */
976 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
977 struct sigaction action
; /* Actions for POSIX signals */
978 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
982 * Make sure status messages are not buffered...
985 setbuf(stderr
, NULL
);
988 * Check command-line...
991 if (argc
< 6 || argc
> 7)
994 * We don't have the correct number of arguments; write an error message
998 _cupsLangPrintFilter(stderr
, "ERROR",
999 _("%s job-id user title copies options [file]"),
1005 * Open the page stream...
1010 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
1012 _cupsLangPrintError("ERROR", _("Unable to open raster file"));
1020 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
1023 * Register a signal handler to eject the current page if the
1029 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1030 sigset(SIGTERM
, CancelJob
);
1031 #elif defined(HAVE_SIGACTION)
1032 memset(&action
, 0, sizeof(action
));
1034 sigemptyset(&action
.sa_mask
);
1035 action
.sa_handler
= CancelJob
;
1036 sigaction(SIGTERM
, &action
, NULL
);
1038 signal(SIGTERM
, CancelJob
);
1039 #endif /* HAVE_SIGSET */
1042 * Initialize the print device...
1045 ppd
= ppdOpenFile(getenv("PPD"));
1048 ppd_status_t status
; /* PPD error */
1049 int linenum
; /* Line number */
1051 _cupsLangPrintFilter(stderr
, "ERROR",
1052 _("The PPD file could not be opened."));
1054 status
= ppdLastError(&linenum
);
1056 fprintf(stderr
, "DEBUG: %s on line %d.\n", ppdErrorString(status
), linenum
);
1061 Model
= ppd
->model_number
;
1066 * Process pages as needed...
1071 while (cupsRasterReadHeader2(ras
, &header
))
1074 * Write a status message with the page number and number of copies.
1082 fprintf(stderr
, "PAGE: %d %d\n", page
, header
.NumCopies
);
1083 _cupsLangPrintFilter(stderr
, "INFO", _("Starting page %d."), page
);
1089 StartPage(ppd
, &header
);
1092 * Loop for each line on the page...
1095 for (y
= 0; y
< header
.cupsHeight
; y
++)
1098 * Let the user know how far we have progressed...
1106 _cupsLangPrintFilter(stderr
, "INFO",
1107 _("Printing page %d, %u%% complete."),
1108 page
, 100 * y
/ header
.cupsHeight
);
1109 fprintf(stderr
, "ATTR: job-media-progress=%u\n",
1110 100 * y
/ header
.cupsHeight
);
1114 * Read a line of graphics...
1117 if (cupsRasterReadPixels(ras
, Planes
[0], header
.cupsBytesPerLine
) < 1)
1121 * Write it to the printer...
1124 OutputLine(&header
);
1131 _cupsLangPrintFilter(stderr
, "INFO", _("Finished page %d."), page
);
1140 * Shutdown the printer...
1148 * Close the raster stream...
1151 cupsRasterClose(ras
);
1156 * If no pages were printed, send an error message...
1161 _cupsLangPrintFilter(stderr
, "ERROR", _("No pages were found."));