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 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
11 * Include necessary headers...
14 #include <cups/cups.h>
16 #include <cups/string-private.h>
17 #include <cups/language-private.h>
18 #include <cups/raster.h>
32 #define EPSON_ICOLOR 4
33 #define EPSON_IPHOTO 5
40 #define pwrite(s,n) fwrite((s), 1, (n), stdout)
47 unsigned char *Planes
[6], /* Output buffers */
48 *CompBuffer
, /* Compression buffer */
49 *LineBuffers
[2]; /* Line bitmap buffers */
50 int Model
, /* Model number */
51 EjectPage
, /* Eject the page when done? */
52 Shingling
, /* Shingle output? */
53 Canceled
; /* Has the current job been canceled? */
54 unsigned NumPlanes
, /* Number of color planes */
55 Feed
, /* Number of lines to skip */
56 DotBit
, /* Bit in buffers */
57 DotBytes
, /* # bytes in a dot column */
58 DotColumns
, /* # columns in 1/60 inch */
59 LineCount
, /* # of lines processed */
60 EvenOffset
, /* Offset into 'even' buffers */
61 OddOffset
; /* Offset into 'odd' buffers */
69 void StartPage(const ppd_file_t
*ppd
, const cups_page_header2_t
*header
);
70 void EndPage(const cups_page_header2_t
*header
);
73 void CancelJob(int sig
);
74 void CompressData(const unsigned char *line
, unsigned length
, unsigned plane
,
75 unsigned type
, unsigned xstep
, unsigned ystep
);
76 void OutputLine(const cups_page_header2_t
*header
);
77 void OutputRows(const cups_page_header2_t
*header
, int row
);
81 * 'Setup()' - Prepare the printer for printing.
87 const char *device_uri
; /* The device for the printer... */
91 * EPSON USB printers need an additional command issued at the
92 * beginning of each job to exit from "packet" mode...
95 if ((device_uri
= getenv("DEVICE_URI")) != NULL
&&
96 strncmp(device_uri
, "usb:", 4) == 0 && Model
>= EPSON_ICOLOR
)
97 pwrite("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
102 * 'StartPage()' - Start a page of graphics.
107 const ppd_file_t
*ppd
, /* I - PPD file */
108 const cups_page_header2_t
*header
) /* I - Page header */
110 int n
, t
; /* Numbers */
111 unsigned plane
; /* Looping var */
115 * Show page device dictionary...
118 fprintf(stderr
, "DEBUG: StartPage...\n");
119 fprintf(stderr
, "DEBUG: Duplex = %d\n", header
->Duplex
);
120 fprintf(stderr
, "DEBUG: HWResolution = [ %d %d ]\n", header
->HWResolution
[0], header
->HWResolution
[1]);
121 fprintf(stderr
, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", header
->ImagingBoundingBox
[0], header
->ImagingBoundingBox
[1], header
->ImagingBoundingBox
[2], header
->ImagingBoundingBox
[3]);
122 fprintf(stderr
, "DEBUG: Margins = [ %d %d ]\n", header
->Margins
[0], header
->Margins
[1]);
123 fprintf(stderr
, "DEBUG: ManualFeed = %d\n", header
->ManualFeed
);
124 fprintf(stderr
, "DEBUG: MediaPosition = %d\n", header
->MediaPosition
);
125 fprintf(stderr
, "DEBUG: NumCopies = %d\n", header
->NumCopies
);
126 fprintf(stderr
, "DEBUG: Orientation = %d\n", header
->Orientation
);
127 fprintf(stderr
, "DEBUG: PageSize = [ %d %d ]\n", header
->PageSize
[0], header
->PageSize
[1]);
128 fprintf(stderr
, "DEBUG: cupsWidth = %d\n", header
->cupsWidth
);
129 fprintf(stderr
, "DEBUG: cupsHeight = %d\n", header
->cupsHeight
);
130 fprintf(stderr
, "DEBUG: cupsMediaType = %d\n", header
->cupsMediaType
);
131 fprintf(stderr
, "DEBUG: cupsBitsPerColor = %d\n", header
->cupsBitsPerColor
);
132 fprintf(stderr
, "DEBUG: cupsBitsPerPixel = %d\n", header
->cupsBitsPerPixel
);
133 fprintf(stderr
, "DEBUG: cupsBytesPerLine = %d\n", header
->cupsBytesPerLine
);
134 fprintf(stderr
, "DEBUG: cupsColorOrder = %d\n", header
->cupsColorOrder
);
135 fprintf(stderr
, "DEBUG: cupsColorSpace = %d\n", header
->cupsColorSpace
);
136 fprintf(stderr
, "DEBUG: cupsCompression = %d\n", header
->cupsCompression
);
139 * Send a reset sequence.
142 if (ppd
&& ppd
->nickname
&& strstr(ppd
->nickname
, "OKIDATA") != NULL
)
143 printf("\033{A"); /* Set EPSON emulation mode */
148 * See which type of printer we are using...
155 printf("\033P\022"); /* Set 10 CPI */
157 if (header
->HWResolution
[0] == 360 || header
->HWResolution
[0] == 240)
159 printf("\033x1"); /* LQ printing */
160 printf("\033U1"); /* Unidirectional */
164 printf("\033x0"); /* Draft printing */
165 printf("\033U0"); /* Bidirectional */
168 printf("\033l%c\033Q%c", 0, /* Side margins */
169 (int)(10.0 * header
->PageSize
[0] / 72.0 + 0.5));
170 printf("\033\062\033C%c", /* Page length in 1/6th inches */
171 (int)(header
->PageSize
[1] / 12.0 + 0.5));
172 printf("\033N%c", 0); /* Bottom margin */
173 printf("\033O"); /* No perforation skip */
176 * Setup various buffer limits...
179 DotBytes
= header
->cupsRowCount
/ 8;
180 DotColumns
= header
->HWResolution
[0] / 60;
183 if (Model
== EPSON_9PIN
)
184 printf("\033\063\030"); /* Set line feed */
186 switch (header
->HWResolution
[0])
191 printf("\033\063\030"); /* Set line feed */
198 if (header
->HWResolution
[1] == 180)
199 printf("\033\063\010");/* Set line feed */
201 printf("\033+\010"); /* Set line feed */
208 * Set graphics mode...
211 pwrite("\033(G\001\000\001", 6); /* Graphics mode */
214 * Set the media size...
217 if (Model
< EPSON_ICOLOR
)
219 pwrite("\033(U\001\000", 5); /* Resolution/units */
220 putchar((int)(3600 / header
->HWResolution
[1]));
224 pwrite("\033(U\005\000", 5);
225 putchar((int)(1440 / header
->HWResolution
[1]));
226 putchar((int)(1440 / header
->HWResolution
[1]));
227 putchar((int)(1440 / header
->HWResolution
[0]));
228 putchar(0xa0); /* n/1440ths... */
232 n
= (int)(header
->PageSize
[1] * header
->HWResolution
[1] / 72.0);
234 pwrite("\033(C\002\000", 5); /* Page length */
239 t
= (int)((ppd
->sizes
[1].length
- ppd
->sizes
[1].top
) * header
->HWResolution
[1] / 72.0);
243 pwrite("\033(c\004\000", 5); /* Top & bottom margins */
249 if (header
->HWResolution
[1] == 720)
251 pwrite("\033(i\001\000\001", 6); /* Microweave */
252 pwrite("\033(e\002\000\000\001", 7); /* Small dots */
255 pwrite("\033(V\002\000\000\000", 7); /* Set absolute position 0 */
267 if (header
->cupsColorSpace
== CUPS_CSPACE_CMY
)
269 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMY
)
271 else if (header
->cupsColorSpace
== CUPS_CSPACE_KCMYcm
)
276 Feed
= 0; /* No blank lines yet */
279 * Allocate memory for a line/row of graphics...
282 if ((Planes
[0] = malloc(header
->cupsBytesPerLine
+ NumPlanes
)) == NULL
)
284 fputs("ERROR: Unable to allocate memory\n", stderr
);
288 for (plane
= 1; plane
< NumPlanes
; plane
++)
289 Planes
[plane
] = Planes
[0] + plane
* header
->cupsBytesPerLine
/ NumPlanes
;
291 if (header
->cupsCompression
|| DotBytes
)
293 if ((CompBuffer
= calloc(2, header
->cupsWidth
+ 1)) == NULL
)
295 fputs("ERROR: Unable to allocate memory\n", stderr
);
304 if ((LineBuffers
[0] = calloc((size_t)DotBytes
, header
->cupsWidth
* (size_t)(Shingling
+ 1))) == NULL
)
306 fputs("ERROR: Unable to allocate memory\n", stderr
);
310 LineBuffers
[1] = LineBuffers
[0] + DotBytes
* header
->cupsWidth
;
320 * 'EndPage()' - Finish a page of graphics.
325 const cups_page_header2_t
*header
) /* I - Page header */
327 if (DotBytes
&& header
)
330 * Flush remaining graphics as needed...
335 if (DotBit
< 128 || EvenOffset
)
336 OutputRows(header
, 0);
338 else if (OddOffset
> EvenOffset
)
340 OutputRows(header
, 1);
341 OutputRows(header
, 0);
345 OutputRows(header
, 0);
346 OutputRows(header
, 1);
351 * Eject the current page...
354 putchar(12); /* Form feed */
367 free(LineBuffers
[0]);
372 * 'Shutdown()' - Shutdown the printer.
379 * Send a reset sequence.
387 * 'CancelJob()' - Cancel the current job...
391 CancelJob(int sig
) /* I - Signal */
400 * 'CompressData()' - Compress a line of graphics.
404 CompressData(const unsigned char *line
, /* I - Data to compress */
405 unsigned length
,/* I - Number of bytes */
406 unsigned plane
, /* I - Color plane */
407 unsigned type
, /* I - Type of compression */
408 unsigned xstep
, /* I - X resolution */
409 unsigned ystep
) /* I - Y resolution */
411 const unsigned char *line_ptr
, /* Current byte pointer */
412 *line_end
, /* End-of-line byte pointer */
413 *start
; /* Start of compression sequence */
414 unsigned char *comp_ptr
, /* Pointer into compression buffer */
415 temp
; /* Current byte */
416 int count
; /* Count of bytes for output */
417 static int ctable
[6] = { 0, 2, 1, 4, 18, 17 };
418 /* KCMYcm color values */
426 line_end
= line
+ length
;
429 * Do depletion for 720 DPI printing...
434 for (comp_ptr
= (unsigned char *)line
; comp_ptr
< line_end
;)
437 * Grab the current byte...
443 * Check adjacent bits...
446 if ((temp
& 0xc0) == 0xc0)
448 if ((temp
& 0x60) == 0x60)
450 if ((temp
& 0x30) == 0x30)
452 if ((temp
& 0x18) == 0x18)
454 if ((temp
& 0x0c) == 0x0c)
456 if ((temp
& 0x06) == 0x06)
458 if ((temp
& 0x03) == 0x03)
464 * Check the last bit in the current byte and the first bit in the
468 if ((temp
& 0x01) && comp_ptr
< line_end
&& *comp_ptr
& 0x80)
477 * Do no compression...
483 * Do TIFF pack-bits encoding...
486 comp_ptr
= CompBuffer
;
488 while (line_ptr
< line_end
)
490 if ((line_ptr
+ 1) >= line_end
)
493 * Single byte on the end...
497 *comp_ptr
++ = *line_ptr
++;
499 else if (line_ptr
[0] == line_ptr
[1])
502 * Repeated sequence...
508 while (line_ptr
< (line_end
- 1) &&
509 line_ptr
[0] == line_ptr
[1] &&
516 *comp_ptr
++ = (unsigned char)(257 - count
);
517 *comp_ptr
++ = *line_ptr
++;
522 * Non-repeated sequence...
529 while (line_ptr
< (line_end
- 1) &&
530 line_ptr
[0] != line_ptr
[1] &&
537 *comp_ptr
++ = (unsigned char)(count
- 1);
539 memcpy(comp_ptr
, start
, (size_t)count
);
544 line_ptr
= CompBuffer
;
549 putchar(0x0d); /* Move print head to left margin */
551 if (Model
< EPSON_ICOLOR
)
554 * Do graphics the "old" way...
564 printf("\033(r%c%c%c%c", 2, 0, 1, ctable
[plane
] & 15);
565 /* Set extended color */
566 else if (NumPlanes
== 3)
567 printf("\033r%c", ctable
[plane
+ 1]);
570 printf("\033r%c", ctable
[plane
]); /* Set color */
574 * Send a raster plane...
578 printf("\033."); /* Raster graphics */
583 putchar((int)length
);
584 putchar((int)(length
>> 8));
589 * Do graphics the "new" way...
593 putchar(ctable
[plane
]);
596 putchar((int)length
);
597 putchar((int)(length
>> 8));
602 pwrite(line_ptr
, (size_t)(line_end
- line_ptr
));
608 * 'OutputLine()' - Output a line of graphics.
613 const cups_page_header2_t
*header
) /* I - Page header */
615 if (header
->cupsRowCount
)
618 unsigned char *tempptr
,
623 const unsigned char *pixel
;
628 * Collect bitmap data in the line buffers and write after each buffer.
631 for (x
= header
->cupsWidth
, bit
= 128, pixel
= Planes
[0],
653 * Copy the holding buffer to the output buffer, shingling as necessary...
656 if (Shingling
&& LineCount
!= 0)
659 * Shingle the output...
664 evenptr
= LineBuffers
[1] + OddOffset
;
665 oddptr
= LineBuffers
[0] + EvenOffset
+ DotBytes
;
669 evenptr
= LineBuffers
[0] + EvenOffset
;
670 oddptr
= LineBuffers
[1] + OddOffset
+ DotBytes
;
673 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
;
675 width
-= 2, tempptr
+= 2, oddptr
+= DotBytes
* 2,
676 evenptr
+= DotBytes
* 2)
678 evenptr
[0] = tempptr
[0];
679 oddptr
[0] = tempptr
[1];
684 evenptr
[0] = tempptr
[0];
685 oddptr
[0] = tempptr
[1];
691 * Don't shingle the output...
694 for (width
= header
->cupsWidth
, tempptr
= CompBuffer
,
695 evenptr
= LineBuffers
[0] + EvenOffset
;
697 width
--, tempptr
++, evenptr
+= DotBytes
)
698 *evenptr
= tempptr
[0];
701 if (Shingling
&& LineCount
!= 0)
706 if (EvenOffset
== DotBytes
)
709 OutputRows(header
, 0);
712 if (OddOffset
== DotBytes
)
715 OutputRows(header
, 1);
722 if (EvenOffset
== DotBytes
)
725 OutputRows(header
, 0);
732 memset(CompBuffer
, 0, header
->cupsWidth
);
737 unsigned plane
; /* Current plane */
738 unsigned bytes
; /* Bytes per plane */
739 unsigned xstep
, ystep
; /* X & Y resolutions */
742 * Write a single line of bitmap data as needed...
745 xstep
= 3600 / header
->HWResolution
[0];
746 ystep
= 3600 / header
->HWResolution
[1];
747 bytes
= header
->cupsBytesPerLine
/ NumPlanes
;
749 for (plane
= 0; plane
< NumPlanes
; plane
++)
755 if (!Planes
[plane
][0] &&
756 memcmp(Planes
[plane
], Planes
[plane
] + 1, (size_t)bytes
- 1) == 0)
760 * Output whitespace as needed...
765 pwrite("\033(v\002\000", 5); /* Relative vertical position */
767 putchar((int)(Feed
>> 8));
772 CompressData(Planes
[plane
], bytes
, plane
, header
->cupsCompression
, xstep
, ystep
);
781 * 'OutputRows()' - Output 8, 24, or 48 rows.
786 const cups_page_header2_t
*header
, /* I - Page image header */
787 int row
) /* I - Row number (0 or 1) */
789 unsigned i
, n
, /* Looping vars */
790 dot_count
, /* Number of bytes to print */
791 dot_min
; /* Minimum number of bytes */
792 unsigned char *dot_ptr
, /* Pointer to print data */
793 *ptr
; /* Current data */
796 dot_min
= DotBytes
* DotColumns
;
798 if (LineBuffers
[row
][0] != 0 ||
799 memcmp(LineBuffers
[row
], LineBuffers
[row
] + 1, header
->cupsWidth
* DotBytes
- 1))
802 * Skip leading space...
806 dot_count
= header
->cupsWidth
* DotBytes
;
807 dot_ptr
= LineBuffers
[row
];
809 while (dot_count
>= dot_min
&& dot_ptr
[0] == 0 &&
810 memcmp(dot_ptr
, dot_ptr
+ 1, dot_min
- 1) == 0)
814 dot_count
-= dot_min
;
818 * Skip trailing space...
821 while (dot_count
>= dot_min
&& dot_ptr
[dot_count
- dot_min
] == 0 &&
822 memcmp(dot_ptr
+ dot_count
- dot_min
,
823 dot_ptr
+ dot_count
- dot_min
+ 1, dot_min
- 1) == 0)
824 dot_count
-= dot_min
;
827 * Position print head for printing...
836 putchar((int)(i
& 255));
837 putchar((int)(i
>> 8));
841 * Start bitmap graphics for this line...
844 printf("\033*"); /* Select bit image */
845 switch (header
->HWResolution
[0])
847 case 60 : /* 60x60/72 DPI gfx */
850 case 120 : /* 120x60/72 DPI gfx */
853 case 180 : /* 180 DPI gfx */
856 case 240 : /* 240x72 DPI gfx */
859 case 360 : /* 360x180/360 DPI gfx */
860 if (header
->HWResolution
[1] == 180)
862 if (Shingling
&& LineCount
!= 0)
863 putchar(40); /* 360x180 fast */
865 putchar(41); /* 360x180 slow */
869 if (Shingling
&& LineCount
!= 0)
870 putchar(72); /* 360x360 fast */
872 putchar(73); /* 360x360 slow */
877 n
= dot_count
/ DotBytes
;
878 putchar((int)(n
& 255));
879 putchar((int)(n
/ 256));
882 * Write the graphics data...
885 if (header
->HWResolution
[0] == 120 ||
886 header
->HWResolution
[0] == 240)
889 * Need to interleave the dots to avoid hosing the print head...
892 for (n
= dot_count
/ 2, ptr
= dot_ptr
; n
> 0; n
--, ptr
+= 2)
902 * Move the head back and print the odd bytes...
911 putchar((int)(i
& 255));
912 putchar((int)(i
>> 8));
915 if (header
->HWResolution
[0] == 120)
916 printf("\033*\001"); /* Select bit image */
918 printf("\033*\003"); /* Select bit image */
920 n
= (unsigned)dot_count
/ DotBytes
;
921 putchar((int)(n
& 255));
922 putchar((int)(n
/ 256));
924 for (n
= dot_count
/ 2, ptr
= dot_ptr
+ 1; n
> 0; n
--, ptr
+= 2)
934 pwrite(dot_ptr
, dot_count
);
943 if (Shingling
&& row
== 1)
945 if (header
->HWResolution
[1] == 360)
954 * Clear the buffer...
957 memset(LineBuffers
[row
], 0, header
->cupsWidth
* DotBytes
);
962 * 'main()' - Main entry and processing of driver.
965 int /* O - Exit status */
966 main(int argc
, /* I - Number of command-line arguments */
967 char *argv
[]) /* I - Command-line arguments */
969 int fd
; /* File descriptor */
970 cups_raster_t
*ras
; /* Raster stream for printing */
971 cups_page_header2_t header
; /* Page header from file */
972 ppd_file_t
*ppd
; /* PPD file */
973 int page
; /* Current page */
974 unsigned y
; /* Current line */
975 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
976 struct sigaction action
; /* Actions for POSIX signals */
977 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
981 * Make sure status messages are not buffered...
984 setbuf(stderr
, NULL
);
987 * Check command-line...
990 if (argc
< 6 || argc
> 7)
993 * We don't have the correct number of arguments; write an error message
997 _cupsLangPrintFilter(stderr
, "ERROR",
998 _("%s job-id user title copies options [file]"),
1004 * Open the page stream...
1009 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
1011 _cupsLangPrintError("ERROR", _("Unable to open raster file"));
1019 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
1022 * Register a signal handler to eject the current page if the
1028 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1029 sigset(SIGTERM
, CancelJob
);
1030 #elif defined(HAVE_SIGACTION)
1031 memset(&action
, 0, sizeof(action
));
1033 sigemptyset(&action
.sa_mask
);
1034 action
.sa_handler
= CancelJob
;
1035 sigaction(SIGTERM
, &action
, NULL
);
1037 signal(SIGTERM
, CancelJob
);
1038 #endif /* HAVE_SIGSET */
1041 * Initialize the print device...
1044 ppd
= ppdOpenFile(getenv("PPD"));
1047 ppd_status_t status
; /* PPD error */
1048 int linenum
; /* Line number */
1050 _cupsLangPrintFilter(stderr
, "ERROR",
1051 _("The PPD file could not be opened."));
1053 status
= ppdLastError(&linenum
);
1055 fprintf(stderr
, "DEBUG: %s on line %d.\n", ppdErrorString(status
), linenum
);
1060 Model
= ppd
->model_number
;
1065 * Process pages as needed...
1070 while (cupsRasterReadHeader2(ras
, &header
))
1073 * Write a status message with the page number and number of copies.
1081 fprintf(stderr
, "PAGE: %d %d\n", page
, header
.NumCopies
);
1082 _cupsLangPrintFilter(stderr
, "INFO", _("Starting page %d."), page
);
1088 StartPage(ppd
, &header
);
1091 * Loop for each line on the page...
1094 for (y
= 0; y
< header
.cupsHeight
; y
++)
1097 * Let the user know how far we have progressed...
1105 _cupsLangPrintFilter(stderr
, "INFO",
1106 _("Printing page %d, %u%% complete."),
1107 page
, 100 * y
/ header
.cupsHeight
);
1108 fprintf(stderr
, "ATTR: job-media-progress=%u\n",
1109 100 * y
/ header
.cupsHeight
);
1113 * Read a line of graphics...
1116 if (cupsRasterReadPixels(ras
, Planes
[0], header
.cupsBytesPerLine
) < 1)
1120 * Write it to the printer...
1123 OutputLine(&header
);
1130 _cupsLangPrintFilter(stderr
, "INFO", _("Finished page %d."), page
);
1139 * Shutdown the printer...
1147 * Close the raster stream...
1150 cupsRasterClose(ras
);
1155 * If no pages were printed, send an error message...
1160 _cupsLangPrintFilter(stderr
, "ERROR", _("No pages were found."));