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