• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *   Advanced EPSON ESC/P raster driver for CUPS.
3  *
4  *   Copyright 2007-2011 by Apple Inc.
5  *   Copyright 1993-2005 by Easy Software Products.
6  *
7  *   These coded instructions, statements, and computer programs are the
8  *   property of Apple Inc. and are protected by Federal copyright
9  *   law.  Distribution and use rights are outlined in the file "COPYING"
10  *   which should have been included with this file.
11  *
12  * Contents:
13  *
14  *   Setup()           - Prepare the printer for graphics output.
15  *   StartPage()       - Start a page of graphics.
16  *   EndPage()         - Finish a page of graphics.
17  *   Shutdown()        - Shutdown a printer.
18  *   CancelJob()       - Cancel the current job...
19  *   CompressData()    - Compress a line of graphics.
20  *   OutputBand()      - Output a band of graphics.
21  *   ProcessLine()     - Read graphics from the page stream and output
22  *                       as needed.
23  *   main()            - Main entry and processing of driver.
24  */
25 
26 /*
27  * Include necessary headers...
28  */
29 
30 #include <cupsfilters/driver.h>
31 #include "escp.h"
32 #include <signal.h>
33 #include <string.h>
34 #include <ctype.h>
35 
36 
37 /*
38  * Softweave data...
39  */
40 
41 typedef struct cups_weave_str
42 {
43   struct cups_weave_str	*prev,			/* Previous band */
44 			*next;			/* Next band */
45   int			x, y,			/* Column/Line on the page */
46 			plane,			/* Color plane */
47 			dirty,			/* Is this buffer dirty? */
48 			row,			/* Row in the buffer */
49 			count;			/* Max rows this pass */
50   unsigned char		*buffer;		/* Data buffer */
51 } cups_weave_t;
52 
53 
54 /*
55  * Globals...
56  */
57 
58 cups_rgb_t	*RGB;			/* RGB color separation data */
59 cups_cmyk_t	*CMYK;			/* CMYK color separation data */
60 unsigned char	*PixelBuffer,		/* Pixel buffer */
61 		*CMYKBuffer,		/* CMYK buffer */
62 		*OutputBuffers[7],	/* Output buffers */
63 		*DotBuffers[7],		/* Dot buffers */
64 		*CompBuffer;		/* Compression buffer */
65 short		*InputBuffer;		/* Color separation buffer */
66 cups_weave_t	*DotAvailList,		/* Available buffers */
67 		*DotUsedList,		/* Used buffers */
68 		*DotBands[128][7];	/* Buffers in use */
69 int		DotBufferSize,		/* Size of dot buffers */
70 		DotRowMax,		/* Maximum row number in buffer */
71 		DotColStep,		/* Step for each output column */
72 		DotRowStep,		/* Step for each output line */
73 		DotRowFeed,		/* Amount to feed for interleave */
74 		DotRowCount,		/* Number of rows to output */
75 		DotRowOffset[7],	/* Offset for each color on print head */
76 		DotRowCurrent,		/* Current row */
77 		DotSize;		/* Dot size (Pro 5000 only) */
78 int		PrinterPlanes,		/* # of color planes */
79 		BitPlanes,		/* # of bit planes per color */
80 		PrinterTop,		/* Top of page */
81 		PrinterLength;		/* Length of page */
82 cups_lut_t	*DitherLuts[7];		/* Lookup tables for dithering */
83 cups_dither_t	*DitherStates[7];	/* Dither state tables */
84 int		OutputFeed;		/* Number of lines to skip */
85 int		Canceled;		/* Is the job canceled? */
86 
87 
88 /*
89  * Prototypes...
90  */
91 
92 void	Setup(ppd_file_t *);
93 void	StartPage(ppd_file_t *, cups_page_header2_t *);
94 void	EndPage(ppd_file_t *, cups_page_header2_t *);
95 void	Shutdown(ppd_file_t *);
96 
97 void	AddBand(cups_weave_t *band);
98 void	CancelJob(int sig);
99 void	CompressData(ppd_file_t *, const unsigned char *, const int,
100 	             int, int, const int, const int, const int,
101 		     const int);
102 void	OutputBand(ppd_file_t *, cups_page_header2_t *,
103 	           cups_weave_t *band);
104 void	ProcessLine(ppd_file_t *, cups_raster_t *,
105 	            cups_page_header2_t *, const int y);
106 
107 
108 /*
109  * 'Setup()' - Prepare a printer for graphics output.
110  */
111 
112 void
Setup(ppd_file_t * ppd)113 Setup(ppd_file_t *ppd)		/* I - PPD file */
114 {
115  /*
116   * Some EPSON printers need an additional command issued at the
117   * beginning of each job to exit from USB "packet" mode...
118   */
119 
120   if (ppd->model_number & ESCP_USB)
121     cupsWritePrintData("\000\000\000\033\001@EJL 1284.4\n@EJL     \n\033@", 29);
122 }
123 
124 
125 /*
126  * 'StartPage()' - Start a page of graphics.
127  */
128 
129 void
StartPage(ppd_file_t * ppd,cups_page_header2_t * header)130 StartPage(ppd_file_t         *ppd,	/* I - PPD file */
131           cups_page_header2_t *header)	/* I - Page header */
132 {
133   int		i, y;			/* Looping vars */
134   int		subrow,			/* Current subrow */
135 		modrow,			/* Subrow modulus */
136 		plane;			/* Current color plane */
137   unsigned char	*ptr;			/* Pointer into dot buffer */
138   int		bands;			/* Number of bands to allocate */
139   int		units;			/* Units for resolution */
140   cups_weave_t	*band;			/* Current band */
141   const char	*colormodel;		/* Color model string */
142   char		resolution[PPD_MAX_NAME],
143 					/* Resolution string */
144 		spec[PPD_MAX_NAME];	/* PPD attribute name */
145   ppd_attr_t	*attr;			/* Attribute from PPD file */
146   const float	default_lut[2] =	/* Default dithering lookup table */
147 		{
148 		  0.0,
149 		  1.0
150 		};
151 
152 
153   fprintf(stderr, "DEBUG: StartPage...\n");
154   fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass);
155   fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor);
156   fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType);
157   fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType);
158 
159   fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance);
160   fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia);
161   fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate);
162   fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia);
163   fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
164   fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0],
165           header->HWResolution[1]);
166   fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
167           header->ImagingBoundingBox[0], header->ImagingBoundingBox[1],
168           header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
169   fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet);
170   fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog);
171   fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge);
172   fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0],
173           header->Margins[1]);
174   fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
175   fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
176   fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight);
177   fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint);
178   fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint);
179   fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
180   fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
181   fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp);
182   fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0],
183           header->PageSize[1]);
184   fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations);
185   fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch);
186   fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble);
187   fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
188   fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
189   fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
190   fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
191   fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
192   fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
193   fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
194   fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
195   fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
196   fprintf(stderr, "DEBUG: cupsRowCount = %d\n", header->cupsRowCount);
197   fprintf(stderr, "DEBUG: cupsRowFeed = %d\n", header->cupsRowFeed);
198   fprintf(stderr, "DEBUG: cupsRowStep = %d\n", header->cupsRowStep);
199 
200  /*
201   * Figure out the color model and spec strings...
202   */
203 
204   switch (header->cupsColorSpace)
205   {
206     case CUPS_CSPACE_K :
207         colormodel = "Black";
208 	break;
209     case CUPS_CSPACE_W :
210         colormodel = "Gray";
211 	break;
212     default :
213     case CUPS_CSPACE_RGB :
214         colormodel = "RGB";
215 	break;
216     case CUPS_CSPACE_CMYK :
217         colormodel = "CMYK";
218 	break;
219   }
220 
221   if (header->HWResolution[0] != header->HWResolution[1])
222     snprintf(resolution, sizeof(resolution), "%dx%ddpi",
223              header->HWResolution[0], header->HWResolution[1]);
224   else
225     snprintf(resolution, sizeof(resolution), "%ddpi",
226              header->HWResolution[0]);
227 
228   if (!header->MediaType[0])
229     strcpy(header->MediaType, "Plain");
230 
231  /*
232   * Load the appropriate color profiles...
233   */
234 
235   RGB  = NULL;
236   CMYK = NULL;
237 
238   fputs("DEBUG: Attempting to load color profiles using the following values:\n", stderr);
239   fprintf(stderr, "DEBUG: ColorModel = %s\n", colormodel);
240   fprintf(stderr, "DEBUG: MediaType = %s\n", header->MediaType);
241   fprintf(stderr, "DEBUG: Resolution = %s\n", resolution);
242 
243   if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
244       header->cupsColorSpace == CUPS_CSPACE_W)
245     RGB = cupsRGBLoad(ppd, colormodel, header->MediaType, resolution);
246   else
247     RGB = NULL;
248 
249   CMYK = cupsCMYKLoad(ppd, colormodel, header->MediaType, resolution);
250 
251   if (RGB)
252     fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr);
253 
254   if (CMYK)
255     fputs("DEBUG: Loaded CMYK separation from PPD.\n", stderr);
256   else
257   {
258     fputs("DEBUG: Loading default CMYK separation.\n", stderr);
259     CMYK = cupsCMYKNew(4);
260   }
261 
262   PrinterPlanes = CMYK->num_channels;
263 
264   fprintf(stderr, "DEBUG: PrinterPlanes = %d\n", PrinterPlanes);
265 
266  /*
267   * Get the dithering parameters...
268   */
269 
270   switch (PrinterPlanes)
271   {
272     case 1 : /* K */
273         DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
274 	                            resolution, "Black");
275         break;
276 
277     case 2 : /* Kk */
278         DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
279 	                            resolution, "Black");
280         DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
281 	                            resolution, "LightBlack");
282         break;
283 
284     case 3 : /* CMY */
285         DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
286 	                            resolution, "Cyan");
287         DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
288 	                            resolution, "Magenta");
289         DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
290 	                            resolution, "Yellow");
291         break;
292 
293     case 4 : /* CMYK */
294         DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
295 	                            resolution, "Cyan");
296         DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
297 	                            resolution, "Magenta");
298         DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
299 	                            resolution, "Yellow");
300         DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
301 	                            resolution, "Black");
302         break;
303 
304     case 6 : /* CcMmYK */
305         DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
306 	                            resolution, "Cyan");
307         DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
308 	                            resolution, "LightCyan");
309         DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
310 	                            resolution, "Magenta");
311         DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
312 	                            resolution, "LightMagenta");
313         DitherLuts[4] = cupsLutLoad(ppd, colormodel, header->MediaType,
314 	                            resolution, "Yellow");
315         DitherLuts[5] = cupsLutLoad(ppd, colormodel, header->MediaType,
316 	                            resolution, "Black");
317         break;
318 
319     case 7 : /* CcMmYKk */
320         DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
321 	                            resolution, "Cyan");
322         DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
323 	                            resolution, "LightCyan");
324         DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
325 	                            resolution, "Magenta");
326         DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
327 	                            resolution, "LightMagenta");
328         DitherLuts[4] = cupsLutLoad(ppd, colormodel, header->MediaType,
329 	                            resolution, "Yellow");
330         DitherLuts[5] = cupsLutLoad(ppd, colormodel, header->MediaType,
331 	                            resolution, "Black");
332         DitherLuts[6] = cupsLutLoad(ppd, colormodel, header->MediaType,
333 	                            resolution, "LightBlack");
334         break;
335   }
336 
337   for (plane = 0; plane < PrinterPlanes; plane ++)
338   {
339     DitherStates[plane] = cupsDitherNew(header->cupsWidth);
340 
341     if (!DitherLuts[plane])
342       DitherLuts[plane] = cupsLutNew(2, default_lut);
343   }
344 
345   if (DitherLuts[0][4095].pixel > 1)
346     BitPlanes = 2;
347   else
348     BitPlanes = 1;
349 
350  /*
351   * Initialize the printer...
352   */
353 
354   printf("\033@");
355 
356   if (ppd->model_number & ESCP_REMOTE)
357   {
358    /*
359     * Go into remote mode...
360     */
361 
362     cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
363 
364    /*
365     * Disable status reporting...
366     */
367 
368     cupsWritePrintData("ST\002\000\000\000", 6);
369 
370    /*
371     * Enable borderless printing...
372     */
373 
374     if ((attr = ppdFindAttr(ppd, "cupsESCPFP", NULL)) != NULL && attr->value)
375     {
376      /*
377       * Set horizontal offset...
378       */
379 
380       i = atoi(attr->value);
381 
382       cupsWritePrintData("FP\003\000\000", 5);
383       putchar(i & 255);
384       putchar(i >> 8);
385     }
386 
387    /*
388     * Set media type...
389     */
390 
391     if (header->cupsMediaType)
392     {
393       sprintf(spec, "%d", header->cupsMediaType);
394 
395       if ((attr = ppdFindAttr(ppd, "cupsESCPSN0", spec)) != NULL && attr->value)
396       {
397        /*
398         * Set feed sequence...
399 	*/
400 
401 	cupsWritePrintData("SN\003\000\000\000", 6);
402 	putchar(atoi(attr->value));
403       }
404 
405       if ((attr = ppdFindAttr(ppd, "cupsESCPSN1", spec)) != NULL && attr->value)
406       {
407        /*
408         * Set platten gap...
409 	*/
410 
411 	cupsWritePrintData("SN\003\000\000\001", 6);
412 	putchar(atoi(attr->value));
413       }
414 
415       if ((attr = ppdFindAttr(ppd, "cupsESCPSN2", spec)) != NULL && attr->value)
416       {
417        /*
418         * Paper feeding/ejecting sequence...
419 	*/
420 
421 	cupsWritePrintData("SN\003\000\000\002", 6);
422 	putchar(atoi(attr->value));
423       }
424 
425       if ((attr = ppdFindAttr(ppd, "cupsESCPSN6", spec)) != NULL && attr->value)
426       {
427        /*
428         * Eject delay...
429 	*/
430 
431         cupsWritePrintData("SN\003\000\000\006", 6);
432         putchar(atoi(attr->value));
433       }
434 
435       if ((attr = ppdFindAttr(ppd, "cupsESCPMT", spec)) != NULL && attr->value)
436       {
437        /*
438         * Set media type.
439 	*/
440 
441 	cupsWritePrintData("MT\003\000\000\000", 6);
442         putchar(atoi(attr->value));
443       }
444 
445       if ((attr = ppdFindAttr(ppd, "cupsESCPPH", spec)) != NULL && attr->value)
446       {
447        /*
448         * Set paper thickness.
449         */
450 
451 	cupsWritePrintData("PH\002\000\000", 5);
452         putchar(atoi(attr->value));
453       }
454     }
455 
456     sprintf(spec, "%d", header->MediaPosition);
457 
458     if (header->MediaPosition)
459     {
460       if ((attr = ppdFindAttr(ppd, "cupsESCPPC", spec)) != NULL && attr->value)
461       {
462        /*
463 	* Paper check.
464 	*/
465 
466 	cupsWritePrintData("PC\002\000\000", 5);
467         putchar(atoi(attr->value));
468       }
469 
470       if ((attr = ppdFindAttr(ppd, "cupsESCPPP", spec)) != NULL && attr->value)
471       {
472        /*
473 	* Paper path.
474 	*/
475 
476         int a, b;
477 
478         a = b = 0;
479         sscanf(attr->value, "%d%d", &a, &b);
480 
481 	cupsWritePrintData("PP\003\000\000", 5);
482         putchar(a);
483         putchar(b);
484       }
485 
486       if ((attr = ppdFindAttr(ppd, "cupsESCPEX", spec)) != NULL && attr->value)
487       {
488        /*
489 	* Set media position.
490 	*/
491 
492 	cupsWritePrintData("EX\006\000\000\000\000\000\005", 9);
493         putchar(atoi(attr->value));
494       }
495     }
496 
497     if ((attr = ppdFindAttr(ppd, "cupsESCPMS", spec)) != NULL && attr->value)
498     {
499      /*
500       * Set media size...
501       */
502 
503       cupsWritePrintData("MS\010\000\000", 5);
504       putchar(atoi(attr->value));
505 
506       switch (header->PageSize[1])
507       {
508         case 1191 :	/* A3 */
509 	    putchar(0x01);
510 	    putchar(0x00);
511 	    putchar(0x00);
512 	    putchar(0x00);
513 	    putchar(0x00);
514 	    putchar(0x00);
515 	    break;
516 	case 1032 :	/* B4 */
517 	    putchar(0x02);
518 	    putchar(0x00);
519 	    putchar(0x00);
520 	    putchar(0x00);
521 	    putchar(0x00);
522 	    putchar(0x00);
523 	    break;
524 	case 842 :	/* A4 */
525 	    putchar(0x03);
526 	    putchar(0x00);
527 	    putchar(0x00);
528 	    putchar(0x00);
529 	    putchar(0x00);
530 	    putchar(0x00);
531 	    break;
532 	case 595 :	/* A4.Transverse */
533 	    putchar(0x03);
534 	    putchar(0x01);
535 	    putchar(0x00);
536 	    putchar(0x00);
537 	    putchar(0x00);
538 	    putchar(0x00);
539 	    break;
540 	case 729 :	/* B5 */
541 	    putchar(0x04);
542 	    putchar(0x00);
543 	    putchar(0x00);
544 	    putchar(0x00);
545 	    putchar(0x00);
546 	    putchar(0x00);
547 	    break;
548 	case 516 :	/* B5.Transverse */
549 	    putchar(0x04);
550 	    putchar(0x01);
551 	    putchar(0x00);
552 	    putchar(0x00);
553 	    putchar(0x00);
554 	    putchar(0x00);
555 	    break;
556 	case 1369 :	/* Super A3/B */
557 	    putchar(0x20);
558 	    putchar(0x00);
559 	    putchar(0x00);
560 	    putchar(0x00);
561 	    putchar(0x00);
562 	    putchar(0x00);
563 	    break;
564 	case 792 :	/* Letter */
565 	    putchar(0x08);
566 	    putchar(0x00);
567 	    putchar(0x00);
568 	    putchar(0x00);
569 	    putchar(0x00);
570 	    putchar(0x00);
571 	    break;
572 	case 612 :	/* Letter.Transverse */
573 	    putchar(0x08);
574 	    putchar(0x01);
575 	    putchar(0x00);
576 	    putchar(0x00);
577 	    putchar(0x00);
578 	    putchar(0x00);
579 	    break;
580 	case 1004 :	/* Legal */
581 	    putchar(0x0a);
582 	    putchar(0x00);
583 	    putchar(0x00);
584 	    putchar(0x00);
585 	    putchar(0x00);
586 	    putchar(0x00);
587 	    break;
588 	case 1224 :	/* Tabloid */
589 	    putchar(0x2d);
590 	    putchar(0x00);
591 	    putchar(0x00);
592 	    putchar(0x00);
593 	    putchar(0x00);
594 	    putchar(0x00);
595 	    break;
596 	default :	/* Custom size */
597 	    putchar(0xff);
598 	    putchar(0xff);
599 	    i = 360 * header->PageSize[0] / 72;
600 	    putchar(i);
601 	    putchar(i >> 8);
602 	    i = 360 * header->PageSize[1] / 72;
603 	    putchar(i);
604 	    putchar(i >> 8);
605 	    break;
606       }
607     }
608 
609     sprintf(spec, "%d", header->CutMedia);
610 
611     if ((attr = ppdFindAttr(ppd, "cupsESCPAC", spec)) != NULL && attr->value)
612     {
613      /*
614       * Enable/disable cutter.
615       */
616 
617       cupsWritePrintData("AC\002\000\000", 5);
618       putchar(atoi(attr->value));
619 
620       if ((attr = ppdFindAttr(ppd, "cupsESCPSN80", header->MediaType)) != NULL && attr->value)
621       {
622        /*
623 	* Cutting method...
624 	*/
625 
626 	cupsWritePrintData("SN\003\000\000\200", 6);
627 	putchar(atoi(attr->value));
628       }
629 
630       if ((attr = ppdFindAttr(ppd, "cupsESCPSN81", header->MediaType)) != NULL && attr->value)
631       {
632        /*
633 	* Cutting pressure...
634 	*/
635 
636 	cupsWritePrintData("SN\003\000\000\201", 6);
637 	putchar(atoi(attr->value));
638       }
639     }
640 
641     if ((attr = ppdFindAttr(ppd, "cupsESCPCO", spec)) != NULL && attr->value)
642     {
643      /*
644       * Enable/disable cutter.
645       */
646 
647       cupsWritePrintData("CO\010\000\000\000", 6);
648       putchar(atoi(attr->value));
649       cupsWritePrintData("\000\000\000\000\000", 5);
650     }
651 
652    /*
653     * Exit remote mode...
654     */
655 
656     cupsWritePrintData("\033\000\000\000", 4);
657   }
658 
659  /*
660   * Enter graphics mode...
661   */
662 
663   cupsWritePrintData("\033(G\001\000\001", 6);
664 
665  /*
666   * Set the line feed increment...
667   */
668 
669   /* TODO: get this from the PPD file... */
670   for (units = 1440; units < header->HWResolution[0]; units *= 2);
671 
672   if (ppd->model_number & ESCP_EXT_UNITS)
673   {
674     cupsWritePrintData("\033(U\005\000", 5);
675     putchar(units / header->HWResolution[1]);
676     putchar(units / header->HWResolution[1]);
677     putchar(units / header->HWResolution[0]);
678     putchar(units);
679     putchar(units >> 8);
680   }
681   else
682   {
683     cupsWritePrintData("\033(U\001\000", 5);
684     putchar(3600 / header->HWResolution[1]);
685   }
686 
687  /*
688   * Set the page length...
689   */
690 
691   PrinterLength = header->PageSize[1] * header->HWResolution[1] / 72;
692 
693   if (ppd->model_number & ESCP_PAGE_SIZE)
694   {
695    /*
696     * Set page size (expands bottom margin)...
697     */
698 
699     cupsWritePrintData("\033(S\010\000", 5);
700 
701     i = header->PageSize[0] * header->HWResolution[1] / 72;
702     putchar(i);
703     putchar(i >> 8);
704     putchar(i >> 16);
705     putchar(i >> 24);
706 
707     i = header->PageSize[1] * header->HWResolution[1] / 72;
708     putchar(i);
709     putchar(i >> 8);
710     putchar(i >> 16);
711     putchar(i >> 24);
712   }
713   else
714   {
715     cupsWritePrintData("\033(C\002\000", 5);
716     putchar(PrinterLength & 255);
717     putchar(PrinterLength >> 8);
718   }
719 
720  /*
721   * Set the top and bottom margins...
722   */
723 
724   PrinterTop = (int)((ppd->sizes[1].length - ppd->sizes[1].top) *
725                      header->HWResolution[1] / 72.0);
726 
727   if (ppd->model_number & ESCP_EXT_MARGINS)
728   {
729     cupsWritePrintData("\033(c\010\000", 5);
730 
731     putchar(PrinterTop);
732     putchar(PrinterTop >> 8);
733     putchar(PrinterTop >> 16);
734     putchar(PrinterTop >> 24);
735 
736     putchar(PrinterLength);
737     putchar(PrinterLength >> 8);
738     putchar(PrinterLength >> 16);
739     putchar(PrinterLength >> 24);
740   }
741   else
742   {
743     cupsWritePrintData("\033(c\004\000", 5);
744 
745     putchar(PrinterTop & 255);
746     putchar(PrinterTop >> 8);
747 
748     putchar(PrinterLength & 255);
749     putchar(PrinterLength >> 8);
750   }
751 
752  /*
753   * Set the top position...
754   */
755 
756   cupsWritePrintData("\033(V\002\000\000\000", 7);
757 
758  /*
759   * Enable unidirectional printing depending on the mode...
760   */
761 
762   if ((attr = cupsFindAttr(ppd, "cupsESCPDirection", colormodel,
763                            header->MediaType, resolution, spec,
764 			   sizeof(spec))) != NULL)
765     printf("\033U%c", atoi(attr->value));
766 
767  /*
768   * Enable/disable microweaving as needed...
769   */
770 
771   if ((attr = cupsFindAttr(ppd, "cupsESCPMicroWeave", colormodel,
772                            header->MediaType, resolution, spec,
773 			   sizeof(spec))) != NULL)
774     printf("\033(i\001%c%c", 0, atoi(attr->value));
775 
776  /*
777   * Set the dot size and print speed as needed...
778   */
779 
780   if ((attr = cupsFindAttr(ppd, "cupsESCPDotSize", colormodel,
781                            header->MediaType, resolution, spec,
782 			   sizeof(spec))) != NULL)
783     printf("\033(e\002%c%c%c", 0, 0, atoi(attr->value));
784 
785   if (ppd->model_number & ESCP_ESCK)
786   {
787    /*
788     * Set the print mode...
789     */
790 
791     if (PrinterPlanes == 1)
792     {
793      /*
794       * Fast black printing.
795       */
796 
797       cupsWritePrintData("\033(K\002\000\000\001", 7);
798     }
799     else
800     {
801      /*
802       * Color printing.
803       */
804 
805       cupsWritePrintData("\033(K\002\000\000\002", 7);
806     }
807   }
808 
809  /*
810   * Get softweave settings from header...
811   */
812 
813   if (header->cupsRowCount <= 1)
814   {
815     DotRowCount = 1;
816     DotColStep  = 1;
817     DotRowStep  = 1;
818     DotRowFeed  = 1;
819   }
820   else
821   {
822     DotRowCount = header->cupsRowCount;
823     DotRowFeed  = header->cupsRowFeed;
824     DotRowStep  = header->cupsRowStep % 100;
825     DotColStep  = header->cupsRowStep / 100;
826 
827     if (DotColStep == 0)
828       DotColStep ++;
829   }
830 
831  /*
832   * Setup softweave parameters...
833   */
834 
835   DotRowCurrent = 0;
836   DotRowMax     = DotRowCount * DotRowStep;
837   DotBufferSize = (header->cupsWidth / DotColStep * BitPlanes + 7) / 8;
838 
839   fprintf(stderr, "DEBUG: DotBufferSize = %d\n", DotBufferSize);
840   fprintf(stderr, "DEBUG: DotColStep = %d\n", DotColStep);
841   fprintf(stderr, "DEBUG: DotRowMax = %d\n", DotRowMax);
842   fprintf(stderr, "DEBUG: DotRowStep = %d\n", DotRowStep);
843   fprintf(stderr, "DEBUG: DotRowFeed = %d\n", DotRowFeed);
844   fprintf(stderr, "DEBUG: DotRowCount = %d\n", DotRowCount);
845 
846   DotAvailList  = NULL;
847   DotUsedList   = NULL;
848   DotBuffers[0] = NULL;
849 
850   fprintf(stderr, "DEBUG: model_number = %x\n", ppd->model_number);
851 
852   if (DotRowMax > 1)
853   {
854    /*
855     * Compute offsets for the color jets on the print head...
856     */
857 
858     bands = DotRowStep * DotColStep * PrinterPlanes * 4;
859 
860     memset(DotRowOffset, 0, sizeof(DotRowOffset));
861 
862     if (PrinterPlanes == 1)
863     {
864      /*
865       * Use full height of print head...
866       */
867 
868       if ((attr = ppdFindAttr(ppd, "cupsESCPBlack", resolution)) != NULL &&
869           attr->value)
870       {
871        /*
872         * Use custom black head data...
873 	*/
874 
875         sscanf(attr->value, "%d%d", &DotRowCount, &DotRowStep);
876       }
877     }
878     else if (ppd->model_number & ESCP_STAGGER)
879     {
880      /*
881       * Use staggered print head...
882       */
883 
884       fputs("DEBUG: Offset head detected...\n", stderr);
885 
886       if ((attr = ppdFindAttr(ppd, "cupsESCPOffsets", resolution)) != NULL &&
887           attr->value)
888       {
889        /*
890         * Use only 1/3 of the print head when printing color...
891 	*/
892 
893         sscanf(attr->value, "%d%d%d%d", DotRowOffset + 0,
894 	       DotRowOffset + 1, DotRowOffset + 2, DotRowOffset + 3);
895       }
896     }
897 
898     for (i = 0; i < PrinterPlanes; i ++)
899       fprintf(stderr, "DEBUG: DotRowOffset[%d] = %d\n", i, DotRowOffset[i]);
900 
901    /*
902     * Allocate bands...
903     */
904 
905     for (i = 0; i < bands; i ++)
906     {
907       band         = (cups_weave_t *)calloc(1, sizeof(cups_weave_t));
908       band->next   = DotAvailList;
909       DotAvailList = band;
910 
911       band->buffer = calloc(DotRowCount, DotBufferSize);
912     }
913 
914     if (!DotAvailList)
915     {
916       fputs("ERROR: Unable to allocate band list\n", stderr);
917       exit(1);
918     }
919 
920     fputs("DEBUG: Pointer list at start of page...\n", stderr);
921 
922     for (band = DotAvailList; band != NULL; band = band->next)
923       fprintf(stderr, "DEBUG: %p\n", (void*)band);
924 
925     fputs("DEBUG: ----END----\n", stderr);
926 
927    /*
928     * Fill the initial bands...
929     */
930 
931     modrow = DotColStep * DotRowStep;
932 
933     if (DotRowFeed == 0)
934     {
935      /*
936       * Automatically compute the optimal feed value...
937       */
938 
939       DotRowFeed = DotRowCount / DotColStep - DotRowStep;
940 
941       while ((((DotRowFeed % 2) == 0) == ((DotRowCount % 2) == 0) ||
942               ((DotRowFeed % 3) == 0) == ((DotRowCount % 3) == 0) ||
943               ((DotRowFeed % 5) == 0) == ((DotRowCount % 5) == 0)) &&
944 	     DotRowFeed > 1)
945 	DotRowFeed --;
946 
947       if (DotRowFeed < 1)
948 	DotRowFeed = 1;
949 
950       fprintf(stderr, "DEBUG: Auto DotRowFeed = %d, modrow=%d...\n",
951               DotRowFeed, modrow);
952     }
953 
954     memset(DotBands, 0, sizeof(DotBands));
955 
956     for (i = modrow, subrow = modrow - 1, y = DotRowFeed;
957 	 i > 0;
958 	 i --, y += DotRowFeed)
959     {
960       while (DotBands[subrow][0])
961       {
962        /*
963         * This subrow is already used, move to another one...
964 	*/
965 
966 	subrow = (subrow + 1) % modrow;
967       }
968 
969       for (plane = 0; plane < PrinterPlanes; plane ++)
970       {
971        /*
972         * Pull the next available band from the list...
973 	*/
974 
975         band                    = DotAvailList;
976 	DotAvailList            = DotAvailList->next;
977 	DotBands[subrow][plane] = band;
978 
979        /*
980         * Start the band in the first few passes, with the number of rows
981 	* varying to allow for a nice interleaved pattern...
982 	*/
983 
984         band->x     = subrow / DotRowStep;
985         band->y     = (subrow % DotRowStep) + DotRowOffset[plane];
986 	band->plane = plane;
987 	band->row   = 0;
988 	band->count = DotRowCount - y / DotRowStep;
989 
990         if (band->count < 1)
991 	  band->count = 1;
992 	else if (band->count > DotRowCount)
993 	  band->count = DotRowCount;
994 
995 	fprintf(stderr, "DEBUG: DotBands[%d][%d] = %p, x = %d, y = %d, plane = %d, count = %d\n",
996 	        subrow, plane, (void*)band, band->x, band->y, band->plane, band->count);
997       }
998 
999       subrow = (subrow + DotRowFeed) % modrow;
1000     }
1001   }
1002   else
1003   {
1004    /*
1005     * Allocate memory for a single line of graphics...
1006     */
1007 
1008     ptr = calloc(PrinterPlanes, DotBufferSize);
1009 
1010     for (plane = 0; plane < PrinterPlanes; plane ++, ptr += DotBufferSize)
1011       DotBuffers[plane] = ptr;
1012   }
1013 
1014  /*
1015   * Set the output resolution...
1016   */
1017 
1018   cupsWritePrintData("\033(D\004\000", 5);
1019   putchar(units);
1020   putchar(units >> 8);
1021   putchar(units * DotRowStep / header->HWResolution[1]);
1022   putchar(units * DotColStep / header->HWResolution[0]);
1023 
1024  /*
1025   * Set the top of form...
1026   */
1027 
1028   OutputFeed = 0;
1029 
1030  /*
1031   * Allocate buffers as needed...
1032   */
1033 
1034   PixelBuffer      = malloc(header->cupsBytesPerLine);
1035   InputBuffer      = malloc(header->cupsWidth * PrinterPlanes * 2);
1036   OutputBuffers[0] = malloc(PrinterPlanes * header->cupsWidth);
1037 
1038   for (i = 1; i < PrinterPlanes; i ++)
1039     OutputBuffers[i] = OutputBuffers[0] + i * header->cupsWidth;
1040 
1041   if (RGB)
1042     CMYKBuffer = malloc(header->cupsWidth * PrinterPlanes);
1043 
1044   CompBuffer = malloc(10 * DotBufferSize * DotRowMax);
1045 }
1046 
1047 
1048 /*
1049  * 'EndPage()' - Finish a page of graphics.
1050  */
1051 
1052 void
EndPage(ppd_file_t * ppd,cups_page_header2_t * header)1053 EndPage(ppd_file_t         *ppd,	/* I - PPD file */
1054         cups_page_header2_t *header)	/* I - Page header */
1055 {
1056   int		i;			/* Looping var */
1057   cups_weave_t	*band,			/* Current band */
1058 		*next;			/* Next band in list */
1059   int		plane;			/* Current plane */
1060   int		subrow;			/* Current subrow */
1061   int		subrows;		/* Number of subrows */
1062 
1063 
1064  /*
1065   * Output the last bands of print data as necessary...
1066   */
1067 
1068   if (DotRowMax > 1)
1069   {
1070    /*
1071     * Move the remaining bands to the used or avail lists...
1072     */
1073 
1074     subrows = DotRowStep * DotColStep;
1075 
1076     for (subrow = 0; subrow < subrows; subrow ++)
1077       for (plane = 0; plane < PrinterPlanes; plane ++)
1078       {
1079         if (DotBands[subrow][plane]->dirty)
1080 	{
1081 	 /*
1082 	  * Insert into the used list...
1083 	  */
1084 
1085           DotBands[subrow][plane]->count = DotBands[subrow][plane]->row;
1086 
1087           AddBand(DotBands[subrow][plane]);
1088 	}
1089 	else
1090 	{
1091 	 /*
1092 	  * Nothing here, so move it to the available list...
1093 	  */
1094 
1095 	  DotBands[subrow][plane]->next = DotAvailList;
1096 	  DotAvailList                  = DotBands[subrow][plane];
1097 	}
1098 
1099 	DotBands[subrow][plane] = NULL;
1100       }
1101 
1102    /*
1103     * Loop until all bands are written...
1104     */
1105 
1106     fputs("DEBUG: Pointer list at end of page...\n", stderr);
1107 
1108     for (band = DotUsedList; band != NULL; band = band->next)
1109       fprintf(stderr, "DEBUG: %p (used)\n", (void*)band);
1110     for (band = DotAvailList; band != NULL; band = band->next)
1111       fprintf(stderr, "DEBUG: %p (avail)\n", (void*)band);
1112 
1113     fputs("DEBUG: ----END----\n", stderr);
1114 
1115     for (band = DotUsedList; band != NULL; band = next)
1116     {
1117       next = band->next;
1118 
1119       OutputBand(ppd, header, band);
1120 
1121       fprintf(stderr, "DEBUG: freeing used band %p, prev = %p, next = %p\n",
1122               (void*)band, (void*)band->prev, (void*)band->next);
1123 
1124       free(band->buffer);
1125       free(band);
1126     }
1127 
1128    /*
1129     * Free memory for the available bands, if any...
1130     */
1131 
1132     for (band = DotAvailList; band != NULL; band = next)
1133     {
1134       next = band->next;
1135 
1136       fprintf(stderr, "DEBUG: freeing avail band %p, prev = %p,  next = %p\n",
1137               (void*)band, (void*)band->prev, (void*)band->next);
1138 
1139       free(band->buffer);
1140       free(band);
1141     }
1142   }
1143   else
1144   {
1145     free(DotBuffers[0]);
1146     DotBuffers[0] = NULL;
1147   }
1148 
1149  /*
1150   * Output a page eject sequence...
1151   */
1152 
1153   putchar(12);
1154 
1155  /*
1156   * Free memory for the page...
1157   */
1158 
1159   for (i = 0; i < PrinterPlanes; i ++)
1160   {
1161     cupsDitherDelete(DitherStates[i]);
1162     cupsLutDelete(DitherLuts[i]);
1163   }
1164 
1165   free(OutputBuffers[0]);
1166 
1167   free(PixelBuffer);
1168   free(InputBuffer);
1169   free(CompBuffer);
1170 
1171   cupsCMYKDelete(CMYK);
1172 
1173   if (RGB)
1174   {
1175     cupsRGBDelete(RGB);
1176     free(CMYKBuffer);
1177   }
1178 }
1179 
1180 
1181 /*
1182  * 'Shutdown()' - Shutdown a printer.
1183  */
1184 
1185 void
Shutdown(ppd_file_t * ppd)1186 Shutdown(ppd_file_t *ppd)		/* I - PPD file */
1187 {
1188  /*
1189   * Reset the printer...
1190   */
1191 
1192   printf("\033@");
1193 
1194   if (ppd->model_number & ESCP_REMOTE)
1195   {
1196    /*
1197     * Go into remote mode...
1198     */
1199 
1200     cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
1201 
1202    /*
1203     * Load defaults...
1204     */
1205 
1206     cupsWritePrintData("LD\000\000", 4);
1207 
1208    /*
1209     * Exit remote mode...
1210     */
1211 
1212     cupsWritePrintData("\033\000\000\000", 4);
1213   }
1214 }
1215 
1216 
1217 /*
1218  * 'AddBand()' - Add a band of data to the used list.
1219  */
1220 
1221 void
AddBand(cups_weave_t * band)1222 AddBand(cups_weave_t *band)			/* I - Band to add */
1223 {
1224   cups_weave_t	*current,			/* Current band */
1225 		*prev;				/* Previous band */
1226 
1227 
1228   if (band->count < 1)
1229     return;
1230 
1231   for (current = DotUsedList, prev = NULL;
1232        current != 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))
1238       break;
1239 
1240   if (current != NULL)
1241   {
1242    /*
1243     * Insert the band...
1244     */
1245 
1246     band->next    = current;
1247     band->prev    = prev;
1248     current->prev = band;
1249 
1250     if (prev != NULL)
1251       prev->next = band;
1252     else
1253       DotUsedList = band;
1254   }
1255   else if (prev != NULL)
1256   {
1257    /*
1258     * Append the band to the end...
1259     */
1260 
1261     band->prev = prev;
1262     prev->next = band;
1263     band->next = NULL;
1264   }
1265   else
1266   {
1267    /*
1268     * First band in list...
1269     */
1270 
1271     DotUsedList = band;
1272     band->prev  = NULL;
1273     band->next  = NULL;
1274   }
1275 }
1276 
1277 
1278 /*
1279  * 'CancelJob()' - Cancel the current job...
1280  */
1281 
1282 void
CancelJob(int sig)1283 CancelJob(int sig)			/* I - Signal */
1284 {
1285   (void)sig;
1286 
1287   Canceled = 1;
1288 }
1289 
1290 
1291 /*
1292  * 'CompressData()' - Compress a line of graphics.
1293  */
1294 
1295 void
CompressData(ppd_file_t * ppd,const unsigned char * line,const int length,int plane,int type,const int rows,const int xstep,const int ystep,const int offset)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 */
1305 {
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 */
1314 		{
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 */
1322 		};
1323 
1324 
1325   switch (type)
1326   {
1327     case 0 :
1328        /*
1329 	* Do no compression...
1330 	*/
1331 
1332 	line_ptr = (const unsigned char *)line;
1333 	line_end = (const unsigned char *)line + length;
1334 	break;
1335 
1336     default :
1337        /*
1338         * Do TIFF pack-bits encoding...
1339         */
1340 
1341 	line_ptr = (const unsigned char *)line;
1342 	line_end = (const unsigned char *)line + length;
1343 	comp_ptr = CompBuffer;
1344 
1345 	while (line_ptr < line_end && (comp_ptr - CompBuffer) < length)
1346 	{
1347 	  if ((line_ptr + 1) >= line_end)
1348 	  {
1349 	   /*
1350 	    * Single byte on the end...
1351 	    */
1352 
1353 	    *comp_ptr++ = 0x00;
1354 	    *comp_ptr++ = *line_ptr++;
1355 	  }
1356 	  else if (line_ptr[0] == line_ptr[1])
1357 	  {
1358 	   /*
1359 	    * Repeated sequence...
1360 	    */
1361 
1362 	    line_ptr ++;
1363 	    count = 2;
1364 
1365 	    while (line_ptr < (line_end - 1) &&
1366         	   line_ptr[0] == line_ptr[1] &&
1367         	   count < 127)
1368 	    {
1369               line_ptr ++;
1370               count ++;
1371 	    }
1372 
1373 	    *comp_ptr++ = 257 - count;
1374 	    *comp_ptr++ = *line_ptr++;
1375 	  }
1376 	  else
1377 	  {
1378 	   /*
1379 	    * Non-repeated sequence...
1380 	    */
1381 
1382 	    start    = line_ptr;
1383 	    line_ptr ++;
1384 	    count    = 1;
1385 
1386 	    while (line_ptr < (line_end - 1) &&
1387         	   line_ptr[0] != line_ptr[1] &&
1388         	   count < 127)
1389 	    {
1390               line_ptr ++;
1391               count ++;
1392 	    }
1393 
1394 	    *comp_ptr++ = count - 1;
1395 
1396 	    memcpy(comp_ptr, start, count);
1397 	    comp_ptr += count;
1398 	  }
1399 	}
1400 
1401         if ((comp_ptr - CompBuffer) < length)
1402 	{
1403           line_ptr = (const unsigned char *)CompBuffer;
1404           line_end = (const unsigned char *)comp_ptr;
1405 	}
1406 	else
1407 	{
1408 	  type     = 0;
1409 	  line_ptr = (const unsigned char *)line;
1410 	  line_end = (const unsigned char *)line + length;
1411 	}
1412 	break;
1413   }
1414 
1415  /*
1416   * Position the print head...
1417   */
1418 
1419   putchar(0x0d);
1420 
1421   if (offset)
1422   {
1423     if (BitPlanes == 1)
1424       cupsWritePrintData("\033(\\\004\000\240\005", 7);
1425     else
1426       printf("\033\\");
1427 
1428     putchar(offset);
1429     putchar(offset >> 8);
1430   }
1431 
1432  /*
1433   * Send the graphics...
1434   */
1435 
1436   bytes = length / rows;
1437 
1438   if (ppd->model_number & ESCP_RASTER_ESCI)
1439   {
1440    /*
1441     * Send graphics with ESC i command.
1442     */
1443 
1444     printf("\033i");
1445     putchar(ctable[PrinterPlanes - 1][plane]);
1446     putchar((type != 0) ? '1': '0');
1447     putchar(BitPlanes);
1448     putchar(bytes & 255);
1449     putchar(bytes >> 8);
1450     putchar(rows & 255);
1451     putchar(rows >> 8);
1452   }
1453   else
1454   {
1455    /*
1456     * Set the color if necessary...
1457     */
1458 
1459     if (PrinterPlanes > 1)
1460     {
1461       plane = ctable[PrinterPlanes - 1][plane];
1462 
1463       if (plane & 0x10)
1464 	printf("\033(r%c%c%c%c", 2, 0, 1, plane & 0x0f);
1465       else
1466 	printf("\033r%c", plane);
1467     }
1468 
1469    /*
1470     * Send graphics with ESC . command.
1471     */
1472 
1473     bytes *= 8;
1474 
1475     printf("\033.");
1476     putchar((type != 0) ? '1': '0');
1477     putchar(ystep);
1478     putchar(xstep);
1479     putchar(rows);
1480     putchar(bytes & 255);
1481     putchar(bytes >> 8);
1482   }
1483 
1484   cupsWritePrintData(line_ptr, line_end - line_ptr);
1485 }
1486 
1487 
1488 /*
1489  * 'OutputBand()' - Output a band of graphics.
1490  */
1491 
1492 void
OutputBand(ppd_file_t * ppd,cups_page_header2_t * header,cups_weave_t * band)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 */
1496 {
1497   int	xstep,				/* Spacing between columns */
1498 	ystep;				/* Spacing between rows */
1499 
1500 
1501  /*
1502   * Interleaved ESC/P2 graphics...
1503   */
1504 
1505   OutputFeed    = band->y - DotRowCurrent;
1506   DotRowCurrent = band->y;
1507 
1508   fprintf(stderr, "DEBUG: Printing band %p, x = %d, y = %d, plane = %d, count = %d, OutputFeed = %d\n",
1509           (void*)band, band->x, band->y, band->plane, band->count, OutputFeed);
1510 
1511  /*
1512   * Compute step values...
1513   */
1514 
1515   xstep = 3600 * DotColStep / header->HWResolution[0];
1516   ystep = 3600 * DotRowStep / header->HWResolution[1];
1517 
1518  /*
1519   * Output the band...
1520   */
1521 
1522   if (OutputFeed > 0)
1523   {
1524     cupsWritePrintData("\033(v\002\000", 5);
1525     putchar(OutputFeed & 255);
1526     putchar(OutputFeed >> 8);
1527 
1528     OutputFeed = 0;
1529   }
1530 
1531   CompressData(ppd, band->buffer, band->count * DotBufferSize, band->plane,
1532 	       header->cupsCompression, band->count, xstep, ystep, band->x);
1533 
1534  /*
1535   * Clear the band...
1536   */
1537 
1538   memset(band->buffer, 0, band->count * DotBufferSize);
1539   band->dirty = 0;
1540 
1541  /*
1542   * Flush the output buffers...
1543   */
1544 
1545   fflush(stdout);
1546 }
1547 
1548 
1549 /*
1550  * 'ProcessLine()' - Read graphics from the page stream and output as needed.
1551  */
1552 
1553 void
ProcessLine(ppd_file_t * ppd,cups_raster_t * ras,cups_page_header2_t * header,const int y)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 */
1558 {
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 */
1568 
1569 
1570  /*
1571   * Read a row of graphics...
1572   */
1573 
1574   if (!cupsRasterReadPixels(ras, PixelBuffer, header->cupsBytesPerLine))
1575     return;
1576 
1577  /*
1578   * Perform the color separation...
1579   */
1580 
1581   width    = header->cupsWidth;
1582   subwidth = header->cupsWidth / DotColStep;
1583   xstep    = 3600 / header->HWResolution[0];
1584   ystep    = 3600 / header->HWResolution[1];
1585 
1586   switch (header->cupsColorSpace)
1587   {
1588     case CUPS_CSPACE_W :
1589         if (RGB)
1590 	{
1591 	  cupsRGBDoGray(RGB, PixelBuffer, CMYKBuffer, width);
1592 	  cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
1593 	}
1594 	else
1595           cupsCMYKDoGray(CMYK, PixelBuffer, InputBuffer, width);
1596 	break;
1597 
1598     case CUPS_CSPACE_K :
1599         cupsCMYKDoBlack(CMYK, PixelBuffer, InputBuffer, width);
1600 	break;
1601 
1602     default :
1603     case CUPS_CSPACE_RGB :
1604         if (RGB)
1605 	{
1606 	  cupsRGBDoRGB(RGB, PixelBuffer, CMYKBuffer, width);
1607 	  cupsCMYKDoCMYK(CMYK, CMYKBuffer, InputBuffer, width);
1608 	}
1609 	else
1610           cupsCMYKDoRGB(CMYK, PixelBuffer, InputBuffer, width);
1611 	break;
1612 
1613     case CUPS_CSPACE_CMYK :
1614         cupsCMYKDoCMYK(CMYK, PixelBuffer, InputBuffer, width);
1615 	break;
1616   }
1617 
1618  /*
1619   * Dither the pixels...
1620   */
1621 
1622   for (plane = 0; plane < PrinterPlanes; plane ++)
1623   {
1624     cupsDitherLine(DitherStates[plane], DitherLuts[plane], InputBuffer + plane,
1625                    PrinterPlanes, OutputBuffers[plane]);
1626 
1627     if (DotRowMax == 1)
1628     {
1629      /*
1630       * Handle microweaved output...
1631       */
1632 
1633       if (cupsCheckBytes(OutputBuffers[plane], width))
1634 	continue;
1635 
1636       if (BitPlanes == 1)
1637 	cupsPackHorizontal(OutputBuffers[plane], DotBuffers[plane],
1638 	                   width, 0, 1);
1639       else
1640 	cupsPackHorizontal2(OutputBuffers[plane], DotBuffers[plane],
1641                 	    width, 1);
1642 
1643       if (OutputFeed > 0)
1644       {
1645 	cupsWritePrintData("\033(v\002\000", 5);
1646 	putchar(OutputFeed & 255);
1647 	putchar(OutputFeed >> 8);
1648 	OutputFeed = 0;
1649       }
1650 
1651       CompressData(ppd, DotBuffers[plane], DotBufferSize, plane, 1, 1,
1652                    xstep, ystep, 0);
1653       fflush(stdout);
1654     }
1655     else
1656     {
1657      /*
1658       * Handle softweaved output...
1659       */
1660 
1661       for (pass = 0, subrow = y % DotRowStep;
1662            pass < DotColStep;
1663 	   pass ++, subrow += DotRowStep)
1664       {
1665        /*
1666 	* See if we need to output the band...
1667 	*/
1668 
1669         band   = DotBands[subrow][plane];
1670 	offset = band->row * DotBufferSize;
1671 
1672         if (BitPlanes == 1)
1673 	  cupsPackHorizontal(OutputBuffers[plane] + pass,
1674 	                     band->buffer + offset, subwidth, 0, DotColStep);
1675         else
1676 	  cupsPackHorizontal2(OutputBuffers[plane] + pass,
1677 	                      band->buffer + offset, subwidth, DotColStep);
1678 
1679         band->row ++;
1680 	band->dirty |= !cupsCheckBytes(band->buffer + offset, DotBufferSize);
1681 	if (band->row >= band->count)
1682 	{
1683 	  if (band->dirty)
1684 	  {
1685 	   /*
1686 	    * Dirty band needs to be added to the used list...
1687 	    */
1688 
1689 	    AddBand(band);
1690 
1691            /*
1692 	    * Then find a new band...
1693 	    */
1694 
1695 	    if (DotAvailList == NULL)
1696 	    {
1697 	      OutputBand(ppd, header, DotUsedList);
1698 
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;
1706 	    }
1707 	    else
1708 	    {
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;
1716 	    }
1717 	  }
1718 	  else
1719 	  {
1720 	   /*
1721 	    * This band isn't dirty, so reuse it...
1722 	    */
1723 
1724             fprintf(stderr, "DEBUG: Blank band %p, x = %d, y = %d, plane = %d, count = %d\n",
1725 	            (void*)band, band->x, band->y, band->plane, band->count);
1726 
1727 	    band->y     += band->count * DotRowStep;
1728 	    band->row   = 0;
1729 	    band->count = DotRowCount;
1730 	  }
1731         }
1732       }
1733     }
1734   }
1735 
1736   if (DotRowMax == 1)
1737     OutputFeed ++;
1738 }
1739 
1740 
1741 /*
1742  * 'main()' - Main entry and processing of driver.
1743  */
1744 
1745 int					/* O - Exit status */
main(int argc,char * argv[])1746 main(int  argc,				/* I - Number of command-line arguments */
1747      char *argv[])			/* I - Command-line arguments */
1748 {
1749   int			fd;		/* File descriptor */
1750   int empty = 1;
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 */
1761 
1762 
1763  /*
1764   * Make sure status messages are not buffered...
1765   */
1766 
1767   setbuf(stderr, NULL);
1768 
1769  /*
1770   * Check command-line...
1771   */
1772 
1773   if (argc < 6 || argc > 7)
1774   {
1775     fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
1776 	    argv[0]);
1777     return (1);
1778   }
1779 
1780   num_options = cupsParseOptions(argv[5], 0, &options);
1781 
1782  /*
1783   * Open the PPD file...
1784   */
1785 
1786   ppd = ppdOpenFile(getenv("PPD"));
1787 
1788   if (!ppd)
1789   {
1790     ppd_status_t	status;		/* PPD error */
1791     int			linenum;	/* Line number */
1792 
1793     fputs("ERROR: The PPD file could not be opened.\n", stderr);
1794 
1795     status = ppdLastError(&linenum);
1796 
1797     fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
1798 
1799     return (1);
1800   }
1801 
1802   ppdMarkDefaults(ppd);
1803   cupsMarkOptions(ppd, num_options, options);
1804 
1805  /*
1806   * Open the page stream...
1807   */
1808 
1809   if (argc == 7)
1810   {
1811     if ((fd = open(argv[6], O_RDONLY)) == -1)
1812     {
1813       perror("ERROR: Unable to open raster file");
1814       return (1);
1815     }
1816   }
1817   else
1818     fd = 0;
1819 
1820   ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
1821 
1822  /*
1823   * Register a signal handler to eject the current page if the
1824   * job is cancelled.
1825   */
1826 
1827   Canceled = 0;
1828 
1829 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1830   sigset(SIGTERM, CancelJob);
1831 #elif defined(HAVE_SIGACTION)
1832   memset(&action, 0, sizeof(action));
1833 
1834   sigemptyset(&action.sa_mask);
1835   action.sa_handler = CancelJob;
1836   sigaction(SIGTERM, &action, NULL);
1837 #else
1838   signal(SIGTERM, CancelJob);
1839 #endif /* HAVE_SIGSET */
1840 
1841  /*
1842   * Process pages as needed...
1843   */
1844 
1845   page = 0;
1846 
1847   while (cupsRasterReadHeader2(ras, &header))
1848   {
1849    /*
1850     * Write a status message with the page number and number of copies.
1851     */
1852 
1853     if (empty)
1854     {
1855      /*
1856       * Initialize the print device...
1857       */
1858       Setup(ppd);
1859       empty = 0;
1860     }
1861 
1862     if (Canceled)
1863       break;
1864 
1865     page ++;
1866 
1867     fprintf(stderr, "PAGE: %d 1\n", page);
1868     fprintf(stderr, "INFO: Starting page %d.\n", page);
1869 
1870     StartPage(ppd, &header);
1871 
1872     for (y = 0; y < header.cupsHeight; y ++)
1873     {
1874      /*
1875       * Let the user know how far we have progressed...
1876       */
1877 
1878       if (Canceled)
1879 	break;
1880 
1881       if ((y & 127) == 0)
1882       {
1883         fprintf(stderr, "INFO: Printing page %d, %d%% complete.\n",
1884 		page, 100 * y / header.cupsHeight);
1885         fprintf(stderr, "ATTR: job-media-progress=%d\n",
1886 		100 * y / header.cupsHeight);
1887       }
1888 
1889      /*
1890       * Read and write a line of graphics or whitespace...
1891       */
1892 
1893       ProcessLine(ppd, ras, &header, y);
1894     }
1895 
1896    /*
1897     * Eject the page...
1898     */
1899 
1900     fprintf(stderr, "INFO: Finished page %d.\n", page);
1901 
1902     EndPage(ppd, &header);
1903 
1904     if (Canceled)
1905       break;
1906   }
1907 
1908   if (!empty)
1909     Shutdown(ppd);
1910 
1911   cupsFreeOptions(num_options, options);
1912 
1913   cupsRasterClose(ras);
1914 
1915   if (fd != 0)
1916     close(fd);
1917 
1918   if (DotBuffers[0] != NULL)
1919     free(DotBuffers[0]);
1920 
1921   if (empty)
1922   {
1923     fprintf(stderr, "DEBUG: Input is empty, outputting empty file.\n");
1924     return 0;
1925   }
1926   return (page == 0);
1927 }
1928 
1929