4 * Advanced EPSON ESC/P raster driver for CUPS.
6 * Copyright 2007-2008 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/string.h>
35 #include "data/escp.h"
43 typedef struct cups_weave_str
45 struct cups_weave_str
*prev
, /* Previous band */
46 *next
; /* Next band */
47 int x
, y
, /* Column/Line on the page */
48 plane
, /* Color plane */
49 dirty
, /* Is this buffer dirty? */
50 row
, /* Row in the buffer */
51 count
; /* Max rows this pass */
52 unsigned char *buffer
; /* Data buffer */
60 cups_rgb_t
*RGB
; /* RGB color separation data */
61 cups_cmyk_t
*CMYK
; /* CMYK color separation data */
62 unsigned char *PixelBuffer
, /* Pixel buffer */
63 *CMYKBuffer
, /* CMYK buffer */
64 *OutputBuffers
[7], /* Output buffers */
65 *DotBuffers
[7], /* Dot buffers */
66 *CompBuffer
; /* Compression buffer */
67 short *InputBuffer
; /* Color separation buffer */
68 cups_weave_t
*DotAvailList
, /* Available buffers */
69 *DotUsedList
, /* Used buffers */
70 *DotBands
[128][7]; /* Buffers in use */
71 int DotBufferSize
, /* Size of dot buffers */
72 DotRowMax
, /* Maximum row number in buffer */
73 DotColStep
, /* Step for each output column */
74 DotRowStep
, /* Step for each output line */
75 DotRowFeed
, /* Amount to feed for interleave */
76 DotRowCount
, /* Number of rows to output */
77 DotRowOffset
[7], /* Offset for each color on print head */
78 DotRowCurrent
, /* Current row */
79 DotSize
; /* Dot size (Pro 5000 only) */
80 int PrinterPlanes
, /* # of color planes */
81 BitPlanes
, /* # of bit planes per color */
82 PrinterTop
, /* Top of page */
83 PrinterLength
; /* Length of page */
84 cups_lut_t
*DitherLuts
[7]; /* Lookup tables for dithering */
85 cups_dither_t
*DitherStates
[7]; /* Dither state tables */
86 int OutputFeed
; /* Number of lines to skip */
87 int Canceled
; /* Is the job canceled? */
94 void Setup(ppd_file_t
*);
95 void StartPage(ppd_file_t
*, cups_page_header2_t
*);
96 void EndPage(ppd_file_t
*, cups_page_header2_t
*);
97 void Shutdown(ppd_file_t
*);
99 void AddBand(cups_weave_t
*band
);
100 void CancelJob(int sig
);
101 void CompressData(ppd_file_t
*, const unsigned char *, const int,
102 int, int, const int, const int, const int,
104 void OutputBand(ppd_file_t
*, cups_page_header2_t
*,
106 void ProcessLine(ppd_file_t
*, cups_raster_t
*,
107 cups_page_header2_t
*, const int y
);
111 * 'Setup()' - Prepare a printer for graphics output.
115 Setup(ppd_file_t
*ppd
) /* I - PPD file */
118 * Some EPSON printers need an additional command issued at the
119 * beginning of each job to exit from USB "packet" mode...
122 if (ppd
->model_number
& ESCP_USB
)
123 cupsWritePrintData("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
128 * 'StartPage()' - Start a page of graphics.
132 StartPage(ppd_file_t
*ppd
, /* I - PPD file */
133 cups_page_header2_t
*header
) /* I - Page header */
135 int i
, y
; /* Looping vars */
136 int subrow
, /* Current subrow */
137 modrow
, /* Subrow modulus */
138 plane
; /* Current color plane */
139 unsigned char *ptr
; /* Pointer into dot buffer */
140 int bands
; /* Number of bands to allocate */
141 int units
; /* Units for resolution */
142 cups_weave_t
*band
; /* Current band */
143 const char *colormodel
; /* Color model string */
144 char resolution
[PPD_MAX_NAME
],
145 /* Resolution string */
146 spec
[PPD_MAX_NAME
]; /* PPD attribute name */
147 ppd_attr_t
*attr
; /* Attribute from PPD file */
148 const float default_lut
[2] = /* Default dithering lookup table */
155 fprintf(stderr
, "DEBUG: StartPage...\n");
156 fprintf(stderr
, "DEBUG: MediaClass = \"%s\"\n", header
->MediaClass
);
157 fprintf(stderr
, "DEBUG: MediaColor = \"%s\"\n", header
->MediaColor
);
158 fprintf(stderr
, "DEBUG: MediaType = \"%s\"\n", header
->MediaType
);
159 fprintf(stderr
, "DEBUG: OutputType = \"%s\"\n", header
->OutputType
);
161 fprintf(stderr
, "DEBUG: AdvanceDistance = %d\n", header
->AdvanceDistance
);
162 fprintf(stderr
, "DEBUG: AdvanceMedia = %d\n", header
->AdvanceMedia
);
163 fprintf(stderr
, "DEBUG: Collate = %d\n", header
->Collate
);
164 fprintf(stderr
, "DEBUG: CutMedia = %d\n", header
->CutMedia
);
165 fprintf(stderr
, "DEBUG: Duplex = %d\n", header
->Duplex
);
166 fprintf(stderr
, "DEBUG: HWResolution = [ %d %d ]\n", header
->HWResolution
[0],
167 header
->HWResolution
[1]);
168 fprintf(stderr
, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
169 header
->ImagingBoundingBox
[0], header
->ImagingBoundingBox
[1],
170 header
->ImagingBoundingBox
[2], header
->ImagingBoundingBox
[3]);
171 fprintf(stderr
, "DEBUG: InsertSheet = %d\n", header
->InsertSheet
);
172 fprintf(stderr
, "DEBUG: Jog = %d\n", header
->Jog
);
173 fprintf(stderr
, "DEBUG: LeadingEdge = %d\n", header
->LeadingEdge
);
174 fprintf(stderr
, "DEBUG: Margins = [ %d %d ]\n", header
->Margins
[0],
176 fprintf(stderr
, "DEBUG: ManualFeed = %d\n", header
->ManualFeed
);
177 fprintf(stderr
, "DEBUG: MediaPosition = %d\n", header
->MediaPosition
);
178 fprintf(stderr
, "DEBUG: MediaWeight = %d\n", header
->MediaWeight
);
179 fprintf(stderr
, "DEBUG: MirrorPrint = %d\n", header
->MirrorPrint
);
180 fprintf(stderr
, "DEBUG: NegativePrint = %d\n", header
->NegativePrint
);
181 fprintf(stderr
, "DEBUG: NumCopies = %d\n", header
->NumCopies
);
182 fprintf(stderr
, "DEBUG: Orientation = %d\n", header
->Orientation
);
183 fprintf(stderr
, "DEBUG: OutputFaceUp = %d\n", header
->OutputFaceUp
);
184 fprintf(stderr
, "DEBUG: PageSize = [ %d %d ]\n", header
->PageSize
[0],
185 header
->PageSize
[1]);
186 fprintf(stderr
, "DEBUG: Separations = %d\n", header
->Separations
);
187 fprintf(stderr
, "DEBUG: TraySwitch = %d\n", header
->TraySwitch
);
188 fprintf(stderr
, "DEBUG: Tumble = %d\n", header
->Tumble
);
189 fprintf(stderr
, "DEBUG: cupsWidth = %d\n", header
->cupsWidth
);
190 fprintf(stderr
, "DEBUG: cupsHeight = %d\n", header
->cupsHeight
);
191 fprintf(stderr
, "DEBUG: cupsMediaType = %d\n", header
->cupsMediaType
);
192 fprintf(stderr
, "DEBUG: cupsBitsPerColor = %d\n", header
->cupsBitsPerColor
);
193 fprintf(stderr
, "DEBUG: cupsBitsPerPixel = %d\n", header
->cupsBitsPerPixel
);
194 fprintf(stderr
, "DEBUG: cupsBytesPerLine = %d\n", header
->cupsBytesPerLine
);
195 fprintf(stderr
, "DEBUG: cupsColorOrder = %d\n", header
->cupsColorOrder
);
196 fprintf(stderr
, "DEBUG: cupsColorSpace = %d\n", header
->cupsColorSpace
);
197 fprintf(stderr
, "DEBUG: cupsCompression = %d\n", header
->cupsCompression
);
198 fprintf(stderr
, "DEBUG: cupsRowCount = %d\n", header
->cupsRowCount
);
199 fprintf(stderr
, "DEBUG: cupsRowFeed = %d\n", header
->cupsRowFeed
);
200 fprintf(stderr
, "DEBUG: cupsRowStep = %d\n", header
->cupsRowStep
);
203 * Figure out the color model and spec strings...
206 switch (header
->cupsColorSpace
)
209 colormodel
= "Black";
215 case CUPS_CSPACE_RGB
:
218 case CUPS_CSPACE_CMYK
:
223 if (header
->HWResolution
[0] != header
->HWResolution
[1])
224 snprintf(resolution
, sizeof(resolution
), "%dx%ddpi",
225 header
->HWResolution
[0], header
->HWResolution
[1]);
227 snprintf(resolution
, sizeof(resolution
), "%ddpi",
228 header
->HWResolution
[0]);
230 if (!header
->MediaType
[0])
231 strcpy(header
->MediaType
, "Plain");
234 * Load the appropriate color profiles...
240 fputs("DEBUG: Attempting to load color profiles using the following values:\n", stderr
);
241 fprintf(stderr
, "DEBUG: ColorModel = %s\n", colormodel
);
242 fprintf(stderr
, "DEBUG: MediaType = %s\n", header
->MediaType
);
243 fprintf(stderr
, "DEBUG: Resolution = %s\n", resolution
);
245 if (header
->cupsColorSpace
== CUPS_CSPACE_RGB
||
246 header
->cupsColorSpace
== CUPS_CSPACE_W
)
247 RGB
= cupsRGBLoad(ppd
, colormodel
, header
->MediaType
, resolution
);
251 CMYK
= cupsCMYKLoad(ppd
, colormodel
, header
->MediaType
, resolution
);
254 fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr
);
257 fputs("DEBUG: Loaded CMYK separation from PPD.\n", stderr
);
260 fputs("DEBUG: Loading default CMYK separation.\n", stderr
);
261 CMYK
= cupsCMYKNew(4);
264 PrinterPlanes
= CMYK
->num_channels
;
266 fprintf(stderr
, "DEBUG: PrinterPlanes = %d\n", PrinterPlanes
);
269 * Get the dithering parameters...
272 switch (PrinterPlanes
)
275 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
276 resolution
, "Black");
280 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
281 resolution
, "Black");
282 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
283 resolution
, "LightBlack");
287 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
289 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
290 resolution
, "Magenta");
291 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
292 resolution
, "Yellow");
296 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
298 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
299 resolution
, "Magenta");
300 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
301 resolution
, "Yellow");
302 DitherLuts
[3] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
303 resolution
, "Black");
306 case 6 : /* CcMmYK */
307 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
309 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
310 resolution
, "LightCyan");
311 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
312 resolution
, "Magenta");
313 DitherLuts
[3] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
314 resolution
, "LightMagenta");
315 DitherLuts
[4] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
316 resolution
, "Yellow");
317 DitherLuts
[5] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
318 resolution
, "Black");
321 case 7 : /* CcMmYKk */
322 DitherLuts
[0] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
324 DitherLuts
[1] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
325 resolution
, "LightCyan");
326 DitherLuts
[2] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
327 resolution
, "Magenta");
328 DitherLuts
[3] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
329 resolution
, "LightMagenta");
330 DitherLuts
[4] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
331 resolution
, "Yellow");
332 DitherLuts
[5] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
333 resolution
, "Black");
334 DitherLuts
[6] = cupsLutLoad(ppd
, colormodel
, header
->MediaType
,
335 resolution
, "LightBlack");
339 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
341 DitherStates
[plane
] = cupsDitherNew(header
->cupsWidth
);
343 if (!DitherLuts
[plane
])
344 DitherLuts
[plane
] = cupsLutNew(2, default_lut
);
347 if (DitherLuts
[0][4095].pixel
> 1)
353 * Initialize the printer...
358 if (ppd
->model_number
& ESCP_REMOTE
)
361 * Go into remote mode...
364 cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
367 * Disable status reporting...
370 cupsWritePrintData("ST\002\000\000\000", 6);
373 * Enable borderless printing...
376 if ((attr
= ppdFindAttr(ppd
, "cupsESCPFP", NULL
)) != NULL
&& attr
->value
)
379 * Set horizontal offset...
382 i
= atoi(attr
->value
);
384 cupsWritePrintData("FP\003\000\000", 5);
393 if (header
->cupsMediaType
)
395 sprintf(spec
, "%d", header
->cupsMediaType
);
397 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN0", spec
)) != NULL
&& attr
->value
)
400 * Set feed sequence...
403 cupsWritePrintData("SN\003\000\000\000", 6);
404 putchar(atoi(attr
->value
));
407 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN1", spec
)) != NULL
&& attr
->value
)
413 cupsWritePrintData("SN\003\000\000\001", 6);
414 putchar(atoi(attr
->value
));
417 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN2", spec
)) != NULL
&& attr
->value
)
420 * Paper feeding/ejecting sequence...
423 cupsWritePrintData("SN\003\000\000\002", 6);
424 putchar(atoi(attr
->value
));
427 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN6", spec
)) != NULL
&& attr
->value
)
433 cupsWritePrintData("SN\003\000\000\006", 6);
434 putchar(atoi(attr
->value
));
437 if ((attr
= ppdFindAttr(ppd
, "cupsESCPMT", spec
)) != NULL
&& attr
->value
)
443 cupsWritePrintData("MT\003\000\000\000", 6);
444 putchar(atoi(attr
->value
));
447 if ((attr
= ppdFindAttr(ppd
, "cupsESCPPH", spec
)) != NULL
&& attr
->value
)
450 * Set paper thickness.
453 cupsWritePrintData("PH\002\000\000", 5);
454 putchar(atoi(attr
->value
));
458 sprintf(spec
, "%d", header
->MediaPosition
);
460 if (header
->MediaPosition
)
462 if ((attr
= ppdFindAttr(ppd
, "cupsESCPPC", spec
)) != NULL
&& attr
->value
)
468 cupsWritePrintData("PC\002\000\000", 5);
469 putchar(atoi(attr
->value
));
472 if ((attr
= ppdFindAttr(ppd
, "cupsESCPPP", spec
)) != NULL
&& attr
->value
)
481 sscanf(attr
->value
, "%d%d", &a
, &b
);
483 cupsWritePrintData("PP\003\000\000", 5);
488 if ((attr
= ppdFindAttr(ppd
, "cupsESCPEX", spec
)) != NULL
&& attr
->value
)
491 * Set media position.
494 cupsWritePrintData("EX\006\000\000\000\000\000\005", 9);
495 putchar(atoi(attr
->value
));
499 if ((attr
= ppdFindAttr(ppd
, "cupsESCPMS", spec
)) != NULL
&& attr
->value
)
505 cupsWritePrintData("MS\010\000\000", 5);
506 putchar(atoi(attr
->value
));
508 switch (header
->PageSize
[1])
534 case 595 : /* A4.Transverse */
550 case 516 : /* B5.Transverse */
558 case 1369 : /* Super A3/B */
566 case 792 : /* Letter */
574 case 612 : /* Letter.Transverse */
582 case 1004 : /* Legal */
590 case 1224 : /* Tabloid */
598 default : /* Custom size */
601 i
= 360 * header
->PageSize
[0] / 72;
604 i
= 360 * header
->PageSize
[1] / 72;
611 sprintf(spec
, "%d", header
->CutMedia
);
613 if ((attr
= ppdFindAttr(ppd
, "cupsESCPAC", spec
)) != NULL
&& attr
->value
)
616 * Enable/disable cutter.
619 cupsWritePrintData("AC\002\000\000", 5);
620 putchar(atoi(attr
->value
));
622 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN80", header
->MediaType
)) != NULL
&& attr
->value
)
628 cupsWritePrintData("SN\003\000\000\200", 6);
629 putchar(atoi(attr
->value
));
632 if ((attr
= ppdFindAttr(ppd
, "cupsESCPSN81", header
->MediaType
)) != NULL
&& attr
->value
)
635 * Cutting pressure...
638 cupsWritePrintData("SN\003\000\000\201", 6);
639 putchar(atoi(attr
->value
));
643 if ((attr
= ppdFindAttr(ppd
, "cupsESCPCO", spec
)) != NULL
&& attr
->value
)
646 * Enable/disable cutter.
649 cupsWritePrintData("CO\010\000\000\000", 6);
650 putchar(atoi(attr
->value
));
651 cupsWritePrintData("\000\000\000\000\000", 5);
655 * Exit remote mode...
658 cupsWritePrintData("\033\000\000\000", 4);
662 * Enter graphics mode...
665 cupsWritePrintData("\033(G\001\000\001", 6);
668 * Set the line feed increment...
671 /* TODO: get this from the PPD file... */
672 for (units
= 1440; units
< header
->HWResolution
[0]; units
*= 2);
674 if (ppd
->model_number
& ESCP_EXT_UNITS
)
676 cupsWritePrintData("\033(U\005\000", 5);
677 putchar(units
/ header
->HWResolution
[1]);
678 putchar(units
/ header
->HWResolution
[1]);
679 putchar(units
/ header
->HWResolution
[0]);
685 cupsWritePrintData("\033(U\001\000", 5);
686 putchar(3600 / header
->HWResolution
[1]);
690 * Set the page length...
693 PrinterLength
= header
->PageSize
[1] * header
->HWResolution
[1] / 72;
695 if (ppd
->model_number
& ESCP_PAGE_SIZE
)
698 * Set page size (expands bottom margin)...
701 cupsWritePrintData("\033(S\010\000", 5);
703 i
= header
->PageSize
[0] * header
->HWResolution
[1] / 72;
709 i
= header
->PageSize
[1] * header
->HWResolution
[1] / 72;
717 cupsWritePrintData("\033(C\002\000", 5);
718 putchar(PrinterLength
& 255);
719 putchar(PrinterLength
>> 8);
723 * Set the top and bottom margins...
726 PrinterTop
= (int)((ppd
->sizes
[1].length
- ppd
->sizes
[1].top
) *
727 header
->HWResolution
[1] / 72.0);
729 if (ppd
->model_number
& ESCP_EXT_MARGINS
)
731 cupsWritePrintData("\033(c\010\000", 5);
734 putchar(PrinterTop
>> 8);
735 putchar(PrinterTop
>> 16);
736 putchar(PrinterTop
>> 24);
738 putchar(PrinterLength
);
739 putchar(PrinterLength
>> 8);
740 putchar(PrinterLength
>> 16);
741 putchar(PrinterLength
>> 24);
745 cupsWritePrintData("\033(c\004\000", 5);
747 putchar(PrinterTop
& 255);
748 putchar(PrinterTop
>> 8);
750 putchar(PrinterLength
& 255);
751 putchar(PrinterLength
>> 8);
755 * Set the top position...
758 cupsWritePrintData("\033(V\002\000\000\000", 7);
761 * Enable unidirectional printing depending on the mode...
764 if ((attr
= cupsFindAttr(ppd
, "cupsESCPDirection", colormodel
,
765 header
->MediaType
, resolution
, spec
,
766 sizeof(spec
))) != NULL
)
767 printf("\033U%c", atoi(attr
->value
));
770 * Enable/disable microweaving as needed...
773 if ((attr
= cupsFindAttr(ppd
, "cupsESCPMicroWeave", colormodel
,
774 header
->MediaType
, resolution
, spec
,
775 sizeof(spec
))) != NULL
)
776 printf("\033(i\001%c%c", 0, atoi(attr
->value
));
779 * Set the dot size and print speed as needed...
782 if ((attr
= cupsFindAttr(ppd
, "cupsESCPDotSize", colormodel
,
783 header
->MediaType
, resolution
, spec
,
784 sizeof(spec
))) != NULL
)
785 printf("\033(e\002%c%c%c", 0, 0, atoi(attr
->value
));
787 if (ppd
->model_number
& ESCP_ESCK
)
790 * Set the print mode...
793 if (PrinterPlanes
== 1)
796 * Fast black printing.
799 cupsWritePrintData("\033(K\002\000\000\001", 7);
807 cupsWritePrintData("\033(K\002\000\000\002", 7);
812 * Get softweave settings from header...
815 if (header
->cupsRowCount
<= 1)
824 DotRowCount
= header
->cupsRowCount
;
825 DotRowFeed
= header
->cupsRowFeed
;
826 DotRowStep
= header
->cupsRowStep
% 100;
827 DotColStep
= header
->cupsRowStep
/ 100;
834 * Setup softweave parameters...
838 DotRowMax
= DotRowCount
* DotRowStep
;
839 DotBufferSize
= (header
->cupsWidth
/ DotColStep
* BitPlanes
+ 7) / 8;
841 fprintf(stderr
, "DEBUG: DotBufferSize = %d\n", DotBufferSize
);
842 fprintf(stderr
, "DEBUG: DotColStep = %d\n", DotColStep
);
843 fprintf(stderr
, "DEBUG: DotRowMax = %d\n", DotRowMax
);
844 fprintf(stderr
, "DEBUG: DotRowStep = %d\n", DotRowStep
);
845 fprintf(stderr
, "DEBUG: DotRowFeed = %d\n", DotRowFeed
);
846 fprintf(stderr
, "DEBUG: DotRowCount = %d\n", DotRowCount
);
850 DotBuffers
[0] = NULL
;
852 fprintf(stderr
, "DEBUG: model_number = %x\n", ppd
->model_number
);
857 * Compute offsets for the color jets on the print head...
860 bands
= DotRowStep
* DotColStep
* PrinterPlanes
* 4;
862 memset(DotRowOffset
, 0, sizeof(DotRowOffset
));
864 if (PrinterPlanes
== 1)
867 * Use full height of print head...
870 if ((attr
= ppdFindAttr(ppd
, "cupsESCPBlack", resolution
)) != NULL
&&
874 * Use custom black head data...
877 sscanf(attr
->value
, "%d%d", &DotRowCount
, &DotRowStep
);
880 else if (ppd
->model_number
& ESCP_STAGGER
)
883 * Use staggered print head...
886 fputs("DEBUG: Offset head detected...\n", stderr
);
888 if ((attr
= ppdFindAttr(ppd
, "cupsESCPOffsets", resolution
)) != NULL
&&
892 * Use only 1/3 of the print head when printing color...
895 sscanf(attr
->value
, "%d%d%d%d", DotRowOffset
+ 0,
896 DotRowOffset
+ 1, DotRowOffset
+ 2, DotRowOffset
+ 3);
900 for (i
= 0; i
< PrinterPlanes
; i
++)
901 fprintf(stderr
, "DEBUG: DotRowOffset[%d] = %d\n", i
, DotRowOffset
[i
]);
907 for (i
= 0; i
< bands
; i
++)
909 band
= (cups_weave_t
*)calloc(1, sizeof(cups_weave_t
));
910 band
->next
= DotAvailList
;
913 band
->buffer
= calloc(DotRowCount
, DotBufferSize
);
918 fputs("ERROR: Unable to allocate band list!\n", stderr
);
922 fputs("DEBUG: Pointer list at start of page...\n", stderr
);
924 for (band
= DotAvailList
; band
!= NULL
; band
= band
->next
)
925 fprintf(stderr
, "DEBUG: %p\n", band
);
927 fputs("DEBUG: ----END----\n", stderr
);
930 * Fill the initial bands...
933 modrow
= DotColStep
* DotRowStep
;
938 * Automatically compute the optimal feed value...
941 DotRowFeed
= DotRowCount
/ DotColStep
- DotRowStep
;
943 while ((((DotRowFeed
% 2) == 0) == ((DotRowCount
% 2) == 0) ||
944 ((DotRowFeed
% 3) == 0) == ((DotRowCount
% 3) == 0) ||
945 ((DotRowFeed
% 5) == 0) == ((DotRowCount
% 5) == 0)) &&
952 fprintf(stderr
, "DEBUG: Auto DotRowFeed = %d, modrow=%d...\n",
956 memset(DotBands
, 0, sizeof(DotBands
));
958 for (i
= modrow
, subrow
= modrow
- 1, y
= DotRowFeed
;
960 i
--, y
+= DotRowFeed
)
962 while (DotBands
[subrow
][0])
965 * This subrow is already used, move to another one...
968 subrow
= (subrow
+ 1) % modrow
;
971 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
974 * Pull the next available band from the list...
978 DotAvailList
= DotAvailList
->next
;
979 DotBands
[subrow
][plane
] = band
;
982 * Start the band in the first few passes, with the number of rows
983 * varying to allow for a nice interleaved pattern...
986 band
->x
= subrow
/ DotRowStep
;
987 band
->y
= (subrow
% DotRowStep
) + DotRowOffset
[plane
];
990 band
->count
= DotRowCount
- y
/ DotRowStep
;
994 else if (band
->count
> DotRowCount
)
995 band
->count
= DotRowCount
;
997 fprintf(stderr
, "DEBUG: DotBands[%d][%d] = %p, x = %d, y = %d, plane = %d, count = %d\n",
998 subrow
, plane
, band
, band
->x
, band
->y
, band
->plane
, band
->count
);
1001 subrow
= (subrow
+ DotRowFeed
) % modrow
;
1007 * Allocate memory for a single line of graphics...
1010 ptr
= calloc(PrinterPlanes
, DotBufferSize
);
1012 for (plane
= 0; plane
< PrinterPlanes
; plane
++, ptr
+= DotBufferSize
)
1013 DotBuffers
[plane
] = ptr
;
1017 * Set the output resolution...
1020 cupsWritePrintData("\033(D\004\000", 5);
1022 putchar(units
>> 8);
1023 putchar(units
* DotRowStep
/ header
->HWResolution
[1]);
1024 putchar(units
* DotColStep
/ header
->HWResolution
[0]);
1027 * Set the top of form...
1033 * Allocate buffers as needed...
1036 PixelBuffer
= malloc(header
->cupsBytesPerLine
);
1037 InputBuffer
= malloc(header
->cupsWidth
* PrinterPlanes
* 2);
1038 OutputBuffers
[0] = malloc(PrinterPlanes
* header
->cupsWidth
);
1040 for (i
= 1; i
< PrinterPlanes
; i
++)
1041 OutputBuffers
[i
] = OutputBuffers
[0] + i
* header
->cupsWidth
;
1044 CMYKBuffer
= malloc(header
->cupsWidth
* PrinterPlanes
);
1046 CompBuffer
= malloc(10 * DotBufferSize
* DotRowMax
);
1051 * 'EndPage()' - Finish a page of graphics.
1055 EndPage(ppd_file_t
*ppd
, /* I - PPD file */
1056 cups_page_header2_t
*header
) /* I - Page header */
1058 int i
; /* Looping var */
1059 cups_weave_t
*band
, /* Current band */
1060 *next
; /* Next band in list */
1061 int plane
; /* Current plane */
1062 int subrow
; /* Current subrow */
1063 int subrows
; /* Number of subrows */
1067 * Output the last bands of print data as necessary...
1073 * Move the remaining bands to the used or avail lists...
1076 subrows
= DotRowStep
* DotColStep
;
1078 for (subrow
= 0; subrow
< subrows
; subrow
++)
1079 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
1081 if (DotBands
[subrow
][plane
]->dirty
)
1084 * Insert into the used list...
1087 DotBands
[subrow
][plane
]->count
= DotBands
[subrow
][plane
]->row
;
1089 AddBand(DotBands
[subrow
][plane
]);
1094 * Nothing here, so move it to the available list...
1097 DotBands
[subrow
][plane
]->next
= DotAvailList
;
1098 DotAvailList
= DotBands
[subrow
][plane
];
1101 DotBands
[subrow
][plane
] = NULL
;
1105 * Loop until all bands are written...
1108 fputs("DEBUG: Pointer list at end of page...\n", stderr
);
1110 for (band
= DotUsedList
; band
!= NULL
; band
= band
->next
)
1111 fprintf(stderr
, "DEBUG: %p (used)\n", band
);
1112 for (band
= DotAvailList
; band
!= NULL
; band
= band
->next
)
1113 fprintf(stderr
, "DEBUG: %p (avail)\n", band
);
1115 fputs("DEBUG: ----END----\n", stderr
);
1117 for (band
= DotUsedList
; band
!= NULL
; band
= next
)
1121 OutputBand(ppd
, header
, band
);
1123 fprintf(stderr
, "DEBUG: freeing used band %p, prev = %p, next = %p\n",
1124 band
, band
->prev
, band
->next
);
1131 * Free memory for the available bands, if any...
1134 for (band
= DotAvailList
; band
!= NULL
; band
= next
)
1138 fprintf(stderr
, "DEBUG: freeing avail band %p, prev = %p, next = %p\n",
1139 band
, band
->prev
, band
->next
);
1146 free(DotBuffers
[0]);
1149 * Output a page eject sequence...
1155 * Free memory for the page...
1158 for (i
= 0; i
< PrinterPlanes
; i
++)
1160 cupsDitherDelete(DitherStates
[i
]);
1161 cupsLutDelete(DitherLuts
[i
]);
1164 free(OutputBuffers
[0]);
1170 cupsCMYKDelete(CMYK
);
1181 * 'Shutdown()' - Shutdown a printer.
1185 Shutdown(ppd_file_t
*ppd
) /* I - PPD file */
1188 * Reset the printer...
1193 if (ppd
->model_number
& ESCP_REMOTE
)
1196 * Go into remote mode...
1199 cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
1205 cupsWritePrintData("LD\000\000", 4);
1208 * Exit remote mode...
1211 cupsWritePrintData("\033\000\000\000", 4);
1217 * 'AddBand()' - Add a band of data to the used list.
1221 AddBand(cups_weave_t
*band
) /* I - Band to add */
1223 cups_weave_t
*current
, /* Current band */
1224 *prev
; /* Previous band */
1227 if (band
->count
< 1)
1230 for (current
= DotUsedList
, prev
= NULL
;
1232 prev
= current
, current
= current
->next
)
1233 if (band
->y
< current
->y
||
1234 (band
->y
== current
->y
&& band
->x
< current
->x
) ||
1235 (band
->y
== current
->y
&& band
->x
== current
->x
&&
1236 band
->plane
< current
->plane
))
1239 if (current
!= NULL
)
1242 * Insert the band...
1245 band
->next
= current
;
1247 current
->prev
= band
;
1254 else if (prev
!= NULL
)
1257 * Append the band to the end...
1267 * First band in list...
1278 * 'CancelJob()' - Cancel the current job...
1282 CancelJob(int sig
) /* I - Signal */
1291 * 'CompressData()' - Compress a line of graphics.
1295 CompressData(ppd_file_t
*ppd
, /* I - PPD file information */
1296 const unsigned char *line
, /* I - Data to compress */
1297 const int length
,/* I - Number of bytes */
1298 int plane
, /* I - Color plane */
1299 int type
, /* I - Type of compression */
1300 const int rows
, /* I - Number of lines to write */
1301 const int xstep
, /* I - Spacing between columns */
1302 const int ystep
, /* I - Spacing between lines */
1303 const int offset
)/* I - Head offset */
1305 register const unsigned char *line_ptr
,
1306 /* Current byte pointer */
1307 *line_end
, /* End-of-line byte pointer */
1308 *start
; /* Start of compression sequence */
1309 register unsigned char *comp_ptr
; /* Pointer into compression buffer */
1310 register int count
; /* Count of bytes for output */
1311 register int bytes
; /* Number of bytes per row */
1312 static int ctable
[7][7] = /* Colors */
1314 { 0, 0, 0, 0, 0, 0, 0 }, /* K */
1315 { 0, 16, 0, 0, 0, 0, 0 }, /* Kk */
1316 { 2, 1, 4, 0, 0, 0, 0 }, /* CMY */
1317 { 2, 1, 4, 0, 0, 0, 0 }, /* CMYK */
1318 { 0, 0, 0, 0, 0, 0, 0 },
1319 { 2, 18, 1, 17, 4, 0, 0 }, /* CcMmYK */
1320 { 2, 18, 1, 17, 4, 0, 16 }, /* CcMmYKk */
1328 * Do no compression...
1331 line_ptr
= (const unsigned char *)line
;
1332 line_end
= (const unsigned char *)line
+ length
;
1337 * Do TIFF pack-bits encoding...
1340 line_ptr
= (const unsigned char *)line
;
1341 line_end
= (const unsigned char *)line
+ length
;
1342 comp_ptr
= CompBuffer
;
1344 while (line_ptr
< line_end
&& (comp_ptr
- CompBuffer
) < length
)
1346 if ((line_ptr
+ 1) >= line_end
)
1349 * Single byte on the end...
1353 *comp_ptr
++ = *line_ptr
++;
1355 else if (line_ptr
[0] == line_ptr
[1])
1358 * Repeated sequence...
1364 while (line_ptr
< (line_end
- 1) &&
1365 line_ptr
[0] == line_ptr
[1] &&
1372 *comp_ptr
++ = 257 - count
;
1373 *comp_ptr
++ = *line_ptr
++;
1378 * Non-repeated sequence...
1385 while (line_ptr
< (line_end
- 1) &&
1386 line_ptr
[0] != line_ptr
[1] &&
1393 *comp_ptr
++ = count
- 1;
1395 memcpy(comp_ptr
, start
, count
);
1400 if ((comp_ptr
- CompBuffer
) < length
)
1402 line_ptr
= (const unsigned char *)CompBuffer
;
1403 line_end
= (const unsigned char *)comp_ptr
;
1408 line_ptr
= (const unsigned char *)line
;
1409 line_end
= (const unsigned char *)line
+ length
;
1415 * Position the print head...
1423 cupsWritePrintData("\033(\\\004\000\240\005", 7);
1428 putchar(offset
>> 8);
1432 * Send the graphics...
1435 bytes
= length
/ rows
;
1437 if (ppd
->model_number
& ESCP_RASTER_ESCI
)
1440 * Send graphics with ESC i command.
1444 putchar(ctable
[PrinterPlanes
- 1][plane
]);
1447 putchar(bytes
& 255);
1448 putchar(bytes
>> 8);
1449 putchar(rows
& 255);
1455 * Set the color if necessary...
1458 if (PrinterPlanes
> 1)
1460 plane
= ctable
[PrinterPlanes
- 1][plane
];
1463 printf("\033(r%c%c%c%c", 2, 0, 1, plane
& 0x0f);
1465 printf("\033r%c", plane
);
1469 * Send graphics with ESC . command.
1479 putchar(bytes
& 255);
1480 putchar(bytes
>> 8);
1483 cupsWritePrintData(line_ptr
, line_end
- line_ptr
);
1488 * 'OutputBand()' - Output a band of graphics.
1492 OutputBand(ppd_file_t
*ppd
, /* I - PPD file */
1493 cups_page_header2_t
*header
, /* I - Page header */
1494 cups_weave_t
*band
) /* I - Current band */
1496 int xstep
, /* Spacing between columns */
1497 ystep
; /* Spacing between rows */
1501 * Interleaved ESC/P2 graphics...
1504 OutputFeed
= band
->y
- DotRowCurrent
;
1505 DotRowCurrent
= band
->y
;
1507 fprintf(stderr
, "DEBUG: Printing band %p, x = %d, y = %d, plane = %d, count = %d, OutputFeed = %d\n",
1508 band
, band
->x
, band
->y
, band
->plane
, band
->count
, OutputFeed
);
1511 * Compute step values...
1514 xstep
= 3600 * DotColStep
/ header
->HWResolution
[0];
1515 ystep
= 3600 * DotRowStep
/ header
->HWResolution
[1];
1518 * Output the band...
1523 cupsWritePrintData("\033(v\002\000", 5);
1524 putchar(OutputFeed
& 255);
1525 putchar(OutputFeed
>> 8);
1530 CompressData(ppd
, band
->buffer
, band
->count
* DotBufferSize
, band
->plane
,
1531 header
->cupsCompression
, band
->count
, xstep
, ystep
, band
->x
);
1537 memset(band
->buffer
, 0, band
->count
* DotBufferSize
);
1541 * Flush the output buffers...
1549 * 'ProcessLine()' - Read graphics from the page stream and output as needed.
1553 ProcessLine(ppd_file_t
*ppd
, /* I - PPD file */
1554 cups_raster_t
*ras
, /* I - Raster stream */
1555 cups_page_header2_t
*header
, /* I - Page header */
1556 const int y
) /* I - Current scanline */
1558 int plane
, /* Current color plane */
1559 width
, /* Width of line */
1560 subwidth
, /* Width of interleaved row */
1561 subrow
, /* Subrow for interleaved output */
1562 offset
, /* Offset to current line */
1563 pass
, /* Pass number */
1564 xstep
, /* X step value */
1565 ystep
; /* Y step value */
1566 cups_weave_t
*band
; /* Current band */
1570 * Read a row of graphics...
1573 if (!cupsRasterReadPixels(ras
, PixelBuffer
, header
->cupsBytesPerLine
))
1577 * Perform the color separation...
1580 width
= header
->cupsWidth
;
1581 subwidth
= header
->cupsWidth
/ DotColStep
;
1582 xstep
= 3600 / header
->HWResolution
[0];
1583 ystep
= 3600 / header
->HWResolution
[1];
1585 switch (header
->cupsColorSpace
)
1587 case CUPS_CSPACE_W
:
1590 cupsRGBDoGray(RGB
, PixelBuffer
, CMYKBuffer
, width
);
1591 cupsCMYKDoCMYK(CMYK
, CMYKBuffer
, InputBuffer
, width
);
1594 cupsCMYKDoGray(CMYK
, PixelBuffer
, InputBuffer
, width
);
1597 case CUPS_CSPACE_K
:
1598 cupsCMYKDoBlack(CMYK
, PixelBuffer
, InputBuffer
, width
);
1602 case CUPS_CSPACE_RGB
:
1605 cupsRGBDoRGB(RGB
, PixelBuffer
, CMYKBuffer
, width
);
1606 cupsCMYKDoCMYK(CMYK
, CMYKBuffer
, InputBuffer
, width
);
1609 cupsCMYKDoRGB(CMYK
, PixelBuffer
, InputBuffer
, width
);
1612 case CUPS_CSPACE_CMYK
:
1613 cupsCMYKDoCMYK(CMYK
, PixelBuffer
, InputBuffer
, width
);
1618 * Dither the pixels...
1621 for (plane
= 0; plane
< PrinterPlanes
; plane
++)
1623 cupsDitherLine(DitherStates
[plane
], DitherLuts
[plane
], InputBuffer
+ plane
,
1624 PrinterPlanes
, OutputBuffers
[plane
]);
1629 * Handle microweaved output...
1632 if (cupsCheckBytes(OutputBuffers
[plane
], width
))
1636 cupsPackHorizontal(OutputBuffers
[plane
], DotBuffers
[plane
],
1639 cupsPackHorizontal2(OutputBuffers
[plane
], DotBuffers
[plane
],
1644 cupsWritePrintData("\033(v\002\000", 5);
1645 putchar(OutputFeed
& 255);
1646 putchar(OutputFeed
>> 8);
1650 CompressData(ppd
, DotBuffers
[plane
], DotBufferSize
, plane
, 1, 1,
1657 * Handle softweaved output...
1660 for (pass
= 0, subrow
= y
% DotRowStep
;
1662 pass
++, subrow
+= DotRowStep
)
1665 * See if we need to output the band...
1668 band
= DotBands
[subrow
][plane
];
1669 offset
= band
->row
* DotBufferSize
;
1672 cupsPackHorizontal(OutputBuffers
[plane
] + pass
,
1673 band
->buffer
+ offset
, subwidth
, 0, DotColStep
);
1675 cupsPackHorizontal2(OutputBuffers
[plane
] + pass
,
1676 band
->buffer
+ offset
, subwidth
, DotColStep
);
1679 band
->dirty
|= !cupsCheckBytes(band
->buffer
+ offset
, DotBufferSize
);
1680 if (band
->row
>= band
->count
)
1685 * Dirty band needs to be added to the used list...
1691 * Then find a new band...
1694 if (DotAvailList
== NULL
)
1696 OutputBand(ppd
, header
, DotUsedList
);
1698 DotBands
[subrow
][plane
] = DotUsedList
;
1699 DotUsedList
->x
= band
->x
;
1700 DotUsedList
->y
= band
->y
+ band
->count
* DotRowStep
;
1701 DotUsedList
->plane
= band
->plane
;
1702 DotUsedList
->row
= 0;
1703 DotUsedList
->count
= DotRowCount
;
1704 DotUsedList
= DotUsedList
->next
;
1708 DotBands
[subrow
][plane
] = DotAvailList
;
1709 DotAvailList
->x
= band
->x
;
1710 DotAvailList
->y
= band
->y
+ band
->count
* DotRowStep
;
1711 DotAvailList
->plane
= band
->plane
;
1712 DotAvailList
->row
= 0;
1713 DotAvailList
->count
= DotRowCount
;
1714 DotAvailList
= DotAvailList
->next
;
1720 * This band isn't dirty, so reuse it...
1723 fprintf(stderr
, "DEBUG: Blank band %p, x = %d, y = %d, plane = %d, count = %d\n",
1724 band
, band
->x
, band
->y
, band
->plane
, band
->count
);
1726 band
->y
+= band
->count
* DotRowStep
;
1728 band
->count
= DotRowCount
;
1741 * 'main()' - Main entry and processing of driver.
1744 int /* O - Exit status */
1745 main(int argc
, /* I - Number of command-line arguments */
1746 char *argv
[]) /* I - Command-line arguments */
1748 int fd
; /* File descriptor */
1749 cups_raster_t
*ras
; /* Raster stream for printing */
1750 cups_page_header2_t header
; /* Page header from file */
1751 int page
; /* Current page */
1752 int y
; /* Current line */
1753 ppd_file_t
*ppd
; /* PPD file */
1754 int num_options
; /* Number of options */
1755 cups_option_t
*options
; /* Options */
1756 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1757 struct sigaction action
; /* Actions for POSIX signals */
1758 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1762 * Make sure status messages are not buffered...
1765 setbuf(stderr
, NULL
);
1768 * Check command-line...
1771 if (argc
< 6 || argc
> 7)
1773 fputs("ERROR: rastertoescpx job-id user title copies options [file]\n", stderr
);
1777 num_options
= cupsParseOptions(argv
[5], 0, &options
);
1780 * Open the PPD file...
1783 ppd
= ppdOpenFile(getenv("PPD"));
1787 fputs("ERROR: Unable to open PPD file!\n", stderr
);
1791 ppdMarkDefaults(ppd
);
1792 cupsMarkOptions(ppd
, num_options
, options
);
1795 * Open the page stream...
1800 if ((fd
= open(argv
[6], O_RDONLY
)) == -1)
1802 perror("ERROR: Unable to open raster file - ");
1809 ras
= cupsRasterOpen(fd
, CUPS_RASTER_READ
);
1812 * Register a signal handler to eject the current page if the
1818 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1819 sigset(SIGTERM
, CancelJob
);
1820 #elif defined(HAVE_SIGACTION)
1821 memset(&action
, 0, sizeof(action
));
1823 sigemptyset(&action
.sa_mask
);
1824 action
.sa_handler
= CancelJob
;
1825 sigaction(SIGTERM
, &action
, NULL
);
1827 signal(SIGTERM
, CancelJob
);
1828 #endif /* HAVE_SIGSET */
1831 * Initialize the print device...
1837 * Process pages as needed...
1842 while (cupsRasterReadHeader2(ras
, &header
))
1845 * Write a status message with the page number and number of copies.
1853 fprintf(stderr
, "PAGE: %d 1\n", page
);
1854 fprintf(stderr
, "INFO: Starting page %d...\n", page
);
1856 StartPage(ppd
, &header
);
1858 for (y
= 0; y
< header
.cupsHeight
; y
++)
1861 * Let the user know how far we have progressed...
1868 fprintf(stderr
, "INFO: Printing page %d, %d%% complete...\n", page
,
1869 100 * y
/ header
.cupsHeight
);
1872 * Read and write a line of graphics or whitespace...
1875 ProcessLine(ppd
, ras
, &header
, y
);
1882 fprintf(stderr
, "INFO: Finished page %d...\n", page
);
1884 EndPage(ppd
, &header
);
1892 cupsFreeOptions(num_options
, options
);
1894 cupsRasterClose(ras
);
1901 fputs("ERROR: No pages found!\n", stderr
);
1906 fputs("INFO: Ready to print.\n", stderr
);