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