4 * EPSON ESC/P and ESC/P2 filter for CUPS.
6 * Copyright 2007-2015 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 * Show page device dictionary...
126 fprintf(stderr
, "DEBUG: StartPage...\n");
127 fprintf(stderr
, "DEBUG: Duplex = %d\n", header
->Duplex
);
128 fprintf(stderr
, "DEBUG: HWResolution = [ %d %d ]\n", header
->HWResolution
[0], header
->HWResolution
[1]);
129 fprintf(stderr
, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", header
->ImagingBoundingBox
[0], header
->ImagingBoundingBox
[1], header
->ImagingBoundingBox
[2], header
->ImagingBoundingBox
[3]);
130 fprintf(stderr
, "DEBUG: Margins = [ %d %d ]\n", header
->Margins
[0], header
->Margins
[1]);
131 fprintf(stderr
, "DEBUG: ManualFeed = %d\n", header
->ManualFeed
);
132 fprintf(stderr
, "DEBUG: MediaPosition = %d\n", header
->MediaPosition
);
133 fprintf(stderr
, "DEBUG: NumCopies = %d\n", header
->NumCopies
);
134 fprintf(stderr
, "DEBUG: Orientation = %d\n", header
->Orientation
);
135 fprintf(stderr
, "DEBUG: PageSize = [ %d %d ]\n", header
->PageSize
[0], header
->PageSize
[1]);
136 fprintf(stderr
, "DEBUG: cupsWidth = %d\n", header
->cupsWidth
);
137 fprintf(stderr
, "DEBUG: cupsHeight = %d\n", header
->cupsHeight
);
138 fprintf(stderr
, "DEBUG: cupsMediaType = %d\n", header
->cupsMediaType
);
139 fprintf(stderr
, "DEBUG: cupsBitsPerColor = %d\n", header
->cupsBitsPerColor
);
140 fprintf(stderr
, "DEBUG: cupsBitsPerPixel = %d\n", header
->cupsBitsPerPixel
);
141 fprintf(stderr
, "DEBUG: cupsBytesPerLine = %d\n", header
->cupsBytesPerLine
);
142 fprintf(stderr
, "DEBUG: cupsColorOrder = %d\n", header
->cupsColorOrder
);
143 fprintf(stderr
, "DEBUG: cupsColorSpace = %d\n", header
->cupsColorSpace
);
144 fprintf(stderr
, "DEBUG: cupsCompression = %d\n", header
->cupsCompression
);
147 * Send a reset sequence.
150 if (ppd
&& ppd
->nickname
&& strstr(ppd
->nickname
, "OKIDATA") != NULL
)
151 printf("\033{A"); /* Set EPSON emulation mode */
156 * See which type of printer we are using...
163 printf("\033P\022"); /* Set 10 CPI */
165 if (header
->HWResolution
[0] == 360 || header
->HWResolution
[0] == 240)
167 printf("\033x1"); /* LQ printing */
168 printf("\033U1"); /* Unidirectional */
172 printf("\033x0"); /* Draft printing */
173 printf("\033U0"); /* Bidirectional */
176 printf("\033l%c\033Q%c", 0, /* Side margins */
177 (int)(10.0 * header
->PageSize
[0] / 72.0 + 0.5));
178 printf("\033\062\033C%c", /* Page length in 1/6th inches */
179 (int)(header
->PageSize
[1] / 12.0 + 0.5));
180 printf("\033N%c", 0); /* Bottom margin */
181 printf("\033O"); /* No perforation skip */
184 * Setup various buffer limits...
187 DotBytes
= header
->cupsRowCount
/ 8;
188 DotColumns
= header
->HWResolution
[0] / 60;
191 if (Model
== EPSON_9PIN
)
192 printf("\033\063\030"); /* Set line feed */
194 switch (header
->HWResolution
[0])
199 printf("\033\063\030"); /* Set line feed */
206 if (header
->HWResolution
[1] == 180)
207 printf("\033\063\010");/* Set line feed */
209 printf("\033+\010"); /* Set line feed */
216 * Set graphics mode...
219 pwrite("\033(G\001\000\001", 6); /* Graphics mode */
222 * Set the media size...
225 if (Model
< EPSON_ICOLOR
)
227 pwrite("\033(U\001\000", 5); /* Resolution/units */
228 putchar((int)(3600 / header
->HWResolution
[1]));
232 pwrite("\033(U\005\000", 5);
233 putchar((int)(1440 / header
->HWResolution
[1]));
234 putchar((int)(1440 / header
->HWResolution
[1]));
235 putchar((int)(1440 / header
->HWResolution
[0]));
236 putchar(0xa0); /* n/1440ths... */
240 n
= (int)(header
->PageSize
[1] * header
->HWResolution
[1] / 72.0);
242 pwrite("\033(C\002\000", 5); /* Page length */
247 t
= (int)((ppd
->sizes
[1].length
- ppd
->sizes
[1].top
) * header
->HWResolution
[1] / 72.0);
251 pwrite("\033(c\004\000", 5); /* Top & bottom margins */
257 if (header
->HWResolution
[1] == 720)
259 pwrite("\033(i\001\000\001", 6); /* Microweave */
260 pwrite("\033(e\002\000\000\001", 7); /* Small dots */
263 pwrite("\033(V\002\000\000\000", 7); /* Set absolute position 0 */
275 if (header
->cupsColorSpace
== CUPS_CSPACE_CMY
)
277 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
279 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMYcm
)
284 Feed
= 0; /* No blank lines yet */
287 * Allocate memory for a line/row of graphics...
290 if ((Planes
[0] = malloc(header
->cupsBytesPerLine
+ NumPlanes
)) == NULL
)
292 fputs("ERROR: Unable to allocate memory\n", stderr
);
296 for (plane
= 1; plane
< NumPlanes
; plane
++)
297 Planes
[plane
] = Planes
[0] + plane
* header
->cupsBytesPerLine
/ NumPlanes
;
299 if (header
->cupsCompression
|| DotBytes
)
301 if ((CompBuffer
= calloc(2, header
->cupsWidth
+ 1)) == NULL
)
303 fputs("ERROR: Unable to allocate memory\n", stderr
);
312 if ((LineBuffers
[0] = calloc((size_t)DotBytes
, header
->cupsWidth
* (size_t)(Shingling
+ 1))) == NULL
)
314 fputs("ERROR: Unable to allocate memory\n", stderr
);
318 LineBuffers
[1] = LineBuffers
[0] + DotBytes
* header
->cupsWidth
;
328 * 'EndPage()' - Finish a page of graphics.
333 const cups_page_header2_t
*header
) /* I - Page header */
335 if (DotBytes
&& header
)
338 * Flush remaining graphics as needed...
343 if (DotBit
< 128 || EvenOffset
)
344 OutputRows(header
, 0);
346 else if (OddOffset
> EvenOffset
)
348 OutputRows(header
, 1);
349 OutputRows(header
, 0);
353 OutputRows(header
, 0);
354 OutputRows(header
, 1);
359 * Eject the current page...
362 putchar(12); /* Form feed */
375 free(LineBuffers
[0]);
380 * 'Shutdown()' - Shutdown the printer.
387 * Send a reset sequence.
395 * 'CancelJob()' - Cancel the current job...
399 CancelJob(int sig
) /* I - Signal */
408 * 'CompressData()' - Compress a line of graphics.
412 CompressData(const unsigned char *line
, /* I - Data to compress */
413 unsigned length
,/* I - Number of bytes */
414 unsigned plane
, /* I - Color plane */
415 unsigned type
, /* I - Type of compression */
416 unsigned xstep
, /* I - X resolution */
417 unsigned ystep
) /* I - Y resolution */
419 const unsigned char *line_ptr
, /* Current byte pointer */
420 *line_end
, /* End-of-line byte pointer */
421 *start
; /* Start of compression sequence */
422 unsigned char *comp_ptr
, /* Pointer into compression buffer */
423 temp
; /* Current byte */
424 int count
; /* Count of bytes for output */
425 static int ctable
[6] = { 0, 2, 1, 4, 18, 17 };
426 /* KCMYcm color values */
434 line_end
= line
+ length
;
437 * Do depletion for 720 DPI printing...
442 for (comp_ptr
= (unsigned char *)line
; comp_ptr
< line_end
;)
445 * Grab the current byte...
451 * Check adjacent bits...
454 if ((temp
& 0xc0) == 0xc0)
456 if ((temp
& 0x60) == 0x60)
458 if ((temp
& 0x30) == 0x30)
460 if ((temp
& 0x18) == 0x18)
462 if ((temp
& 0x0c) == 0x0c)
464 if ((temp
& 0x06) == 0x06)
466 if ((temp
& 0x03) == 0x03)
472 * Check the last bit in the current byte and the first bit in the
476 if ((temp
& 0x01) && comp_ptr
< line_end
&& *comp_ptr
& 0x80)
485 * Do no compression...
491 * Do TIFF pack-bits encoding...
494 comp_ptr
= CompBuffer
;
496 while (line_ptr
< line_end
)
498 if ((line_ptr
+ 1) >= line_end
)
501 * Single byte on the end...
505 *comp_ptr
++ = *line_ptr
++;
507 else if (line_ptr
[0] == line_ptr
[1])
510 * Repeated sequence...
516 while (line_ptr
< (line_end
- 1) &&
517 line_ptr
[0] == line_ptr
[1] &&
524 *comp_ptr
++ = (unsigned char)(257 - count
);
525 *comp_ptr
++ = *line_ptr
++;
530 * Non-repeated sequence...
537 while (line_ptr
< (line_end
- 1) &&
538 line_ptr
[0] != line_ptr
[1] &&
545 *comp_ptr
++ = (unsigned char)(count
- 1);
547 memcpy(comp_ptr
, start
, (size_t)count
);
552 line_ptr
= CompBuffer
;
557 putchar(0x0d); /* Move print head to left margin */
559 if (Model
< EPSON_ICOLOR
)
562 * Do graphics the "old" way...
572 printf("\033(r%c%c%c%c", 2, 0, 1, ctable
[plane
] & 15);
573 /* Set extended color */
574 else if (NumPlanes
== 3)
575 printf("\033r%c", ctable
[plane
+ 1]);
578 printf("\033r%c", ctable
[plane
]); /* Set color */
582 * Send a raster plane...
586 printf("\033."); /* Raster graphics */
591 putchar((int)length
);
592 putchar((int)(length
>> 8));
597 * Do graphics the "new" way...
601 putchar(ctable
[plane
]);
604 putchar((int)length
);
605 putchar((int)(length
>> 8));
610 pwrite(line_ptr
, (size_t)(line_end
- line_ptr
));
616 * 'OutputLine()' - Output a line of graphics.
621 const cups_page_header2_t
*header
) /* I - Page header */
623 if (header
->cupsRowCount
)
626 unsigned char *tempptr
,
631 const unsigned char *pixel
;
636 * Collect bitmap data in the line buffers and write after each buffer.
639 for (x
= header
->cupsWidth
, bit
= 128, pixel
= Planes
[0],
661 * Copy the holding buffer to the output buffer, shingling as necessary...
664 if (Shingling
&& LineCount
!= 0)
667 * Shingle the output...
672 evenptr
= LineBuffers
[1] + OddOffset
;
673 oddptr
= LineBuffers
[0] + EvenOffset
+ DotBytes
;
677 evenptr
= LineBuffers
[0] + EvenOffset
;
678 oddptr
= LineBuffers
[1] + OddOffset
+ DotBytes
;
681 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
;
683 width
-= 2, tempptr
+= 2, oddptr
+= DotBytes
* 2,
684 evenptr
+= DotBytes
* 2)
686 evenptr
[0] = tempptr
[0];
687 oddptr
[0] = tempptr
[1];
692 evenptr
[0] = tempptr
[0];
693 oddptr
[0] = tempptr
[1];
699 * Don't shingle the output...
702 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
,
703 evenptr
= LineBuffers
[0] + EvenOffset
;
705 width
--, tempptr
++, evenptr
+= DotBytes
)
706 *evenptr
= tempptr
[0];
709 if (Shingling
&& LineCount
!= 0)
714 if (EvenOffset
== DotBytes
)
717 OutputRows(header
, 0);
720 if (OddOffset
== DotBytes
)
723 OutputRows(header
, 1);
730 if (EvenOffset
== DotBytes
)
733 OutputRows(header
, 0);
740 memset(CompBuffer
, 0, header
->cupsWidth
);
745 unsigned plane
; /* Current plane */
746 unsigned bytes
; /* Bytes per plane */
747 unsigned xstep
, ystep
; /* X & Y resolutions */
750 * Write a single line of bitmap data as needed...
753 xstep
= 3600 / header
->HWResolution
[0];
754 ystep
= 3600 / header
->HWResolution
[1];
755 bytes
= header
->cupsBytesPerLine
/ NumPlanes
;
757 for (plane
= 0; plane
< NumPlanes
; plane
++)
763 if (!Planes
[plane
][0] &&
764 memcmp(Planes
[plane
], Planes
[plane
] + 1, (size_t)bytes
- 1) == 0)
768 * Output whitespace as needed...
773 pwrite("\033(v\002\000", 5); /* Relative vertical position */
775 putchar((int)(Feed
>> 8));
780 CompressData(Planes
[plane
], bytes
, plane
, header
->cupsCompression
, xstep
, ystep
);
789 * 'OutputRows()' - Output 8, 24, or 48 rows.
794 const cups_page_header2_t
*header
, /* I - Page image header */
795 int row
) /* I - Row number (0 or 1) */
797 unsigned i
, n
, /* Looping vars */
798 dot_count
, /* Number of bytes to print */
799 dot_min
; /* Minimum number of bytes */
800 unsigned char *dot_ptr
, /* Pointer to print data */
801 *ptr
; /* Current data */
804 dot_min
= DotBytes
* DotColumns
;
806 if (LineBuffers
[row
][0] != 0 ||
807 memcmp(LineBuffers
[row
], LineBuffers
[row
] + 1, header
->cupsWidth
* DotBytes
- 1))
810 * Skip leading space...
814 dot_count
= header
->cupsWidth
* DotBytes
;
815 dot_ptr
= LineBuffers
[row
];
817 while (dot_count
>= dot_min
&& dot_ptr
[0] == 0 &&
818 memcmp(dot_ptr
, dot_ptr
+ 1, dot_min
- 1) == 0)
822 dot_count
-= dot_min
;
826 * Skip trailing space...
829 while (dot_count
>= dot_min
&& dot_ptr
[dot_count
- dot_min
] == 0 &&
830 memcmp(dot_ptr
+ dot_count
- dot_min
,
831 dot_ptr
+ dot_count
- dot_min
+ 1, dot_min
- 1) == 0)
832 dot_count
-= dot_min
;
835 * Position print head for printing...
844 putchar((int)(i
& 255));
845 putchar((int)(i
>> 8));
849 * Start bitmap graphics for this line...
852 printf("\033*"); /* Select bit image */
853 switch (header
->HWResolution
[0])
855 case 60 : /* 60x60/72 DPI gfx */
858 case 120 : /* 120x60/72 DPI gfx */
861 case 180 : /* 180 DPI gfx */
864 case 240 : /* 240x72 DPI gfx */
867 case 360 : /* 360x180/360 DPI gfx */
868 if (header
->HWResolution
[1] == 180)
870 if (Shingling
&& LineCount
!= 0)
871 putchar(40); /* 360x180 fast */
873 putchar(41); /* 360x180 slow */
877 if (Shingling
&& LineCount
!= 0)
878 putchar(72); /* 360x360 fast */
880 putchar(73); /* 360x360 slow */
885 n
= dot_count
/ DotBytes
;
886 putchar((int)(n
& 255));
887 putchar((int)(n
/ 256));
890 * Write the graphics data...
893 if (header
->HWResolution
[0] == 120 ||
894 header
->HWResolution
[0] == 240)
897 * Need to interleave the dots to avoid hosing the print head...
900 for (n
= dot_count
/ 2, ptr
= dot_ptr
; n
> 0; n
--, ptr
+= 2)
910 * Move the head back and print the odd bytes...
919 putchar((int)(i
& 255));
920 putchar((int)(i
>> 8));
923 if (header
->HWResolution
[0] == 120)
924 printf("\033*\001"); /* Select bit image */
926 printf("\033*\003"); /* Select bit image */
928 n
= (unsigned)dot_count
/ DotBytes
;
929 putchar((int)(n
& 255));
930 putchar((int)(n
/ 256));
932 for (n
= dot_count
/ 2, ptr
= dot_ptr
+ 1; n
> 0; n
--, ptr
+= 2)
942 pwrite(dot_ptr
, dot_count
);
951 if (Shingling
&& row
== 1)
953 if (header
->HWResolution
[1] == 360)
962 * Clear the buffer...
965 memset(LineBuffers
[row
], 0, header
->cupsWidth
* DotBytes
);
970 * 'main()' - Main entry and processing of driver.
973 int /* O - Exit status */
974 main(int argc
, /* I - Number of command-line arguments */
975 char *argv
[]) /* I - Command-line arguments */
977 int fd
; /* File descriptor */
978 cups_raster_t
*ras
; /* Raster stream for printing */
979 cups_page_header2_t header
; /* Page header from file */
980 ppd_file_t
*ppd
; /* PPD file */
981 int page
; /* Current page */
982 unsigned y
; /* Current line */
983 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
984 struct sigaction action
; /* Actions for POSIX signals */
985 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
989 * Make sure status messages are not buffered...
992 setbuf(stderr
, NULL
);
995 * Check command-line...
998 if (argc
< 6 || argc
> 7)
1001 * We don't have the correct number of arguments; write an error message
1005 _cupsLangPrintFilter(stderr
, "ERROR",
1006 _("%s job-id user title copies options [file]"),
1012 * Open the page stream...
1017 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
1019 _cupsLangPrintError("ERROR", _("Unable to open raster file"));
1027 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
1030 * Register a signal handler to eject the current page if the
1036 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1037 sigset(SIGTERM
, CancelJob
);
1038 #elif defined(HAVE_SIGACTION)
1039 memset(&action
, 0, sizeof(action
));
1041 sigemptyset(&action
.sa_mask
);
1042 action
.sa_handler
= CancelJob
;
1043 sigaction(SIGTERM
, &action
, NULL
);
1045 signal(SIGTERM
, CancelJob
);
1046 #endif /* HAVE_SIGSET */
1049 * Initialize the print device...
1052 ppd
= ppdOpenFile(getenv("PPD"));
1055 ppd_status_t status
; /* PPD error */
1056 int linenum
; /* Line number */
1058 _cupsLangPrintFilter(stderr
, "ERROR",
1059 _("The PPD file could not be opened."));
1061 status
= ppdLastError(&linenum
);
1063 fprintf(stderr
, "DEBUG: %s on line %d.\n", ppdErrorString(status
), linenum
);
1068 Model
= ppd
->model_number
;
1073 * Process pages as needed...
1078 while (cupsRasterReadHeader2(ras
, &header
))
1081 * Write a status message with the page number and number of copies.
1089 fprintf(stderr
, "PAGE: %d %d\n", page
, header
.NumCopies
);
1090 _cupsLangPrintFilter(stderr
, "INFO", _("Starting page %d."), page
);
1096 StartPage(ppd
, &header
);
1099 * Loop for each line on the page...
1102 for (y
= 0; y
< header
.cupsHeight
; y
++)
1105 * Let the user know how far we have progressed...
1113 _cupsLangPrintFilter(stderr
, "INFO",
1114 _("Printing page %d, %u%% complete."),
1115 page
, 100 * y
/ header
.cupsHeight
);
1116 fprintf(stderr
, "ATTR: job-media-progress=%u\n",
1117 100 * y
/ header
.cupsHeight
);
1121 * Read a line of graphics...
1124 if (cupsRasterReadPixels(ras
, Planes
[0], header
.cupsBytesPerLine
) < 1)
1128 * Write it to the printer...
1131 OutputLine(&header
);
1138 _cupsLangPrintFilter(stderr
, "INFO", _("Finished page %d."), page
);
1147 * Shutdown the printer...
1155 * Close the raster stream...
1158 cupsRasterClose(ras
);
1163 * If no pages were printed, send an error message...
1168 _cupsLangPrintFilter(stderr
, "ERROR", _("No pages were found."));