4 * Advanced EPSON ESC/P raster driver for CUPS.
6 * Copyright 2007-2009 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/i18n.h>
35 #include <cups/string.h>
36 #include "data/escp.h"
45 typedef struct cups_weave_str
47 struct cups_weave_str
*prev
, /* Previous band */
48 *next
; /* Next band */
49 int x
, y
, /* Column/Line on the page */
50 plane
, /* Color plane */
51 dirty
, /* Is this buffer dirty? */
52 row
, /* Row in the buffer */
53 count
; /* Max rows this pass */
54 unsigned char *buffer
; /* Data buffer */
62 cups_rgb_t
*RGB
; /* RGB color separation data */
63 cups_cmyk_t
*CMYK
; /* CMYK color separation data */
64 unsigned char *PixelBuffer
, /* Pixel buffer */
65 *CMYKBuffer
, /* CMYK buffer */
66 *OutputBuffers
[7], /* Output buffers */
67 *DotBuffers
[7], /* Dot buffers */
68 *CompBuffer
; /* Compression buffer */
69 short *InputBuffer
; /* Color separation buffer */
70 cups_weave_t
*DotAvailList
, /* Available buffers */
71 *DotUsedList
, /* Used buffers */
72 *DotBands
[128][7]; /* Buffers in use */
73 int DotBufferSize
, /* Size of dot buffers */
74 DotRowMax
, /* Maximum row number in buffer */
75 DotColStep
, /* Step for each output column */
76 DotRowStep
, /* Step for each output line */
77 DotRowFeed
, /* Amount to feed for interleave */
78 DotRowCount
, /* Number of rows to output */
79 DotRowOffset
[7], /* Offset for each color on print head */
80 DotRowCurrent
, /* Current row */
81 DotSize
; /* Dot size (Pro 5000 only) */
82 int PrinterPlanes
, /* # of color planes */
83 BitPlanes
, /* # of bit planes per color */
84 PrinterTop
, /* Top of page */
85 PrinterLength
; /* Length of page */
86 cups_lut_t
*DitherLuts
[7]; /* Lookup tables for dithering */
87 cups_dither_t
*DitherStates
[7]; /* Dither state tables */
88 int OutputFeed
; /* Number of lines to skip */
89 int Canceled
; /* Is the job canceled? */
96 void Setup(ppd_file_t
*);
97 void StartPage(ppd_file_t
*, cups_page_header2_t
*);
98 void EndPage(ppd_file_t
*, cups_page_header2_t
*);
99 void Shutdown(ppd_file_t
*);
101 void AddBand(cups_weave_t
*band
);
102 void CancelJob(int sig
);
103 void CompressData(ppd_file_t
*, const unsigned char *, const int,
104 int, int, const int, const int, const int,
106 void OutputBand(ppd_file_t
*, cups_page_header2_t
*,
108 void ProcessLine(ppd_file_t
*, cups_raster_t
*,
109 cups_page_header2_t
*, const int y
);
113 * 'Setup()' - Prepare a printer for graphics output.
117 Setup(ppd_file_t
*ppd
) /* I - PPD file */
120 * Some EPSON printers need an additional command issued at the
121 * beginning of each job to exit from USB "packet" mode...
124 if (ppd
->model_number
& ESCP_USB
)
125 cupsWritePrintData("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
130 * 'StartPage()' - Start a page of graphics.
134 StartPage(ppd_file_t
*ppd
, /* I - PPD file */
135 cups_page_header2_t
*header
) /* I - Page header */
137 int i
, y
; /* Looping vars */
138 int subrow
, /* Current subrow */
139 modrow
, /* Subrow modulus */
140 plane
; /* Current color plane */
141 unsigned char *ptr
; /* Pointer into dot buffer */
142 int bands
; /* Number of bands to allocate */
143 int units
; /* Units for resolution */
144 cups_weave_t
*band
; /* Current band */
145 const char *colormodel
; /* Color model string */
146 char resolution
[PPD_MAX_NAME
],
147 /* Resolution string */
148 spec
[PPD_MAX_NAME
]; /* PPD attribute name */
149 ppd_attr_t
*attr
; /* Attribute from PPD file */
150 const float default_lut
[2] = /* Default dithering lookup table */
157 fprintf(stderr
, "DEBUG: StartPage...\n");
158 fprintf(stderr
, "DEBUG: MediaClass = \"%s\"\n", header
->MediaClass
);
159 fprintf(stderr
, "DEBUG: MediaColor = \"%s\"\n", header
->MediaColor
);
160 fprintf(stderr
, "DEBUG: MediaType = \"%s\"\n", header
->MediaType
);
161 fprintf(stderr
, "DEBUG: OutputType = \"%s\"\n", header
->OutputType
);
163 fprintf(stderr
, "DEBUG: AdvanceDistance = %d\n", header
->AdvanceDistance
);
164 fprintf(stderr
, "DEBUG: AdvanceMedia = %d\n", header
->AdvanceMedia
);
165 fprintf(stderr
, "DEBUG: Collate = %d\n", header
->Collate
);
166 fprintf(stderr
, "DEBUG: CutMedia = %d\n", header
->CutMedia
);
167 fprintf(stderr
, "DEBUG: Duplex = %d\n", header
->Duplex
);
168 fprintf(stderr
, "DEBUG: HWResolution = [ %d %d ]\n", header
->HWResolution
[0],
169 header
->HWResolution
[1]);
170 fprintf(stderr
, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
171 header
->ImagingBoundingBox
[0], header
->ImagingBoundingBox
[1],
172 header
->ImagingBoundingBox
[2], header
->ImagingBoundingBox
[3]);
173 fprintf(stderr
, "DEBUG: InsertSheet = %d\n", header
->InsertSheet
);
174 fprintf(stderr
, "DEBUG: Jog = %d\n", header
->Jog
);
175 fprintf(stderr
, "DEBUG: LeadingEdge = %d\n", header
->LeadingEdge
);
176 fprintf(stderr
, "DEBUG: Margins = [ %d %d ]\n", header
->Margins
[0],
178 fprintf(stderr
, "DEBUG: ManualFeed = %d\n", header
->ManualFeed
);
179 fprintf(stderr
, "DEBUG: MediaPosition = %d\n", header
->MediaPosition
);
180 fprintf(stderr
, "DEBUG: MediaWeight = %d\n", header
->MediaWeight
);
181 fprintf(stderr
, "DEBUG: MirrorPrint = %d\n", header
->MirrorPrint
);
182 fprintf(stderr
, "DEBUG: NegativePrint = %d\n", header
->NegativePrint
);
183 fprintf(stderr
, "DEBUG: NumCopies = %d\n", header
->NumCopies
);
184 fprintf(stderr
, "DEBUG: Orientation = %d\n", header
->Orientation
);
185 fprintf(stderr
, "DEBUG: OutputFaceUp = %d\n", header
->OutputFaceUp
);
186 fprintf(stderr
, "DEBUG: PageSize = [ %d %d ]\n", header
->PageSize
[0],
187 header
->PageSize
[1]);
188 fprintf(stderr
, "DEBUG: Separations = %d\n", header
->Separations
);
189 fprintf(stderr
, "DEBUG: TraySwitch = %d\n", header
->TraySwitch
);
190 fprintf(stderr
, "DEBUG: Tumble = %d\n", header
->Tumble
);
191 fprintf(stderr
, "DEBUG: cupsWidth = %d\n", header
->cupsWidth
);
192 fprintf(stderr
, "DEBUG: cupsHeight = %d\n", header
->cupsHeight
);
193 fprintf(stderr
, "DEBUG: cupsMediaType = %d\n", header
->cupsMediaType
);
194 fprintf(stderr
, "DEBUG: cupsBitsPerColor = %d\n", header
->cupsBitsPerColor
);
195 fprintf(stderr
, "DEBUG: cupsBitsPerPixel = %d\n", header
->cupsBitsPerPixel
);
196 fprintf(stderr
, "DEBUG: cupsBytesPerLine = %d\n", header
->cupsBytesPerLine
);
197 fprintf(stderr
, "DEBUG: cupsColorOrder = %d\n", header
->cupsColorOrder
);
198 fprintf(stderr
, "DEBUG: cupsColorSpace = %d\n", header
->cupsColorSpace
);
199 fprintf(stderr
, "DEBUG: cupsCompression = %d\n", header
->cupsCompression
);
200 fprintf(stderr
, "DEBUG: cupsRowCount = %d\n", header
->cupsRowCount
);
201 fprintf(stderr
, "DEBUG: cupsRowFeed = %d\n", header
->cupsRowFeed
);
202 fprintf(stderr
, "DEBUG: cupsRowStep = %d\n", header
->cupsRowStep
);
205 * Figure out the color model and spec strings...
208 switch (header
->cupsColorSpace
)
211 colormodel
= "Black";
217 case CUPS_CSPACE_RGB
:
220 case CUPS_CSPACE_CMYK
:
225 if (header
->HWResolution
[0] != header
->HWResolution
[1])
226 snprintf(resolution
, sizeof(resolution
), "%dx%ddpi",
227 header
->HWResolution
[0], header
->HWResolution
[1]);
229 snprintf(resolution
, sizeof(resolution
), "%ddpi",
230 header
->HWResolution
[0]);
232 if (!header
->MediaType
[0])
233 strcpy(header
->MediaType
, "Plain");
236 * Load the appropriate color profiles...
242 fputs("DEBUG: Attempting to load color profiles using the following values:\n", stderr
);
243 fprintf(stderr
, "DEBUG: ColorModel = %s\n", colormodel
);
244 fprintf(stderr
, "DEBUG: MediaType = %s\n", header
->MediaType
);
245 fprintf(stderr
, "DEBUG: Resolution = %s\n", resolution
);
247 if (header
->cupsColorSpace
== CUPS_CSPACE_RGB
||
248 header
->cupsColorSpace
== CUPS_CSPACE_W
)
249 RGB
= cupsRGBLoad(ppd
, colormodel
, header
->MediaType
, resolution
);
253 CMYK
= cupsCMYKLoad(ppd
, colormodel
, header
->MediaType
, resolution
);
256 fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr
);
259 fputs("DEBUG: Loaded CMYK separation from PPD.\n", stderr
);
262 fputs("DEBUG: Loading default CMYK separation.\n", stderr
);
263 CMYK
= cupsCMYKNew(4);
266 PrinterPlanes
= CMYK
->num_channels
;
268 fprintf(stderr
, "DEBUG: PrinterPlanes = %d\n", PrinterPlanes
);
271 * Get the dithering parameters...
274 switch (PrinterPlanes
)
277 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
278 resolution
, "Black");
282 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
283 resolution
, "Black");
284 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
285 resolution
, "LightBlack");
289 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
291 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
292 resolution
, "Magenta");
293 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
294 resolution
, "Yellow");
298 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
300 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
301 resolution
, "Magenta");
302 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
303 resolution
, "Yellow");
304 DitherLuts
[3] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
305 resolution
, "Black");
308 case 6 : /* CcMmYK */
309 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
311 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
312 resolution
, "LightCyan");
313 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
314 resolution
, "Magenta");
315 DitherLuts
[3] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
316 resolution
, "LightMagenta");
317 DitherLuts
[4] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
318 resolution
, "Yellow");
319 DitherLuts
[5] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
320 resolution
, "Black");
323 case 7 : /* CcMmYKk */
324 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
326 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
327 resolution
, "LightCyan");
328 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
329 resolution
, "Magenta");
330 DitherLuts
[3] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
331 resolution
, "LightMagenta");
332 DitherLuts
[4] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
333 resolution
, "Yellow");
334 DitherLuts
[5] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
335 resolution
, "Black");
336 DitherLuts
[6] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
337 resolution
, "LightBlack");
341 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
343 DitherStates
[plane
] = cupsDitherNew(header
->cupsWidth
);
345 if (!DitherLuts
[plane
])
346 DitherLuts
[plane
] = cupsLutNew(2, default_lut
);
349 if (DitherLuts
[0][4095].pixel
> 1)
355 * Initialize the printer...
360 if (ppd
->model_number
& ESCP_REMOTE
)
363 * Go into remote mode...
366 cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
369 * Disable status reporting...
372 cupsWritePrintData("ST\002\000\000\000", 6);
375 * Enable borderless printing...
378 if ((attr
= ppdFindAttr(ppd
, "cupsESCPFP", NULL
)) != NULL
&& attr
->value
)
381 * Set horizontal offset...
384 i
= atoi(attr
->value
);
386 cupsWritePrintData("FP\003\000\000", 5);
395 if (header
->cupsMediaType
)
397 sprintf(spec
, "%d", header
->cupsMediaType
);
399 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN0", spec
)) != NULL
&& attr
->value
)
402 * Set feed sequence...
405 cupsWritePrintData("SN\003\000\000\000", 6);
406 putchar(atoi(attr
->value
));
409 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN1", spec
)) != NULL
&& attr
->value
)
415 cupsWritePrintData("SN\003\000\000\001", 6);
416 putchar(atoi(attr
->value
));
419 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN2", spec
)) != NULL
&& attr
->value
)
422 * Paper feeding/ejecting sequence...
425 cupsWritePrintData("SN\003\000\000\002", 6);
426 putchar(atoi(attr
->value
));
429 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN6", spec
)) != NULL
&& attr
->value
)
435 cupsWritePrintData("SN\003\000\000\006", 6);
436 putchar(atoi(attr
->value
));
439 if ((attr
= ppdFindAttr(ppd
, "cupsESCPMT", spec
)) != NULL
&& attr
->value
)
445 cupsWritePrintData("MT\003\000\000\000", 6);
446 putchar(atoi(attr
->value
));
449 if ((attr
= ppdFindAttr(ppd
, "cupsESCPPH", spec
)) != NULL
&& attr
->value
)
452 * Set paper thickness.
455 cupsWritePrintData("PH\002\000\000", 5);
456 putchar(atoi(attr
->value
));
460 sprintf(spec
, "%d", header
->MediaPosition
);
462 if (header
->MediaPosition
)
464 if ((attr
= ppdFindAttr(ppd
, "cupsESCPPC", spec
)) != NULL
&& attr
->value
)
470 cupsWritePrintData("PC\002\000\000", 5);
471 putchar(atoi(attr
->value
));
474 if ((attr
= ppdFindAttr(ppd
, "cupsESCPPP", spec
)) != NULL
&& attr
->value
)
483 sscanf(attr
->value
, "%d%d", &a
, &b
);
485 cupsWritePrintData("PP\003\000\000", 5);
490 if ((attr
= ppdFindAttr(ppd
, "cupsESCPEX", spec
)) != NULL
&& attr
->value
)
493 * Set media position.
496 cupsWritePrintData("EX\006\000\000\000\000\000\005", 9);
497 putchar(atoi(attr
->value
));
501 if ((attr
= ppdFindAttr(ppd
, "cupsESCPMS", spec
)) != NULL
&& attr
->value
)
507 cupsWritePrintData("MS\010\000\000", 5);
508 putchar(atoi(attr
->value
));
510 switch (header
->PageSize
[1])
536 case 595 : /* A4.Transverse */
552 case 516 : /* B5.Transverse */
560 case 1369 : /* Super A3/B */
568 case 792 : /* Letter */
576 case 612 : /* Letter.Transverse */
584 case 1004 : /* Legal */
592 case 1224 : /* Tabloid */
600 default : /* Custom size */
603 i
= 360 * header
->PageSize
[0] / 72;
606 i
= 360 * header
->PageSize
[1] / 72;
613 sprintf(spec
, "%d", header
->CutMedia
);
615 if ((attr
= ppdFindAttr(ppd
, "cupsESCPAC", spec
)) != NULL
&& attr
->value
)
618 * Enable/disable cutter.
621 cupsWritePrintData("AC\002\000\000", 5);
622 putchar(atoi(attr
->value
));
624 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN80", header
->MediaType
)) != NULL
&& attr
->value
)
630 cupsWritePrintData("SN\003\000\000\200", 6);
631 putchar(atoi(attr
->value
));
634 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN81", header
->MediaType
)) != NULL
&& attr
->value
)
637 * Cutting pressure...
640 cupsWritePrintData("SN\003\000\000\201", 6);
641 putchar(atoi(attr
->value
));
645 if ((attr
= ppdFindAttr(ppd
, "cupsESCPCO", spec
)) != NULL
&& attr
->value
)
648 * Enable/disable cutter.
651 cupsWritePrintData("CO\010\000\000\000", 6);
652 putchar(atoi(attr
->value
));
653 cupsWritePrintData("\000\000\000\000\000", 5);
657 * Exit remote mode...
660 cupsWritePrintData("\033\000\000\000", 4);
664 * Enter graphics mode...
667 cupsWritePrintData("\033(G\001\000\001", 6);
670 * Set the line feed increment...
673 /* TODO: get this from the PPD file... */
674 for (units
= 1440; units
< header
->HWResolution
[0]; units
*= 2);
676 if (ppd
->model_number
& ESCP_EXT_UNITS
)
678 cupsWritePrintData("\033(U\005\000", 5);
679 putchar(units
/ header
->HWResolution
[1]);
680 putchar(units
/ header
->HWResolution
[1]);
681 putchar(units
/ header
->HWResolution
[0]);
687 cupsWritePrintData("\033(U\001\000", 5);
688 putchar(3600 / header
->HWResolution
[1]);
692 * Set the page length...
695 PrinterLength
= header
->PageSize
[1] * header
->HWResolution
[1] / 72;
697 if (ppd
->model_number
& ESCP_PAGE_SIZE
)
700 * Set page size (expands bottom margin)...
703 cupsWritePrintData("\033(S\010\000", 5);
705 i
= header
->PageSize
[0] * header
->HWResolution
[1] / 72;
711 i
= header
->PageSize
[1] * header
->HWResolution
[1] / 72;
719 cupsWritePrintData("\033(C\002\000", 5);
720 putchar(PrinterLength
& 255);
721 putchar(PrinterLength
>> 8);
725 * Set the top and bottom margins...
728 PrinterTop
= (int)((ppd
->sizes
[1].length
- ppd
->sizes
[1].top
) *
729 header
->HWResolution
[1] / 72.0);
731 if (ppd
->model_number
& ESCP_EXT_MARGINS
)
733 cupsWritePrintData("\033(c\010\000", 5);
736 putchar(PrinterTop
>> 8);
737 putchar(PrinterTop
>> 16);
738 putchar(PrinterTop
>> 24);
740 putchar(PrinterLength
);
741 putchar(PrinterLength
>> 8);
742 putchar(PrinterLength
>> 16);
743 putchar(PrinterLength
>> 24);
747 cupsWritePrintData("\033(c\004\000", 5);
749 putchar(PrinterTop
& 255);
750 putchar(PrinterTop
>> 8);
752 putchar(PrinterLength
& 255);
753 putchar(PrinterLength
>> 8);
757 * Set the top position...
760 cupsWritePrintData("\033(V\002\000\000\000", 7);
763 * Enable unidirectional printing depending on the mode...
766 if ((attr
= cupsFindAttr(ppd
, "cupsESCPDirection", colormodel
,
767 header
->MediaType
, resolution
, spec
,
768 sizeof(spec
))) != NULL
)
769 printf("\033U%c", atoi(attr
->value
));
772 * Enable/disable microweaving as needed...
775 if ((attr
= cupsFindAttr(ppd
, "cupsESCPMicroWeave", colormodel
,
776 header
->MediaType
, resolution
, spec
,
777 sizeof(spec
))) != NULL
)
778 printf("\033(i\001%c%c", 0, atoi(attr
->value
));
781 * Set the dot size and print speed as needed...
784 if ((attr
= cupsFindAttr(ppd
, "cupsESCPDotSize", colormodel
,
785 header
->MediaType
, resolution
, spec
,
786 sizeof(spec
))) != NULL
)
787 printf("\033(e\002%c%c%c", 0, 0, atoi(attr
->value
));
789 if (ppd
->model_number
& ESCP_ESCK
)
792 * Set the print mode...
795 if (PrinterPlanes
== 1)
798 * Fast black printing.
801 cupsWritePrintData("\033(K\002\000\000\001", 7);
809 cupsWritePrintData("\033(K\002\000\000\002", 7);
814 * Get softweave settings from header...
817 if (header
->cupsRowCount
<= 1)
826 DotRowCount
= header
->cupsRowCount
;
827 DotRowFeed
= header
->cupsRowFeed
;
828 DotRowStep
= header
->cupsRowStep
% 100;
829 DotColStep
= header
->cupsRowStep
/ 100;
836 * Setup softweave parameters...
840 DotRowMax
= DotRowCount
* DotRowStep
;
841 DotBufferSize
= (header
->cupsWidth
/ DotColStep
* BitPlanes
+ 7) / 8;
843 fprintf(stderr
, "DEBUG: DotBufferSize = %d\n", DotBufferSize
);
844 fprintf(stderr
, "DEBUG: DotColStep = %d\n", DotColStep
);
845 fprintf(stderr
, "DEBUG: DotRowMax = %d\n", DotRowMax
);
846 fprintf(stderr
, "DEBUG: DotRowStep = %d\n", DotRowStep
);
847 fprintf(stderr
, "DEBUG: DotRowFeed = %d\n", DotRowFeed
);
848 fprintf(stderr
, "DEBUG: DotRowCount = %d\n", DotRowCount
);
852 DotBuffers
[0] = NULL
;
854 fprintf(stderr
, "DEBUG: model_number = %x\n", ppd
->model_number
);
859 * Compute offsets for the color jets on the print head...
862 bands
= DotRowStep
* DotColStep
* PrinterPlanes
* 4;
864 memset(DotRowOffset
, 0, sizeof(DotRowOffset
));
866 if (PrinterPlanes
== 1)
869 * Use full height of print head...
872 if ((attr
= ppdFindAttr(ppd
, "cupsESCPBlack", resolution
)) != NULL
&&
876 * Use custom black head data...
879 sscanf(attr
->value
, "%d%d", &DotRowCount
, &DotRowStep
);
882 else if (ppd
->model_number
& ESCP_STAGGER
)
885 * Use staggered print head...
888 fputs("DEBUG: Offset head detected...\n", stderr
);
890 if ((attr
= ppdFindAttr(ppd
, "cupsESCPOffsets", resolution
)) != NULL
&&
894 * Use only 1/3 of the print head when printing color...
897 sscanf(attr
->value
, "%d%d%d%d", DotRowOffset
+ 0,
898 DotRowOffset
+ 1, DotRowOffset
+ 2, DotRowOffset
+ 3);
902 for (i
= 0; i
< PrinterPlanes
; i
++)
903 fprintf(stderr
, "DEBUG: DotRowOffset[%d] = %d\n", i
, DotRowOffset
[i
]);
909 for (i
= 0; i
< bands
; i
++)
911 band
= (cups_weave_t
*)calloc(1, sizeof(cups_weave_t
));
912 band
->next
= DotAvailList
;
915 band
->buffer
= calloc(DotRowCount
, DotBufferSize
);
920 fputs("ERROR: Unable to allocate band list\n", stderr
);
924 fputs("DEBUG: Pointer list at start of page...\n", stderr
);
926 for (band
= DotAvailList
; band
!= NULL
; band
= band
->next
)
927 fprintf(stderr
, "DEBUG: %p\n", band
);
929 fputs("DEBUG: ----END----\n", stderr
);
932 * Fill the initial bands...
935 modrow
= DotColStep
* DotRowStep
;
940 * Automatically compute the optimal feed value...
943 DotRowFeed
= DotRowCount
/ DotColStep
- DotRowStep
;
945 while ((((DotRowFeed
% 2) == 0) == ((DotRowCount
% 2) == 0) ||
946 ((DotRowFeed
% 3) == 0) == ((DotRowCount
% 3) == 0) ||
947 ((DotRowFeed
% 5) == 0) == ((DotRowCount
% 5) == 0)) &&
954 fprintf(stderr
, "DEBUG: Auto DotRowFeed = %d, modrow=%d...\n",
958 memset(DotBands
, 0, sizeof(DotBands
));
960 for (i
= modrow
, subrow
= modrow
- 1, y
= DotRowFeed
;
962 i
--, y
+= DotRowFeed
)
964 while (DotBands
[subrow
][0])
967 * This subrow is already used, move to another one...
970 subrow
= (subrow
+ 1) % modrow
;
973 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
976 * Pull the next available band from the list...
980 DotAvailList
= DotAvailList
->next
;
981 DotBands
[subrow
][plane
] = band
;
984 * Start the band in the first few passes, with the number of rows
985 * varying to allow for a nice interleaved pattern...
988 band
->x
= subrow
/ DotRowStep
;
989 band
->y
= (subrow
% DotRowStep
) + DotRowOffset
[plane
];
992 band
->count
= DotRowCount
- y
/ DotRowStep
;
996 else if (band
->count
> DotRowCount
)
997 band
->count
= DotRowCount
;
999 fprintf(stderr
, "DEBUG: DotBands[%d][%d] = %p, x = %d, y = %d, plane = %d, count = %d\n",
1000 subrow
, plane
, band
, band
->x
, band
->y
, band
->plane
, band
->count
);
1003 subrow
= (subrow
+ DotRowFeed
) % modrow
;
1009 * Allocate memory for a single line of graphics...
1012 ptr
= calloc(PrinterPlanes
, DotBufferSize
);
1014 for (plane
= 0; plane
< PrinterPlanes
; plane
++, ptr
+= DotBufferSize
)
1015 DotBuffers
[plane
] = ptr
;
1019 * Set the output resolution...
1022 cupsWritePrintData("\033(D\004\000", 5);
1024 putchar(units
>> 8);
1025 putchar(units
* DotRowStep
/ header
->HWResolution
[1]);
1026 putchar(units
* DotColStep
/ header
->HWResolution
[0]);
1029 * Set the top of form...
1035 * Allocate buffers as needed...
1038 PixelBuffer
= malloc(header
->cupsBytesPerLine
);
1039 InputBuffer
= malloc(header
->cupsWidth
* PrinterPlanes
* 2);
1040 OutputBuffers
[0] = malloc(PrinterPlanes
* header
->cupsWidth
);
1042 for (i
= 1; i
< PrinterPlanes
; i
++)
1043 OutputBuffers
[i
] = OutputBuffers
[0] + i
* header
->cupsWidth
;
1046 CMYKBuffer
= malloc(header
->cupsWidth
* PrinterPlanes
);
1048 CompBuffer
= malloc(10 * DotBufferSize
* DotRowMax
);
1053 * 'EndPage()' - Finish a page of graphics.
1057 EndPage(ppd_file_t
*ppd
, /* I - PPD file */
1058 cups_page_header2_t
*header
) /* I - Page header */
1060 int i
; /* Looping var */
1061 cups_weave_t
*band
, /* Current band */
1062 *next
; /* Next band in list */
1063 int plane
; /* Current plane */
1064 int subrow
; /* Current subrow */
1065 int subrows
; /* Number of subrows */
1069 * Output the last bands of print data as necessary...
1075 * Move the remaining bands to the used or avail lists...
1078 subrows
= DotRowStep
* DotColStep
;
1080 for (subrow
= 0; subrow
< subrows
; subrow
++)
1081 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
1083 if (DotBands
[subrow
][plane
]->dirty
)
1086 * Insert into the used list...
1089 DotBands
[subrow
][plane
]->count
= DotBands
[subrow
][plane
]->row
;
1091 AddBand(DotBands
[subrow
][plane
]);
1096 * Nothing here, so move it to the available list...
1099 DotBands
[subrow
][plane
]->next
= DotAvailList
;
1100 DotAvailList
= DotBands
[subrow
][plane
];
1103 DotBands
[subrow
][plane
] = NULL
;
1107 * Loop until all bands are written...
1110 fputs("DEBUG: Pointer list at end of page...\n", stderr
);
1112 for (band
= DotUsedList
; band
!= NULL
; band
= band
->next
)
1113 fprintf(stderr
, "DEBUG: %p (used)\n", band
);
1114 for (band
= DotAvailList
; band
!= NULL
; band
= band
->next
)
1115 fprintf(stderr
, "DEBUG: %p (avail)\n", band
);
1117 fputs("DEBUG: ----END----\n", stderr
);
1119 for (band
= DotUsedList
; band
!= NULL
; band
= next
)
1123 OutputBand(ppd
, header
, band
);
1125 fprintf(stderr
, "DEBUG: freeing used band %p, prev = %p, next = %p\n",
1126 band
, band
->prev
, band
->next
);
1133 * Free memory for the available bands, if any...
1136 for (band
= DotAvailList
; band
!= NULL
; band
= next
)
1140 fprintf(stderr
, "DEBUG: freeing avail band %p, prev = %p, next = %p\n",
1141 band
, band
->prev
, band
->next
);
1148 free(DotBuffers
[0]);
1151 * Output a page eject sequence...
1157 * Free memory for the page...
1160 for (i
= 0; i
< PrinterPlanes
; i
++)
1162 cupsDitherDelete(DitherStates
[i
]);
1163 cupsLutDelete(DitherLuts
[i
]);
1166 free(OutputBuffers
[0]);
1172 cupsCMYKDelete(CMYK
);
1183 * 'Shutdown()' - Shutdown a printer.
1187 Shutdown(ppd_file_t
*ppd
) /* I - PPD file */
1190 * Reset the printer...
1195 if (ppd
->model_number
& ESCP_REMOTE
)
1198 * Go into remote mode...
1201 cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
1207 cupsWritePrintData("LD\000\000", 4);
1210 * Exit remote mode...
1213 cupsWritePrintData("\033\000\000\000", 4);
1219 * 'AddBand()' - Add a band of data to the used list.
1223 AddBand(cups_weave_t
*band
) /* I - Band to add */
1225 cups_weave_t
*current
, /* Current band */
1226 *prev
; /* Previous band */
1229 if (band
->count
< 1)
1232 for (current
= DotUsedList
, prev
= NULL
;
1234 prev
= current
, current
= current
->next
)
1235 if (band
->y
< current
->y
||
1236 (band
->y
== current
->y
&& band
->x
< current
->x
) ||
1237 (band
->y
== current
->y
&& band
->x
== current
->x
&&
1238 band
->plane
< current
->plane
))
1241 if (current
!= NULL
)
1244 * Insert the band...
1247 band
->next
= current
;
1249 current
->prev
= band
;
1256 else if (prev
!= NULL
)
1259 * Append the band to the end...
1269 * First band in list...
1280 * 'CancelJob()' - Cancel the current job...
1284 CancelJob(int sig
) /* I - Signal */
1293 * 'CompressData()' - Compress a line of graphics.
1297 CompressData(ppd_file_t
*ppd
, /* I - PPD file information */
1298 const unsigned char *line
, /* I - Data to compress */
1299 const int length
,/* I - Number of bytes */
1300 int plane
, /* I - Color plane */
1301 int type
, /* I - Type of compression */
1302 const int rows
, /* I - Number of lines to write */
1303 const int xstep
, /* I - Spacing between columns */
1304 const int ystep
, /* I - Spacing between lines */
1305 const int offset
)/* I - Head offset */
1307 register const unsigned char *line_ptr
,
1308 /* Current byte pointer */
1309 *line_end
, /* End-of-line byte pointer */
1310 *start
; /* Start of compression sequence */
1311 register unsigned char *comp_ptr
; /* Pointer into compression buffer */
1312 register int count
; /* Count of bytes for output */
1313 register int bytes
; /* Number of bytes per row */
1314 static int ctable
[7][7] = /* Colors */
1316 { 0, 0, 0, 0, 0, 0, 0 }, /* K */
1317 { 0, 16, 0, 0, 0, 0, 0 }, /* Kk */
1318 { 2, 1, 4, 0, 0, 0, 0 }, /* CMY */
1319 { 2, 1, 4, 0, 0, 0, 0 }, /* CMYK */
1320 { 0, 0, 0, 0, 0, 0, 0 },
1321 { 2, 18, 1, 17, 4, 0, 0 }, /* CcMmYK */
1322 { 2, 18, 1, 17, 4, 0, 16 }, /* CcMmYKk */
1330 * Do no compression...
1333 line_ptr
= (const unsigned char *)line
;
1334 line_end
= (const unsigned char *)line
+ length
;
1339 * Do TIFF pack-bits encoding...
1342 line_ptr
= (const unsigned char *)line
;
1343 line_end
= (const unsigned char *)line
+ length
;
1344 comp_ptr
= CompBuffer
;
1346 while (line_ptr
< line_end
&& (comp_ptr
- CompBuffer
) < length
)
1348 if ((line_ptr
+ 1) >= line_end
)
1351 * Single byte on the end...
1355 *comp_ptr
++ = *line_ptr
++;
1357 else if (line_ptr
[0] == line_ptr
[1])
1360 * Repeated sequence...
1366 while (line_ptr
< (line_end
- 1) &&
1367 line_ptr
[0] == line_ptr
[1] &&
1374 *comp_ptr
++ = 257 - count
;
1375 *comp_ptr
++ = *line_ptr
++;
1380 * Non-repeated sequence...
1387 while (line_ptr
< (line_end
- 1) &&
1388 line_ptr
[0] != line_ptr
[1] &&
1395 *comp_ptr
++ = count
- 1;
1397 memcpy(comp_ptr
, start
, count
);
1402 if ((comp_ptr
- CompBuffer
) < length
)
1404 line_ptr
= (const unsigned char *)CompBuffer
;
1405 line_end
= (const unsigned char *)comp_ptr
;
1410 line_ptr
= (const unsigned char *)line
;
1411 line_end
= (const unsigned char *)line
+ length
;
1417 * Position the print head...
1425 cupsWritePrintData("\033(\\\004\000\240\005", 7);
1430 putchar(offset
>> 8);
1434 * Send the graphics...
1437 bytes
= length
/ rows
;
1439 if (ppd
->model_number
& ESCP_RASTER_ESCI
)
1442 * Send graphics with ESC i command.
1446 putchar(ctable
[PrinterPlanes
- 1][plane
]);
1449 putchar(bytes
& 255);
1450 putchar(bytes
>> 8);
1451 putchar(rows
& 255);
1457 * Set the color if necessary...
1460 if (PrinterPlanes
> 1)
1462 plane
= ctable
[PrinterPlanes
- 1][plane
];
1465 printf("\033(r%c%c%c%c", 2, 0, 1, plane
& 0x0f);
1467 printf("\033r%c", plane
);
1471 * Send graphics with ESC . command.
1481 putchar(bytes
& 255);
1482 putchar(bytes
>> 8);
1485 cupsWritePrintData(line_ptr
, line_end
- line_ptr
);
1490 * 'OutputBand()' - Output a band of graphics.
1494 OutputBand(ppd_file_t
*ppd
, /* I - PPD file */
1495 cups_page_header2_t
*header
, /* I - Page header */
1496 cups_weave_t
*band
) /* I - Current band */
1498 int xstep
, /* Spacing between columns */
1499 ystep
; /* Spacing between rows */
1503 * Interleaved ESC/P2 graphics...
1506 OutputFeed
= band
->y
- DotRowCurrent
;
1507 DotRowCurrent
= band
->y
;
1509 fprintf(stderr
, "DEBUG: Printing band %p, x = %d, y = %d, plane = %d, count = %d, OutputFeed = %d\n",
1510 band
, band
->x
, band
->y
, band
->plane
, band
->count
, OutputFeed
);
1513 * Compute step values...
1516 xstep
= 3600 * DotColStep
/ header
->HWResolution
[0];
1517 ystep
= 3600 * DotRowStep
/ header
->HWResolution
[1];
1520 * Output the band...
1525 cupsWritePrintData("\033(v\002\000", 5);
1526 putchar(OutputFeed
& 255);
1527 putchar(OutputFeed
>> 8);
1532 CompressData(ppd
, band
->buffer
, band
->count
* DotBufferSize
, band
->plane
,
1533 header
->cupsCompression
, band
->count
, xstep
, ystep
, band
->x
);
1539 memset(band
->buffer
, 0, band
->count
* DotBufferSize
);
1543 * Flush the output buffers...
1551 * 'ProcessLine()' - Read graphics from the page stream and output as needed.
1555 ProcessLine(ppd_file_t
*ppd
, /* I - PPD file */
1556 cups_raster_t
*ras
, /* I - Raster stream */
1557 cups_page_header2_t
*header
, /* I - Page header */
1558 const int y
) /* I - Current scanline */
1560 int plane
, /* Current color plane */
1561 width
, /* Width of line */
1562 subwidth
, /* Width of interleaved row */
1563 subrow
, /* Subrow for interleaved output */
1564 offset
, /* Offset to current line */
1565 pass
, /* Pass number */
1566 xstep
, /* X step value */
1567 ystep
; /* Y step value */
1568 cups_weave_t
*band
; /* Current band */
1572 * Read a row of graphics...
1575 if (!cupsRasterReadPixels(ras
, PixelBuffer
, header
->cupsBytesPerLine
))
1579 * Perform the color separation...
1582 width
= header
->cupsWidth
;
1583 subwidth
= header
->cupsWidth
/ DotColStep
;
1584 xstep
= 3600 / header
->HWResolution
[0];
1585 ystep
= 3600 / header
->HWResolution
[1];
1587 switch (header
->cupsColorSpace
)
1589 case CUPS_CSPACE_W
:
1592 cupsRGBDoGray(RGB
, PixelBuffer
, CMYKBuffer
, width
);
1593 cupsCMYKDoCMYK(CMYK
, CMYKBuffer
, InputBuffer
, width
);
1596 cupsCMYKDoGray(CMYK
, PixelBuffer
, InputBuffer
, width
);
1599 case CUPS_CSPACE_K
:
1600 cupsCMYKDoBlack(CMYK
, PixelBuffer
, InputBuffer
, width
);
1604 case CUPS_CSPACE_RGB
:
1607 cupsRGBDoRGB(RGB
, PixelBuffer
, CMYKBuffer
, width
);
1608 cupsCMYKDoCMYK(CMYK
, CMYKBuffer
, InputBuffer
, width
);
1611 cupsCMYKDoRGB(CMYK
, PixelBuffer
, InputBuffer
, width
);
1614 case CUPS_CSPACE_CMYK
:
1615 cupsCMYKDoCMYK(CMYK
, PixelBuffer
, InputBuffer
, width
);
1620 * Dither the pixels...
1623 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
1625 cupsDitherLine(DitherStates
[plane
], DitherLuts
[plane
], InputBuffer
+ plane
,
1626 PrinterPlanes
, OutputBuffers
[plane
]);
1631 * Handle microweaved output...
1634 if (cupsCheckBytes(OutputBuffers
[plane
], width
))
1638 cupsPackHorizontal(OutputBuffers
[plane
], DotBuffers
[plane
],
1641 cupsPackHorizontal2(OutputBuffers
[plane
], DotBuffers
[plane
],
1646 cupsWritePrintData("\033(v\002\000", 5);
1647 putchar(OutputFeed
& 255);
1648 putchar(OutputFeed
>> 8);
1652 CompressData(ppd
, DotBuffers
[plane
], DotBufferSize
, plane
, 1, 1,
1659 * Handle softweaved output...
1662 for (pass
= 0, subrow
= y
% DotRowStep
;
1664 pass
++, subrow
+= DotRowStep
)
1667 * See if we need to output the band...
1670 band
= DotBands
[subrow
][plane
];
1671 offset
= band
->row
* DotBufferSize
;
1674 cupsPackHorizontal(OutputBuffers
[plane
] + pass
,
1675 band
->buffer
+ offset
, subwidth
, 0, DotColStep
);
1677 cupsPackHorizontal2(OutputBuffers
[plane
] + pass
,
1678 band
->buffer
+ offset
, subwidth
, DotColStep
);
1681 band
->dirty
|= !cupsCheckBytes(band
->buffer
+ offset
, DotBufferSize
);
1682 if (band
->row
>= band
->count
)
1687 * Dirty band needs to be added to the used list...
1693 * Then find a new band...
1696 if (DotAvailList
== NULL
)
1698 OutputBand(ppd
, header
, DotUsedList
);
1700 DotBands
[subrow
][plane
] = DotUsedList
;
1701 DotUsedList
->x
= band
->x
;
1702 DotUsedList
->y
= band
->y
+ band
->count
* DotRowStep
;
1703 DotUsedList
->plane
= band
->plane
;
1704 DotUsedList
->row
= 0;
1705 DotUsedList
->count
= DotRowCount
;
1706 DotUsedList
= DotUsedList
->next
;
1710 DotBands
[subrow
][plane
] = DotAvailList
;
1711 DotAvailList
->x
= band
->x
;
1712 DotAvailList
->y
= band
->y
+ band
->count
* DotRowStep
;
1713 DotAvailList
->plane
= band
->plane
;
1714 DotAvailList
->row
= 0;
1715 DotAvailList
->count
= DotRowCount
;
1716 DotAvailList
= DotAvailList
->next
;
1722 * This band isn't dirty, so reuse it...
1725 fprintf(stderr
, "DEBUG: Blank band %p, x = %d, y = %d, plane = %d, count = %d\n",
1726 band
, band
->x
, band
->y
, band
->plane
, band
->count
);
1728 band
->y
+= band
->count
* DotRowStep
;
1730 band
->count
= DotRowCount
;
1743 * 'main()' - Main entry and processing of driver.
1746 int /* O - Exit status */
1747 main(int argc
, /* I - Number of command-line arguments */
1748 char *argv
[]) /* I - Command-line arguments */
1750 int fd
; /* File descriptor */
1751 cups_raster_t
*ras
; /* Raster stream for printing */
1752 cups_page_header2_t header
; /* Page header from file */
1753 int page
; /* Current page */
1754 int y
; /* Current line */
1755 ppd_file_t
*ppd
; /* PPD file */
1756 int num_options
; /* Number of options */
1757 cups_option_t
*options
; /* Options */
1758 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1759 struct sigaction action
; /* Actions for POSIX signals */
1760 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1764 * Make sure status messages are not buffered...
1767 setbuf(stderr
, NULL
);
1770 * Check command-line...
1773 if (argc
< 6 || argc
> 7)
1775 _cupsLangPrintf(stderr
,
1776 _("ERROR: %s job-id user title copies options [file]\n"),
1781 num_options
= cupsParseOptions(argv
[5], 0, &options
);
1784 * Open the PPD file...
1787 ppd
= ppdOpenFile(getenv("PPD"));
1791 _cupsLangPuts(stderr
, _("ERROR: Unable to open PPD file\n"));
1795 ppdMarkDefaults(ppd
);
1796 cupsMarkOptions(ppd
, num_options
, options
);
1799 * Open the page stream...
1804 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
1806 _cupsLangPrintf(stderr
, _("ERROR: Unable to open raster file - %s\n"),
1814 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
1817 * Register a signal handler to eject the current page if the
1823 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1824 sigset(SIGTERM
, CancelJob
);
1825 #elif defined(HAVE_SIGACTION)
1826 memset(&action
, 0, sizeof(action
));
1828 sigemptyset(&action
.sa_mask
);
1829 action
.sa_handler
= CancelJob
;
1830 sigaction(SIGTERM
, &action
, NULL
);
1832 signal(SIGTERM
, CancelJob
);
1833 #endif /* HAVE_SIGSET */
1836 * Initialize the print device...
1842 * Process pages as needed...
1847 while (cupsRasterReadHeader2(ras
, &header
))
1850 * Write a status message with the page number and number of copies.
1858 fprintf(stderr
, "PAGE: %d 1\n", page
);
1859 _cupsLangPrintf(stderr
, _("INFO: Starting page %d...\n"), page
);
1861 StartPage(ppd
, &header
);
1863 for (y
= 0; y
< header
.cupsHeight
; y
++)
1866 * Let the user know how far we have progressed...
1873 _cupsLangPrintf(stderr
, _("INFO: Printing page %d, %d%% complete...\n"),
1874 page
, 100 * y
/ header
.cupsHeight
);
1877 * Read and write a line of graphics or whitespace...
1880 ProcessLine(ppd
, ras
, &header
, y
);
1887 _cupsLangPrintf(stderr
, _("INFO: Finished page %d...\n"), page
);
1889 EndPage(ppd
, &header
);
1897 cupsFreeOptions(num_options
, options
);
1899 cupsRasterClose(ras
);
1906 _cupsLangPuts(stderr
, _("ERROR: No pages found\n"));
1911 _cupsLangPuts(stderr
, _("INFO: Ready to print.\n"));