4 * Advanced EPSON ESC/P raster driver for CUPS.
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1993-2005 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/".
17 * Setup() - Prepare the printer for graphics output.
18 * StartPage() - Start a page of graphics.
19 * EndPage() - Finish a page of graphics.
20 * Shutdown() - Shutdown a printer.
21 * CancelJob() - Cancel the current job...
22 * CompressData() - Compress a line of graphics.
23 * OutputBand() - Output a band of graphics.
24 * ProcessLine() - Read graphics from the page stream and output
26 * main() - Main entry and processing of driver.
30 * Include necessary headers...
34 #include <cups/language-private.h>
35 #include <cups/string-private.h>
36 #include "data/escp.h"
44 typedef struct cups_weave_str
46 struct cups_weave_str
*prev
, /* Previous band */
47 *next
; /* Next band */
48 int x
, y
, /* Column/Line on the page */
49 plane
, /* Color plane */
50 dirty
, /* Is this buffer dirty? */
51 row
, /* Row in the buffer */
52 count
; /* Max rows this pass */
53 unsigned char *buffer
; /* Data buffer */
61 cups_rgb_t
*RGB
; /* RGB color separation data */
62 cups_cmyk_t
*CMYK
; /* CMYK color separation data */
63 unsigned char *PixelBuffer
, /* Pixel buffer */
64 *CMYKBuffer
, /* CMYK buffer */
65 *OutputBuffers
[7], /* Output buffers */
66 *DotBuffers
[7], /* Dot buffers */
67 *CompBuffer
; /* Compression buffer */
68 short *InputBuffer
; /* Color separation buffer */
69 cups_weave_t
*DotAvailList
, /* Available buffers */
70 *DotUsedList
, /* Used buffers */
71 *DotBands
[128][7]; /* Buffers in use */
72 int DotBufferSize
, /* Size of dot buffers */
73 DotRowMax
, /* Maximum row number in buffer */
74 DotColStep
, /* Step for each output column */
75 DotRowStep
, /* Step for each output line */
76 DotRowFeed
, /* Amount to feed for interleave */
77 DotRowCount
, /* Number of rows to output */
78 DotRowOffset
[7], /* Offset for each color on print head */
79 DotRowCurrent
, /* Current row */
80 DotSize
; /* Dot size (Pro 5000 only) */
81 int PrinterPlanes
, /* # of color planes */
82 BitPlanes
, /* # of bit planes per color */
83 PrinterTop
, /* Top of page */
84 PrinterLength
; /* Length of page */
85 cups_lut_t
*DitherLuts
[7]; /* Lookup tables for dithering */
86 cups_dither_t
*DitherStates
[7]; /* Dither state tables */
87 int OutputFeed
; /* Number of lines to skip */
88 int Canceled
; /* Is the job canceled? */
95 void Setup(ppd_file_t
*);
96 void StartPage(ppd_file_t
*, cups_page_header2_t
*);
97 void EndPage(ppd_file_t
*, cups_page_header2_t
*);
98 void Shutdown(ppd_file_t
*);
100 void AddBand(cups_weave_t
*band
);
101 void CancelJob(int sig
);
102 void CompressData(ppd_file_t
*, const unsigned char *, const int,
103 int, int, const int, const int, const int,
105 void OutputBand(ppd_file_t
*, cups_page_header2_t
*,
107 void ProcessLine(ppd_file_t
*, cups_raster_t
*,
108 cups_page_header2_t
*, const int y
);
112 * 'Setup()' - Prepare a printer for graphics output.
116 Setup(ppd_file_t
*ppd
) /* I - PPD file */
119 * Some EPSON printers need an additional command issued at the
120 * beginning of each job to exit from USB "packet" mode...
123 if (ppd
->model_number
& ESCP_USB
)
124 cupsWritePrintData("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
129 * 'StartPage()' - Start a page of graphics.
133 StartPage(ppd_file_t
*ppd
, /* I - PPD file */
134 cups_page_header2_t
*header
) /* I - Page header */
136 int i
, y
; /* Looping vars */
137 int subrow
, /* Current subrow */
138 modrow
, /* Subrow modulus */
139 plane
; /* Current color plane */
140 unsigned char *ptr
; /* Pointer into dot buffer */
141 int bands
; /* Number of bands to allocate */
142 int units
; /* Units for resolution */
143 cups_weave_t
*band
; /* Current band */
144 const char *colormodel
; /* Color model string */
145 char resolution
[PPD_MAX_NAME
],
146 /* Resolution string */
147 spec
[PPD_MAX_NAME
]; /* PPD attribute name */
148 ppd_attr_t
*attr
; /* Attribute from PPD file */
149 const float default_lut
[2] = /* Default dithering lookup table */
156 fprintf(stderr
, "DEBUG: StartPage...\n");
157 fprintf(stderr
, "DEBUG: MediaClass = \"%s\"\n", header
->MediaClass
);
158 fprintf(stderr
, "DEBUG: MediaColor = \"%s\"\n", header
->MediaColor
);
159 fprintf(stderr
, "DEBUG: MediaType = \"%s\"\n", header
->MediaType
);
160 fprintf(stderr
, "DEBUG: OutputType = \"%s\"\n", header
->OutputType
);
162 fprintf(stderr
, "DEBUG: AdvanceDistance = %d\n", header
->AdvanceDistance
);
163 fprintf(stderr
, "DEBUG: AdvanceMedia = %d\n", header
->AdvanceMedia
);
164 fprintf(stderr
, "DEBUG: Collate = %d\n", header
->Collate
);
165 fprintf(stderr
, "DEBUG: CutMedia = %d\n", header
->CutMedia
);
166 fprintf(stderr
, "DEBUG: Duplex = %d\n", header
->Duplex
);
167 fprintf(stderr
, "DEBUG: HWResolution = [ %d %d ]\n", header
->HWResolution
[0],
168 header
->HWResolution
[1]);
169 fprintf(stderr
, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
170 header
->ImagingBoundingBox
[0], header
->ImagingBoundingBox
[1],
171 header
->ImagingBoundingBox
[2], header
->ImagingBoundingBox
[3]);
172 fprintf(stderr
, "DEBUG: InsertSheet = %d\n", header
->InsertSheet
);
173 fprintf(stderr
, "DEBUG: Jog = %d\n", header
->Jog
);
174 fprintf(stderr
, "DEBUG: LeadingEdge = %d\n", header
->LeadingEdge
);
175 fprintf(stderr
, "DEBUG: Margins = [ %d %d ]\n", header
->Margins
[0],
177 fprintf(stderr
, "DEBUG: ManualFeed = %d\n", header
->ManualFeed
);
178 fprintf(stderr
, "DEBUG: MediaPosition = %d\n", header
->MediaPosition
);
179 fprintf(stderr
, "DEBUG: MediaWeight = %d\n", header
->MediaWeight
);
180 fprintf(stderr
, "DEBUG: MirrorPrint = %d\n", header
->MirrorPrint
);
181 fprintf(stderr
, "DEBUG: NegativePrint = %d\n", header
->NegativePrint
);
182 fprintf(stderr
, "DEBUG: NumCopies = %d\n", header
->NumCopies
);
183 fprintf(stderr
, "DEBUG: Orientation = %d\n", header
->Orientation
);
184 fprintf(stderr
, "DEBUG: OutputFaceUp = %d\n", header
->OutputFaceUp
);
185 fprintf(stderr
, "DEBUG: PageSize = [ %d %d ]\n", header
->PageSize
[0],
186 header
->PageSize
[1]);
187 fprintf(stderr
, "DEBUG: Separations = %d\n", header
->Separations
);
188 fprintf(stderr
, "DEBUG: TraySwitch = %d\n", header
->TraySwitch
);
189 fprintf(stderr
, "DEBUG: Tumble = %d\n", header
->Tumble
);
190 fprintf(stderr
, "DEBUG: cupsWidth = %d\n", header
->cupsWidth
);
191 fprintf(stderr
, "DEBUG: cupsHeight = %d\n", header
->cupsHeight
);
192 fprintf(stderr
, "DEBUG: cupsMediaType = %d\n", header
->cupsMediaType
);
193 fprintf(stderr
, "DEBUG: cupsBitsPerColor = %d\n", header
->cupsBitsPerColor
);
194 fprintf(stderr
, "DEBUG: cupsBitsPerPixel = %d\n", header
->cupsBitsPerPixel
);
195 fprintf(stderr
, "DEBUG: cupsBytesPerLine = %d\n", header
->cupsBytesPerLine
);
196 fprintf(stderr
, "DEBUG: cupsColorOrder = %d\n", header
->cupsColorOrder
);
197 fprintf(stderr
, "DEBUG: cupsColorSpace = %d\n", header
->cupsColorSpace
);
198 fprintf(stderr
, "DEBUG: cupsCompression = %d\n", header
->cupsCompression
);
199 fprintf(stderr
, "DEBUG: cupsRowCount = %d\n", header
->cupsRowCount
);
200 fprintf(stderr
, "DEBUG: cupsRowFeed = %d\n", header
->cupsRowFeed
);
201 fprintf(stderr
, "DEBUG: cupsRowStep = %d\n", header
->cupsRowStep
);
204 * Figure out the color model and spec strings...
207 switch (header
->cupsColorSpace
)
210 colormodel
= "Black";
216 case CUPS_CSPACE_RGB
:
219 case CUPS_CSPACE_CMYK
:
224 if (header
->HWResolution
[0] != header
->HWResolution
[1])
225 snprintf(resolution
, sizeof(resolution
), "%dx%ddpi",
226 header
->HWResolution
[0], header
->HWResolution
[1]);
228 snprintf(resolution
, sizeof(resolution
), "%ddpi",
229 header
->HWResolution
[0]);
231 if (!header
->MediaType
[0])
232 strcpy(header
->MediaType
, "Plain");
235 * Load the appropriate color profiles...
241 fputs("DEBUG: Attempting to load color profiles using the following values:\n", stderr
);
242 fprintf(stderr
, "DEBUG: ColorModel = %s\n", colormodel
);
243 fprintf(stderr
, "DEBUG: MediaType = %s\n", header
->MediaType
);
244 fprintf(stderr
, "DEBUG: Resolution = %s\n", resolution
);
246 if (header
->cupsColorSpace
== CUPS_CSPACE_RGB
||
247 header
->cupsColorSpace
== CUPS_CSPACE_W
)
248 RGB
= cupsRGBLoad(ppd
, colormodel
, header
->MediaType
, resolution
);
252 CMYK
= cupsCMYKLoad(ppd
, colormodel
, header
->MediaType
, resolution
);
255 fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr
);
258 fputs("DEBUG: Loaded CMYK separation from PPD.\n", stderr
);
261 fputs("DEBUG: Loading default CMYK separation.\n", stderr
);
262 CMYK
= cupsCMYKNew(4);
265 PrinterPlanes
= CMYK
->num_channels
;
267 fprintf(stderr
, "DEBUG: PrinterPlanes = %d\n", PrinterPlanes
);
270 * Get the dithering parameters...
273 switch (PrinterPlanes
)
276 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
277 resolution
, "Black");
281 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
282 resolution
, "Black");
283 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
284 resolution
, "LightBlack");
288 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
290 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
291 resolution
, "Magenta");
292 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
293 resolution
, "Yellow");
297 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
299 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
300 resolution
, "Magenta");
301 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
302 resolution
, "Yellow");
303 DitherLuts
[3] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
304 resolution
, "Black");
307 case 6 : /* CcMmYK */
308 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
310 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
311 resolution
, "LightCyan");
312 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
313 resolution
, "Magenta");
314 DitherLuts
[3] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
315 resolution
, "LightMagenta");
316 DitherLuts
[4] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
317 resolution
, "Yellow");
318 DitherLuts
[5] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
319 resolution
, "Black");
322 case 7 : /* CcMmYKk */
323 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
325 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
326 resolution
, "LightCyan");
327 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
328 resolution
, "Magenta");
329 DitherLuts
[3] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
330 resolution
, "LightMagenta");
331 DitherLuts
[4] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
332 resolution
, "Yellow");
333 DitherLuts
[5] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
334 resolution
, "Black");
335 DitherLuts
[6] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
336 resolution
, "LightBlack");
340 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
342 DitherStates
[plane
] = cupsDitherNew(header
->cupsWidth
);
344 if (!DitherLuts
[plane
])
345 DitherLuts
[plane
] = cupsLutNew(2, default_lut
);
348 if (DitherLuts
[0][4095].pixel
> 1)
354 * Initialize the printer...
359 if (ppd
->model_number
& ESCP_REMOTE
)
362 * Go into remote mode...
365 cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
368 * Disable status reporting...
371 cupsWritePrintData("ST\002\000\000\000", 6);
374 * Enable borderless printing...
377 if ((attr
= ppdFindAttr(ppd
, "cupsESCPFP", NULL
)) != NULL
&& attr
->value
)
380 * Set horizontal offset...
383 i
= atoi(attr
->value
);
385 cupsWritePrintData("FP\003\000\000", 5);
394 if (header
->cupsMediaType
)
396 sprintf(spec
, "%d", header
->cupsMediaType
);
398 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN0", spec
)) != NULL
&& attr
->value
)
401 * Set feed sequence...
404 cupsWritePrintData("SN\003\000\000\000", 6);
405 putchar(atoi(attr
->value
));
408 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN1", spec
)) != NULL
&& attr
->value
)
414 cupsWritePrintData("SN\003\000\000\001", 6);
415 putchar(atoi(attr
->value
));
418 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN2", spec
)) != NULL
&& attr
->value
)
421 * Paper feeding/ejecting sequence...
424 cupsWritePrintData("SN\003\000\000\002", 6);
425 putchar(atoi(attr
->value
));
428 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN6", spec
)) != NULL
&& attr
->value
)
434 cupsWritePrintData("SN\003\000\000\006", 6);
435 putchar(atoi(attr
->value
));
438 if ((attr
= ppdFindAttr(ppd
, "cupsESCPMT", spec
)) != NULL
&& attr
->value
)
444 cupsWritePrintData("MT\003\000\000\000", 6);
445 putchar(atoi(attr
->value
));
448 if ((attr
= ppdFindAttr(ppd
, "cupsESCPPH", spec
)) != NULL
&& attr
->value
)
451 * Set paper thickness.
454 cupsWritePrintData("PH\002\000\000", 5);
455 putchar(atoi(attr
->value
));
459 sprintf(spec
, "%d", header
->MediaPosition
);
461 if (header
->MediaPosition
)
463 if ((attr
= ppdFindAttr(ppd
, "cupsESCPPC", spec
)) != NULL
&& attr
->value
)
469 cupsWritePrintData("PC\002\000\000", 5);
470 putchar(atoi(attr
->value
));
473 if ((attr
= ppdFindAttr(ppd
, "cupsESCPPP", spec
)) != NULL
&& attr
->value
)
482 sscanf(attr
->value
, "%d%d", &a
, &b
);
484 cupsWritePrintData("PP\003\000\000", 5);
489 if ((attr
= ppdFindAttr(ppd
, "cupsESCPEX", spec
)) != NULL
&& attr
->value
)
492 * Set media position.
495 cupsWritePrintData("EX\006\000\000\000\000\000\005", 9);
496 putchar(atoi(attr
->value
));
500 if ((attr
= ppdFindAttr(ppd
, "cupsESCPMS", spec
)) != NULL
&& attr
->value
)
506 cupsWritePrintData("MS\010\000\000", 5);
507 putchar(atoi(attr
->value
));
509 switch (header
->PageSize
[1])
535 case 595 : /* A4.Transverse */
551 case 516 : /* B5.Transverse */
559 case 1369 : /* Super A3/B */
567 case 792 : /* Letter */
575 case 612 : /* Letter.Transverse */
583 case 1004 : /* Legal */
591 case 1224 : /* Tabloid */
599 default : /* Custom size */
602 i
= 360 * header
->PageSize
[0] / 72;
605 i
= 360 * header
->PageSize
[1] / 72;
612 sprintf(spec
, "%d", header
->CutMedia
);
614 if ((attr
= ppdFindAttr(ppd
, "cupsESCPAC", spec
)) != NULL
&& attr
->value
)
617 * Enable/disable cutter.
620 cupsWritePrintData("AC\002\000\000", 5);
621 putchar(atoi(attr
->value
));
623 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN80", header
->MediaType
)) != NULL
&& attr
->value
)
629 cupsWritePrintData("SN\003\000\000\200", 6);
630 putchar(atoi(attr
->value
));
633 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN81", header
->MediaType
)) != NULL
&& attr
->value
)
636 * Cutting pressure...
639 cupsWritePrintData("SN\003\000\000\201", 6);
640 putchar(atoi(attr
->value
));
644 if ((attr
= ppdFindAttr(ppd
, "cupsESCPCO", spec
)) != NULL
&& attr
->value
)
647 * Enable/disable cutter.
650 cupsWritePrintData("CO\010\000\000\000", 6);
651 putchar(atoi(attr
->value
));
652 cupsWritePrintData("\000\000\000\000\000", 5);
656 * Exit remote mode...
659 cupsWritePrintData("\033\000\000\000", 4);
663 * Enter graphics mode...
666 cupsWritePrintData("\033(G\001\000\001", 6);
669 * Set the line feed increment...
672 /* TODO: get this from the PPD file... */
673 for (units
= 1440; units
< header
->HWResolution
[0]; units
*= 2);
675 if (ppd
->model_number
& ESCP_EXT_UNITS
)
677 cupsWritePrintData("\033(U\005\000", 5);
678 putchar(units
/ header
->HWResolution
[1]);
679 putchar(units
/ header
->HWResolution
[1]);
680 putchar(units
/ header
->HWResolution
[0]);
686 cupsWritePrintData("\033(U\001\000", 5);
687 putchar(3600 / header
->HWResolution
[1]);
691 * Set the page length...
694 PrinterLength
= header
->PageSize
[1] * header
->HWResolution
[1] / 72;
696 if (ppd
->model_number
& ESCP_PAGE_SIZE
)
699 * Set page size (expands bottom margin)...
702 cupsWritePrintData("\033(S\010\000", 5);
704 i
= header
->PageSize
[0] * header
->HWResolution
[1] / 72;
710 i
= header
->PageSize
[1] * header
->HWResolution
[1] / 72;
718 cupsWritePrintData("\033(C\002\000", 5);
719 putchar(PrinterLength
& 255);
720 putchar(PrinterLength
>> 8);
724 * Set the top and bottom margins...
727 PrinterTop
= (int)((ppd
->sizes
[1].length
- ppd
->sizes
[1].top
) *
728 header
->HWResolution
[1] / 72.0);
730 if (ppd
->model_number
& ESCP_EXT_MARGINS
)
732 cupsWritePrintData("\033(c\010\000", 5);
735 putchar(PrinterTop
>> 8);
736 putchar(PrinterTop
>> 16);
737 putchar(PrinterTop
>> 24);
739 putchar(PrinterLength
);
740 putchar(PrinterLength
>> 8);
741 putchar(PrinterLength
>> 16);
742 putchar(PrinterLength
>> 24);
746 cupsWritePrintData("\033(c\004\000", 5);
748 putchar(PrinterTop
& 255);
749 putchar(PrinterTop
>> 8);
751 putchar(PrinterLength
& 255);
752 putchar(PrinterLength
>> 8);
756 * Set the top position...
759 cupsWritePrintData("\033(V\002\000\000\000", 7);
762 * Enable unidirectional printing depending on the mode...
765 if ((attr
= cupsFindAttr(ppd
, "cupsESCPDirection", colormodel
,
766 header
->MediaType
, resolution
, spec
,
767 sizeof(spec
))) != NULL
)
768 printf("\033U%c", atoi(attr
->value
));
771 * Enable/disable microweaving as needed...
774 if ((attr
= cupsFindAttr(ppd
, "cupsESCPMicroWeave", colormodel
,
775 header
->MediaType
, resolution
, spec
,
776 sizeof(spec
))) != NULL
)
777 printf("\033(i\001%c%c", 0, atoi(attr
->value
));
780 * Set the dot size and print speed as needed...
783 if ((attr
= cupsFindAttr(ppd
, "cupsESCPDotSize", colormodel
,
784 header
->MediaType
, resolution
, spec
,
785 sizeof(spec
))) != NULL
)
786 printf("\033(e\002%c%c%c", 0, 0, atoi(attr
->value
));
788 if (ppd
->model_number
& ESCP_ESCK
)
791 * Set the print mode...
794 if (PrinterPlanes
== 1)
797 * Fast black printing.
800 cupsWritePrintData("\033(K\002\000\000\001", 7);
808 cupsWritePrintData("\033(K\002\000\000\002", 7);
813 * Get softweave settings from header...
816 if (header
->cupsRowCount
<= 1)
825 DotRowCount
= header
->cupsRowCount
;
826 DotRowFeed
= header
->cupsRowFeed
;
827 DotRowStep
= header
->cupsRowStep
% 100;
828 DotColStep
= header
->cupsRowStep
/ 100;
835 * Setup softweave parameters...
839 DotRowMax
= DotRowCount
* DotRowStep
;
840 DotBufferSize
= (header
->cupsWidth
/ DotColStep
* BitPlanes
+ 7) / 8;
842 fprintf(stderr
, "DEBUG: DotBufferSize = %d\n", DotBufferSize
);
843 fprintf(stderr
, "DEBUG: DotColStep = %d\n", DotColStep
);
844 fprintf(stderr
, "DEBUG: DotRowMax = %d\n", DotRowMax
);
845 fprintf(stderr
, "DEBUG: DotRowStep = %d\n", DotRowStep
);
846 fprintf(stderr
, "DEBUG: DotRowFeed = %d\n", DotRowFeed
);
847 fprintf(stderr
, "DEBUG: DotRowCount = %d\n", DotRowCount
);
851 DotBuffers
[0] = NULL
;
853 fprintf(stderr
, "DEBUG: model_number = %x\n", ppd
->model_number
);
858 * Compute offsets for the color jets on the print head...
861 bands
= DotRowStep
* DotColStep
* PrinterPlanes
* 4;
863 memset(DotRowOffset
, 0, sizeof(DotRowOffset
));
865 if (PrinterPlanes
== 1)
868 * Use full height of print head...
871 if ((attr
= ppdFindAttr(ppd
, "cupsESCPBlack", resolution
)) != NULL
&&
875 * Use custom black head data...
878 sscanf(attr
->value
, "%d%d", &DotRowCount
, &DotRowStep
);
881 else if (ppd
->model_number
& ESCP_STAGGER
)
884 * Use staggered print head...
887 fputs("DEBUG: Offset head detected...\n", stderr
);
889 if ((attr
= ppdFindAttr(ppd
, "cupsESCPOffsets", resolution
)) != NULL
&&
893 * Use only 1/3 of the print head when printing color...
896 sscanf(attr
->value
, "%d%d%d%d", DotRowOffset
+ 0,
897 DotRowOffset
+ 1, DotRowOffset
+ 2, DotRowOffset
+ 3);
901 for (i
= 0; i
< PrinterPlanes
; i
++)
902 fprintf(stderr
, "DEBUG: DotRowOffset[%d] = %d\n", i
, DotRowOffset
[i
]);
908 for (i
= 0; i
< bands
; i
++)
910 band
= (cups_weave_t
*)calloc(1, sizeof(cups_weave_t
));
911 band
->next
= DotAvailList
;
914 band
->buffer
= calloc(DotRowCount
, DotBufferSize
);
919 fputs("ERROR: Unable to allocate band list\n", stderr
);
923 fputs("DEBUG: Pointer list at start of page...\n", stderr
);
925 for (band
= DotAvailList
; band
!= NULL
; band
= band
->next
)
926 fprintf(stderr
, "DEBUG: %p\n", band
);
928 fputs("DEBUG: ----END----\n", stderr
);
931 * Fill the initial bands...
934 modrow
= DotColStep
* DotRowStep
;
939 * Automatically compute the optimal feed value...
942 DotRowFeed
= DotRowCount
/ DotColStep
- DotRowStep
;
944 while ((((DotRowFeed
% 2) == 0) == ((DotRowCount
% 2) == 0) ||
945 ((DotRowFeed
% 3) == 0) == ((DotRowCount
% 3) == 0) ||
946 ((DotRowFeed
% 5) == 0) == ((DotRowCount
% 5) == 0)) &&
953 fprintf(stderr
, "DEBUG: Auto DotRowFeed = %d, modrow=%d...\n",
957 memset(DotBands
, 0, sizeof(DotBands
));
959 for (i
= modrow
, subrow
= modrow
- 1, y
= DotRowFeed
;
961 i
--, y
+= DotRowFeed
)
963 while (DotBands
[subrow
][0])
966 * This subrow is already used, move to another one...
969 subrow
= (subrow
+ 1) % modrow
;
972 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
975 * Pull the next available band from the list...
979 DotAvailList
= DotAvailList
->next
;
980 DotBands
[subrow
][plane
] = band
;
983 * Start the band in the first few passes, with the number of rows
984 * varying to allow for a nice interleaved pattern...
987 band
->x
= subrow
/ DotRowStep
;
988 band
->y
= (subrow
% DotRowStep
) + DotRowOffset
[plane
];
991 band
->count
= DotRowCount
- y
/ DotRowStep
;
995 else if (band
->count
> DotRowCount
)
996 band
->count
= DotRowCount
;
998 fprintf(stderr
, "DEBUG: DotBands[%d][%d] = %p, x = %d, y = %d, plane = %d, count = %d\n",
999 subrow
, plane
, band
, band
->x
, band
->y
, band
->plane
, band
->count
);
1002 subrow
= (subrow
+ DotRowFeed
) % modrow
;
1008 * Allocate memory for a single line of graphics...
1011 ptr
= calloc(PrinterPlanes
, DotBufferSize
);
1013 for (plane
= 0; plane
< PrinterPlanes
; plane
++, ptr
+= DotBufferSize
)
1014 DotBuffers
[plane
] = ptr
;
1018 * Set the output resolution...
1021 cupsWritePrintData("\033(D\004\000", 5);
1023 putchar(units
>> 8);
1024 putchar(units
* DotRowStep
/ header
->HWResolution
[1]);
1025 putchar(units
* DotColStep
/ header
->HWResolution
[0]);
1028 * Set the top of form...
1034 * Allocate buffers as needed...
1037 PixelBuffer
= malloc(header
->cupsBytesPerLine
);
1038 InputBuffer
= malloc(header
->cupsWidth
* PrinterPlanes
* 2);
1039 OutputBuffers
[0] = malloc(PrinterPlanes
* header
->cupsWidth
);
1041 for (i
= 1; i
< PrinterPlanes
; i
++)
1042 OutputBuffers
[i
] = OutputBuffers
[0] + i
* header
->cupsWidth
;
1045 CMYKBuffer
= malloc(header
->cupsWidth
* PrinterPlanes
);
1047 CompBuffer
= malloc(10 * DotBufferSize
* DotRowMax
);
1052 * 'EndPage()' - Finish a page of graphics.
1056 EndPage(ppd_file_t
*ppd
, /* I - PPD file */
1057 cups_page_header2_t
*header
) /* I - Page header */
1059 int i
; /* Looping var */
1060 cups_weave_t
*band
, /* Current band */
1061 *next
; /* Next band in list */
1062 int plane
; /* Current plane */
1063 int subrow
; /* Current subrow */
1064 int subrows
; /* Number of subrows */
1068 * Output the last bands of print data as necessary...
1074 * Move the remaining bands to the used or avail lists...
1077 subrows
= DotRowStep
* DotColStep
;
1079 for (subrow
= 0; subrow
< subrows
; subrow
++)
1080 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
1082 if (DotBands
[subrow
][plane
]->dirty
)
1085 * Insert into the used list...
1088 DotBands
[subrow
][plane
]->count
= DotBands
[subrow
][plane
]->row
;
1090 AddBand(DotBands
[subrow
][plane
]);
1095 * Nothing here, so move it to the available list...
1098 DotBands
[subrow
][plane
]->next
= DotAvailList
;
1099 DotAvailList
= DotBands
[subrow
][plane
];
1102 DotBands
[subrow
][plane
] = NULL
;
1106 * Loop until all bands are written...
1109 fputs("DEBUG: Pointer list at end of page...\n", stderr
);
1111 for (band
= DotUsedList
; band
!= NULL
; band
= band
->next
)
1112 fprintf(stderr
, "DEBUG: %p (used)\n", band
);
1113 for (band
= DotAvailList
; band
!= NULL
; band
= band
->next
)
1114 fprintf(stderr
, "DEBUG: %p (avail)\n", band
);
1116 fputs("DEBUG: ----END----\n", stderr
);
1118 for (band
= DotUsedList
; band
!= NULL
; band
= next
)
1122 OutputBand(ppd
, header
, band
);
1124 fprintf(stderr
, "DEBUG: freeing used band %p, prev = %p, next = %p\n",
1125 band
, band
->prev
, band
->next
);
1132 * Free memory for the available bands, if any...
1135 for (band
= DotAvailList
; band
!= NULL
; band
= next
)
1139 fprintf(stderr
, "DEBUG: freeing avail band %p, prev = %p, next = %p\n",
1140 band
, band
->prev
, band
->next
);
1147 free(DotBuffers
[0]);
1150 * Output a page eject sequence...
1156 * Free memory for the page...
1159 for (i
= 0; i
< PrinterPlanes
; i
++)
1161 cupsDitherDelete(DitherStates
[i
]);
1162 cupsLutDelete(DitherLuts
[i
]);
1165 free(OutputBuffers
[0]);
1171 cupsCMYKDelete(CMYK
);
1182 * 'Shutdown()' - Shutdown a printer.
1186 Shutdown(ppd_file_t
*ppd
) /* I - PPD file */
1189 * Reset the printer...
1194 if (ppd
->model_number
& ESCP_REMOTE
)
1197 * Go into remote mode...
1200 cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
1206 cupsWritePrintData("LD\000\000", 4);
1209 * Exit remote mode...
1212 cupsWritePrintData("\033\000\000\000", 4);
1218 * 'AddBand()' - Add a band of data to the used list.
1222 AddBand(cups_weave_t
*band
) /* I - Band to add */
1224 cups_weave_t
*current
, /* Current band */
1225 *prev
; /* Previous band */
1228 if (band
->count
< 1)
1231 for (current
= DotUsedList
, prev
= NULL
;
1233 prev
= current
, current
= current
->next
)
1234 if (band
->y
< current
->y
||
1235 (band
->y
== current
->y
&& band
->x
< current
->x
) ||
1236 (band
->y
== current
->y
&& band
->x
== current
->x
&&
1237 band
->plane
< current
->plane
))
1240 if (current
!= NULL
)
1243 * Insert the band...
1246 band
->next
= current
;
1248 current
->prev
= band
;
1255 else if (prev
!= NULL
)
1258 * Append the band to the end...
1268 * First band in list...
1279 * 'CancelJob()' - Cancel the current job...
1283 CancelJob(int sig
) /* I - Signal */
1292 * 'CompressData()' - Compress a line of graphics.
1296 CompressData(ppd_file_t
*ppd
, /* I - PPD file information */
1297 const unsigned char *line
, /* I - Data to compress */
1298 const int length
,/* I - Number of bytes */
1299 int plane
, /* I - Color plane */
1300 int type
, /* I - Type of compression */
1301 const int rows
, /* I - Number of lines to write */
1302 const int xstep
, /* I - Spacing between columns */
1303 const int ystep
, /* I - Spacing between lines */
1304 const int offset
)/* I - Head offset */
1306 register const unsigned char *line_ptr
,
1307 /* Current byte pointer */
1308 *line_end
, /* End-of-line byte pointer */
1309 *start
; /* Start of compression sequence */
1310 register unsigned char *comp_ptr
; /* Pointer into compression buffer */
1311 register int count
; /* Count of bytes for output */
1312 register int bytes
; /* Number of bytes per row */
1313 static int ctable
[7][7] = /* Colors */
1315 { 0, 0, 0, 0, 0, 0, 0 }, /* K */
1316 { 0, 16, 0, 0, 0, 0, 0 }, /* Kk */
1317 { 2, 1, 4, 0, 0, 0, 0 }, /* CMY */
1318 { 2, 1, 4, 0, 0, 0, 0 }, /* CMYK */
1319 { 0, 0, 0, 0, 0, 0, 0 },
1320 { 2, 18, 1, 17, 4, 0, 0 }, /* CcMmYK */
1321 { 2, 18, 1, 17, 4, 0, 16 }, /* CcMmYKk */
1329 * Do no compression...
1332 line_ptr
= (const unsigned char *)line
;
1333 line_end
= (const unsigned char *)line
+ length
;
1338 * Do TIFF pack-bits encoding...
1341 line_ptr
= (const unsigned char *)line
;
1342 line_end
= (const unsigned char *)line
+ length
;
1343 comp_ptr
= CompBuffer
;
1345 while (line_ptr
< line_end
&& (comp_ptr
- CompBuffer
) < length
)
1347 if ((line_ptr
+ 1) >= line_end
)
1350 * Single byte on the end...
1354 *comp_ptr
++ = *line_ptr
++;
1356 else if (line_ptr
[0] == line_ptr
[1])
1359 * Repeated sequence...
1365 while (line_ptr
< (line_end
- 1) &&
1366 line_ptr
[0] == line_ptr
[1] &&
1373 *comp_ptr
++ = 257 - count
;
1374 *comp_ptr
++ = *line_ptr
++;
1379 * Non-repeated sequence...
1386 while (line_ptr
< (line_end
- 1) &&
1387 line_ptr
[0] != line_ptr
[1] &&
1394 *comp_ptr
++ = count
- 1;
1396 memcpy(comp_ptr
, start
, count
);
1401 if ((comp_ptr
- CompBuffer
) < length
)
1403 line_ptr
= (const unsigned char *)CompBuffer
;
1404 line_end
= (const unsigned char *)comp_ptr
;
1409 line_ptr
= (const unsigned char *)line
;
1410 line_end
= (const unsigned char *)line
+ length
;
1416 * Position the print head...
1424 cupsWritePrintData("\033(\\\004\000\240\005", 7);
1429 putchar(offset
>> 8);
1433 * Send the graphics...
1436 bytes
= length
/ rows
;
1438 if (ppd
->model_number
& ESCP_RASTER_ESCI
)
1441 * Send graphics with ESC i command.
1445 putchar(ctable
[PrinterPlanes
- 1][plane
]);
1448 putchar(bytes
& 255);
1449 putchar(bytes
>> 8);
1450 putchar(rows
& 255);
1456 * Set the color if necessary...
1459 if (PrinterPlanes
> 1)
1461 plane
= ctable
[PrinterPlanes
- 1][plane
];
1464 printf("\033(r%c%c%c%c", 2, 0, 1, plane
& 0x0f);
1466 printf("\033r%c", plane
);
1470 * Send graphics with ESC . command.
1480 putchar(bytes
& 255);
1481 putchar(bytes
>> 8);
1484 cupsWritePrintData(line_ptr
, line_end
- line_ptr
);
1489 * 'OutputBand()' - Output a band of graphics.
1493 OutputBand(ppd_file_t
*ppd
, /* I - PPD file */
1494 cups_page_header2_t
*header
, /* I - Page header */
1495 cups_weave_t
*band
) /* I - Current band */
1497 int xstep
, /* Spacing between columns */
1498 ystep
; /* Spacing between rows */
1502 * Interleaved ESC/P2 graphics...
1505 OutputFeed
= band
->y
- DotRowCurrent
;
1506 DotRowCurrent
= band
->y
;
1508 fprintf(stderr
, "DEBUG: Printing band %p, x = %d, y = %d, plane = %d, count = %d, OutputFeed = %d\n",
1509 band
, band
->x
, band
->y
, band
->plane
, band
->count
, OutputFeed
);
1512 * Compute step values...
1515 xstep
= 3600 * DotColStep
/ header
->HWResolution
[0];
1516 ystep
= 3600 * DotRowStep
/ header
->HWResolution
[1];
1519 * Output the band...
1524 cupsWritePrintData("\033(v\002\000", 5);
1525 putchar(OutputFeed
& 255);
1526 putchar(OutputFeed
>> 8);
1531 CompressData(ppd
, band
->buffer
, band
->count
* DotBufferSize
, band
->plane
,
1532 header
->cupsCompression
, band
->count
, xstep
, ystep
, band
->x
);
1538 memset(band
->buffer
, 0, band
->count
* DotBufferSize
);
1542 * Flush the output buffers...
1550 * 'ProcessLine()' - Read graphics from the page stream and output as needed.
1554 ProcessLine(ppd_file_t
*ppd
, /* I - PPD file */
1555 cups_raster_t
*ras
, /* I - Raster stream */
1556 cups_page_header2_t
*header
, /* I - Page header */
1557 const int y
) /* I - Current scanline */
1559 int plane
, /* Current color plane */
1560 width
, /* Width of line */
1561 subwidth
, /* Width of interleaved row */
1562 subrow
, /* Subrow for interleaved output */
1563 offset
, /* Offset to current line */
1564 pass
, /* Pass number */
1565 xstep
, /* X step value */
1566 ystep
; /* Y step value */
1567 cups_weave_t
*band
; /* Current band */
1571 * Read a row of graphics...
1574 if (!cupsRasterReadPixels(ras
, PixelBuffer
, header
->cupsBytesPerLine
))
1578 * Perform the color separation...
1581 width
= header
->cupsWidth
;
1582 subwidth
= header
->cupsWidth
/ DotColStep
;
1583 xstep
= 3600 / header
->HWResolution
[0];
1584 ystep
= 3600 / header
->HWResolution
[1];
1586 switch (header
->cupsColorSpace
)
1588 case CUPS_CSPACE_W
:
1591 cupsRGBDoGray(RGB
, PixelBuffer
, CMYKBuffer
, width
);
1592 cupsCMYKDoCMYK(CMYK
, CMYKBuffer
, InputBuffer
, width
);
1595 cupsCMYKDoGray(CMYK
, PixelBuffer
, InputBuffer
, width
);
1598 case CUPS_CSPACE_K
:
1599 cupsCMYKDoBlack(CMYK
, PixelBuffer
, InputBuffer
, width
);
1603 case CUPS_CSPACE_RGB
:
1606 cupsRGBDoRGB(RGB
, PixelBuffer
, CMYKBuffer
, width
);
1607 cupsCMYKDoCMYK(CMYK
, CMYKBuffer
, InputBuffer
, width
);
1610 cupsCMYKDoRGB(CMYK
, PixelBuffer
, InputBuffer
, width
);
1613 case CUPS_CSPACE_CMYK
:
1614 cupsCMYKDoCMYK(CMYK
, PixelBuffer
, InputBuffer
, width
);
1619 * Dither the pixels...
1622 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
1624 cupsDitherLine(DitherStates
[plane
], DitherLuts
[plane
], InputBuffer
+ plane
,
1625 PrinterPlanes
, OutputBuffers
[plane
]);
1630 * Handle microweaved output...
1633 if (cupsCheckBytes(OutputBuffers
[plane
], width
))
1637 cupsPackHorizontal(OutputBuffers
[plane
], DotBuffers
[plane
],
1640 cupsPackHorizontal2(OutputBuffers
[plane
], DotBuffers
[plane
],
1645 cupsWritePrintData("\033(v\002\000", 5);
1646 putchar(OutputFeed
& 255);
1647 putchar(OutputFeed
>> 8);
1651 CompressData(ppd
, DotBuffers
[plane
], DotBufferSize
, plane
, 1, 1,
1658 * Handle softweaved output...
1661 for (pass
= 0, subrow
= y
% DotRowStep
;
1663 pass
++, subrow
+= DotRowStep
)
1666 * See if we need to output the band...
1669 band
= DotBands
[subrow
][plane
];
1670 offset
= band
->row
* DotBufferSize
;
1673 cupsPackHorizontal(OutputBuffers
[plane
] + pass
,
1674 band
->buffer
+ offset
, subwidth
, 0, DotColStep
);
1676 cupsPackHorizontal2(OutputBuffers
[plane
] + pass
,
1677 band
->buffer
+ offset
, subwidth
, DotColStep
);
1680 band
->dirty
|= !cupsCheckBytes(band
->buffer
+ offset
, DotBufferSize
);
1681 if (band
->row
>= band
->count
)
1686 * Dirty band needs to be added to the used list...
1692 * Then find a new band...
1695 if (DotAvailList
== NULL
)
1697 OutputBand(ppd
, header
, DotUsedList
);
1699 DotBands
[subrow
][plane
] = DotUsedList
;
1700 DotUsedList
->x
= band
->x
;
1701 DotUsedList
->y
= band
->y
+ band
->count
* DotRowStep
;
1702 DotUsedList
->plane
= band
->plane
;
1703 DotUsedList
->row
= 0;
1704 DotUsedList
->count
= DotRowCount
;
1705 DotUsedList
= DotUsedList
->next
;
1709 DotBands
[subrow
][plane
] = DotAvailList
;
1710 DotAvailList
->x
= band
->x
;
1711 DotAvailList
->y
= band
->y
+ band
->count
* DotRowStep
;
1712 DotAvailList
->plane
= band
->plane
;
1713 DotAvailList
->row
= 0;
1714 DotAvailList
->count
= DotRowCount
;
1715 DotAvailList
= DotAvailList
->next
;
1721 * This band isn't dirty, so reuse it...
1724 fprintf(stderr
, "DEBUG: Blank band %p, x = %d, y = %d, plane = %d, count = %d\n",
1725 band
, band
->x
, band
->y
, band
->plane
, band
->count
);
1727 band
->y
+= band
->count
* DotRowStep
;
1729 band
->count
= DotRowCount
;
1742 * 'main()' - Main entry and processing of driver.
1745 int /* O - Exit status */
1746 main(int argc
, /* I - Number of command-line arguments */
1747 char *argv
[]) /* I - Command-line arguments */
1749 int fd
; /* File descriptor */
1750 cups_raster_t
*ras
; /* Raster stream for printing */
1751 cups_page_header2_t header
; /* Page header from file */
1752 int page
; /* Current page */
1753 int y
; /* Current line */
1754 ppd_file_t
*ppd
; /* PPD file */
1755 int num_options
; /* Number of options */
1756 cups_option_t
*options
; /* Options */
1757 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1758 struct sigaction action
; /* Actions for POSIX signals */
1759 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1763 * Make sure status messages are not buffered...
1766 setbuf(stderr
, NULL
);
1769 * Check command-line...
1772 if (argc
< 6 || argc
> 7)
1774 _cupsLangPrintFilter(stderr
, "ERROR",
1775 _("%s job-id user title copies options [file]"),
1780 num_options
= cupsParseOptions(argv
[5], 0, &options
);
1783 * Open the PPD file...
1786 ppd
= ppdOpenFile(getenv("PPD"));
1790 ppd_status_t status
; /* PPD error */
1791 int linenum
; /* Line number */
1793 _cupsLangPrintFilter(stderr
, "ERROR",
1794 _("The PPD file could not be opened."));
1796 status
= ppdLastError(&linenum
);
1798 fprintf(stderr
, "DEBUG: %s on line %d.\n", ppdErrorString(status
), linenum
);
1803 ppdMarkDefaults(ppd
);
1804 cupsMarkOptions(ppd
, num_options
, options
);
1807 * Open the page stream...
1812 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
1814 _cupsLangPrintError("ERROR", _("Unable to open raster file"));
1821 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
1824 * Register a signal handler to eject the current page if the
1830 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1831 sigset(SIGTERM
, CancelJob
);
1832 #elif defined(HAVE_SIGACTION)
1833 memset(&action
, 0, sizeof(action
));
1835 sigemptyset(&action
.sa_mask
);
1836 action
.sa_handler
= CancelJob
;
1837 sigaction(SIGTERM
, &action
, NULL
);
1839 signal(SIGTERM
, CancelJob
);
1840 #endif /* HAVE_SIGSET */
1843 * Initialize the print device...
1849 * Process pages as needed...
1854 while (cupsRasterReadHeader2(ras
, &header
))
1857 * Write a status message with the page number and number of copies.
1865 fprintf(stderr
, "PAGE: %d 1\n", page
);
1866 _cupsLangPrintFilter(stderr
, "INFO", _("Starting page %d."), page
);
1868 StartPage(ppd
, &header
);
1870 for (y
= 0; y
< header
.cupsHeight
; y
++)
1873 * Let the user know how far we have progressed...
1881 _cupsLangPrintFilter(stderr
, "INFO",
1882 _("Printing page %d, %d%% complete."),
1883 page
, 100 * y
/ header
.cupsHeight
);
1884 fprintf(stderr
, "ATTR: job-media-progress=%d\n",
1885 100 * y
/ header
.cupsHeight
);
1889 * Read and write a line of graphics or whitespace...
1892 ProcessLine(ppd
, ras
, &header
, y
);
1899 _cupsLangPrintFilter(stderr
, "INFO", _("Finished page %d."), page
);
1901 EndPage(ppd
, &header
);
1909 cupsFreeOptions(num_options
, options
);
1911 cupsRasterClose(ras
);
1918 _cupsLangPrintFilter(stderr
, "ERROR", _("No pages were found."));
1923 _cupsLangPrintFilter(stderr
, "INFO", _("Ready to print."));