]> git.ipfire.org Git - thirdparty/cups.git/blob - driver/rastertoescpx.c
Merge changes from CUPS 1.5.1-r9875.
[thirdparty/cups.git] / driver / rastertoescpx.c
1 /*
2 * "$Id$"
3 *
4 * Advanced EPSON ESC/P raster driver for CUPS.
5 *
6 * Copyright 2007-2010 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/language-private.h>
35 #include <cups/string-private.h>
36 #include "data/escp.h"
37 #include <signal.h>
38
39
40 /*
41 * Softweave data...
42 */
43
44 typedef struct cups_weave_str
45 {
46 struct cups_weave_str *prev, /* Previous band */
47 *next; /* Next band */
48 int x, y, /* Column/Line on the page */
49 plane, /* Color plane */
50 dirty, /* Is this buffer dirty? */
51 row, /* Row in the buffer */
52 count; /* Max rows this pass */
53 unsigned char *buffer; /* Data buffer */
54 } cups_weave_t;
55
56
57 /*
58 * Globals...
59 */
60
61 cups_rgb_t *RGB; /* RGB color separation data */
62 cups_cmyk_t *CMYK; /* CMYK color separation data */
63 unsigned char *PixelBuffer, /* Pixel buffer */
64 *CMYKBuffer, /* CMYK buffer */
65 *OutputBuffers[7], /* Output buffers */
66 *DotBuffers[7], /* Dot buffers */
67 *CompBuffer; /* Compression buffer */
68 short *InputBuffer; /* Color separation buffer */
69 cups_weave_t *DotAvailList, /* Available buffers */
70 *DotUsedList, /* Used buffers */
71 *DotBands[128][7]; /* Buffers in use */
72 int DotBufferSize, /* Size of dot buffers */
73 DotRowMax, /* Maximum row number in buffer */
74 DotColStep, /* Step for each output column */
75 DotRowStep, /* Step for each output line */
76 DotRowFeed, /* Amount to feed for interleave */
77 DotRowCount, /* Number of rows to output */
78 DotRowOffset[7], /* Offset for each color on print head */
79 DotRowCurrent, /* Current row */
80 DotSize; /* Dot size (Pro 5000 only) */
81 int PrinterPlanes, /* # of color planes */
82 BitPlanes, /* # of bit planes per color */
83 PrinterTop, /* Top of page */
84 PrinterLength; /* Length of page */
85 cups_lut_t *DitherLuts[7]; /* Lookup tables for dithering */
86 cups_dither_t *DitherStates[7]; /* Dither state tables */
87 int OutputFeed; /* Number of lines to skip */
88 int Canceled; /* Is the job canceled? */
89
90
91 /*
92 * Prototypes...
93 */
94
95 void Setup(ppd_file_t *);
96 void StartPage(ppd_file_t *, cups_page_header2_t *);
97 void EndPage(ppd_file_t *, cups_page_header2_t *);
98 void Shutdown(ppd_file_t *);
99
100 void AddBand(cups_weave_t *band);
101 void CancelJob(int sig);
102 void CompressData(ppd_file_t *, const unsigned char *, const int,
103 int, int, const int, const int, const int,
104 const int);
105 void OutputBand(ppd_file_t *, cups_page_header2_t *,
106 cups_weave_t *band);
107 void ProcessLine(ppd_file_t *, cups_raster_t *,
108 cups_page_header2_t *, const int y);
109
110
111 /*
112 * 'Setup()' - Prepare a printer for graphics output.
113 */
114
115 void
116 Setup(ppd_file_t *ppd) /* I - PPD file */
117 {
118 /*
119 * Some EPSON printers need an additional command issued at the
120 * beginning of each job to exit from USB "packet" mode...
121 */
122
123 if (ppd->model_number & ESCP_USB)
124 cupsWritePrintData("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
125 }
126
127
128 /*
129 * 'StartPage()' - Start a page of graphics.
130 */
131
132 void
133 StartPage(ppd_file_t *ppd, /* I - PPD file */
134 cups_page_header2_t *header) /* I - Page header */
135 {
136 int i, y; /* Looping vars */
137 int subrow, /* Current subrow */
138 modrow, /* Subrow modulus */
139 plane; /* Current color plane */
140 unsigned char *ptr; /* Pointer into dot buffer */
141 int bands; /* Number of bands to allocate */
142 int units; /* Units for resolution */
143 cups_weave_t *band; /* Current band */
144 const char *colormodel; /* Color model string */
145 char resolution[PPD_MAX_NAME],
146 /* Resolution string */
147 spec[PPD_MAX_NAME]; /* PPD attribute name */
148 ppd_attr_t *attr; /* Attribute from PPD file */
149 const float default_lut[2] = /* Default dithering lookup table */
150 {
151 0.0,
152 1.0
153 };
154
155
156 fprintf(stderr, "DEBUG: StartPage...\n");
157 fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass);
158 fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor);
159 fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType);
160 fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType);
161
162 fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance);
163 fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia);
164 fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate);
165 fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia);
166 fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
167 fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0],
168 header->HWResolution[1]);
169 fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
170 header->ImagingBoundingBox[0], header->ImagingBoundingBox[1],
171 header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
172 fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet);
173 fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog);
174 fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge);
175 fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0],
176 header->Margins[1]);
177 fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
178 fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
179 fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight);
180 fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint);
181 fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint);
182 fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
183 fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
184 fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp);
185 fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0],
186 header->PageSize[1]);
187 fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations);
188 fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch);
189 fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble);
190 fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
191 fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
192 fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
193 fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
194 fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
195 fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
196 fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
197 fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
198 fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
199 fprintf(stderr, "DEBUG: cupsRowCount = %d\n", header->cupsRowCount);
200 fprintf(stderr, "DEBUG: cupsRowFeed = %d\n", header->cupsRowFeed);
201 fprintf(stderr, "DEBUG: cupsRowStep = %d\n", header->cupsRowStep);
202
203 /*
204 * Figure out the color model and spec strings...
205 */
206
207 switch (header->cupsColorSpace)
208 {
209 case CUPS_CSPACE_K :
210 colormodel = "Black";
211 break;
212 case CUPS_CSPACE_W :
213 colormodel = "Gray";
214 break;
215 default :
216 case CUPS_CSPACE_RGB :
217 colormodel = "RGB";
218 break;
219 case CUPS_CSPACE_CMYK :
220 colormodel = "CMYK";
221 break;
222 }
223
224 if (header->HWResolution[0] != header->HWResolution[1])
225 snprintf(resolution, sizeof(resolution), "%dx%ddpi",
226 header->HWResolution[0], header->HWResolution[1]);
227 else
228 snprintf(resolution, sizeof(resolution), "%ddpi",
229 header->HWResolution[0]);
230
231 if (!header->MediaType[0])
232 strcpy(header->MediaType, "Plain");
233
234 /*
235 * Load the appropriate color profiles...
236 */
237
238 RGB = NULL;
239 CMYK = NULL;
240
241 fputs("DEBUG: Attempting to load color profiles using the following values:\n", stderr);
242 fprintf(stderr, "DEBUG: ColorModel = %s\n", colormodel);
243 fprintf(stderr, "DEBUG: MediaType = %s\n", header->MediaType);
244 fprintf(stderr, "DEBUG: Resolution = %s\n", resolution);
245
246 if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
247 header->cupsColorSpace == CUPS_CSPACE_W)
248 RGB = cupsRGBLoad(ppd, colormodel, header->MediaType, resolution);
249 else
250 RGB = NULL;
251
252 CMYK = cupsCMYKLoad(ppd, colormodel, header->MediaType, resolution);
253
254 if (RGB)
255 fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr);
256
257 if (CMYK)
258 fputs("DEBUG: Loaded CMYK separation from PPD.\n", stderr);
259 else
260 {
261 fputs("DEBUG: Loading default CMYK separation.\n", stderr);
262 CMYK = cupsCMYKNew(4);
263 }
264
265 PrinterPlanes = CMYK->num_channels;
266
267 fprintf(stderr, "DEBUG: PrinterPlanes = %d\n", PrinterPlanes);
268
269 /*
270 * Get the dithering parameters...
271 */
272
273 switch (PrinterPlanes)
274 {
275 case 1 : /* K */
276 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
277 resolution, "Black");
278 break;
279
280 case 2 : /* Kk */
281 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
282 resolution, "Black");
283 DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
284 resolution, "LightBlack");
285 break;
286
287 case 3 : /* CMY */
288 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
289 resolution, "Cyan");
290 DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
291 resolution, "Magenta");
292 DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
293 resolution, "Yellow");
294 break;
295
296 case 4 : /* CMYK */
297 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
298 resolution, "Cyan");
299 DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
300 resolution, "Magenta");
301 DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
302 resolution, "Yellow");
303 DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
304 resolution, "Black");
305 break;
306
307 case 6 : /* CcMmYK */
308 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
309 resolution, "Cyan");
310 DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
311 resolution, "LightCyan");
312 DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
313 resolution, "Magenta");
314 DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
315 resolution, "LightMagenta");
316 DitherLuts[4] = cupsLutLoad(ppd, colormodel, header->MediaType,
317 resolution, "Yellow");
318 DitherLuts[5] = cupsLutLoad(ppd, colormodel, header->MediaType,
319 resolution, "Black");
320 break;
321
322 case 7 : /* CcMmYKk */
323 DitherLuts[0] = cupsLutLoad(ppd, colormodel, header->MediaType,
324 resolution, "Cyan");
325 DitherLuts[1] = cupsLutLoad(ppd, colormodel, header->MediaType,
326 resolution, "LightCyan");
327 DitherLuts[2] = cupsLutLoad(ppd, colormodel, header->MediaType,
328 resolution, "Magenta");
329 DitherLuts[3] = cupsLutLoad(ppd, colormodel, header->MediaType,
330 resolution, "LightMagenta");
331 DitherLuts[4] = cupsLutLoad(ppd, colormodel, header->MediaType,
332 resolution, "Yellow");
333 DitherLuts[5] = cupsLutLoad(ppd, colormodel, header->MediaType,
334 resolution, "Black");
335 DitherLuts[6] = cupsLutLoad(ppd, colormodel, header->MediaType,
336 resolution, "LightBlack");
337 break;
338 }
339
340 for (plane = 0; plane < PrinterPlanes; plane ++)
341 {
342 DitherStates[plane] = cupsDitherNew(header->cupsWidth);
343
344 if (!DitherLuts[plane])
345 DitherLuts[plane] = cupsLutNew(2, default_lut);
346 }
347
348 if (DitherLuts[0][4095].pixel > 1)
349 BitPlanes = 2;
350 else
351 BitPlanes = 1;
352
353 /*
354 * Initialize the printer...
355 */
356
357 printf("\033@");
358
359 if (ppd->model_number & ESCP_REMOTE)
360 {
361 /*
362 * Go into remote mode...
363 */
364
365 cupsWritePrintData("\033(R\010\000\000REMOTE1", 13);
366
367 /*
368 * Disable status reporting...
369 */
370
371 cupsWritePrintData("ST\002\000\000\000", 6);
372
373 /*
374 * Enable borderless printing...
375 */
376
377 if ((attr = ppdFindAttr(ppd, "cupsESCPFP", NULL)) != NULL && attr->value)
378 {
379 /*
380 * Set horizontal offset...
381 */
382
383 i = atoi(attr->value);
384
385 cupsWritePrintData("FP\003\000\000", 5);
386 putchar(i & 255);
387 putchar(i >> 8);
388 }
389
390 /*
391 * Set media type...
392 */
393
394 if (header->cupsMediaType)
395 {
396 sprintf(spec, "%d", header->cupsMediaType);
397
398 if ((attr = ppdFindAttr(ppd, "cupsESCPSN0", spec)) != NULL && attr->value)
399 {
400 /*
401 * Set feed sequence...
402 */
403
404 cupsWritePrintData("SN\003\000\000\000", 6);
405 putchar(atoi(attr->value));
406 }
407
408 if ((attr = ppdFindAttr(ppd, "cupsESCPSN1", spec)) != NULL && attr->value)
409 {
410 /*
411 * Set platten gap...
412 */
413
414 cupsWritePrintData("SN\003\000\000\001", 6);
415 putchar(atoi(attr->value));
416 }
417
418 if ((attr = ppdFindAttr(ppd, "cupsESCPSN2", spec)) != NULL && attr->value)
419 {
420 /*
421 * Paper feeding/ejecting sequence...
422 */
423
424 cupsWritePrintData("SN\003\000\000\002", 6);
425 putchar(atoi(attr->value));
426 }
427
428 if ((attr = ppdFindAttr(ppd, "cupsESCPSN6", spec)) != NULL && attr->value)
429 {
430 /*
431 * Eject delay...
432 */
433
434 cupsWritePrintData("SN\003\000\000\006", 6);
435 putchar(atoi(attr->value));
436 }
437
438 if ((attr = ppdFindAttr(ppd, "cupsESCPMT", spec)) != NULL && attr->value)
439 {
440 /*
441 * Set media type.
442 */
443
444 cupsWritePrintData("MT\003\000\000\000", 6);
445 putchar(atoi(attr->value));
446 }
447
448 if ((attr = ppdFindAttr(ppd, "cupsESCPPH", spec)) != NULL && attr->value)
449 {
450 /*
451 * Set paper thickness.
452 */
453
454 cupsWritePrintData("PH\002\000\000", 5);
455 putchar(atoi(attr->value));
456 }
457 }
458
459 sprintf(spec, "%d", header->MediaPosition);
460
461 if (header->MediaPosition)
462 {
463 if ((attr = ppdFindAttr(ppd, "cupsESCPPC", spec)) != NULL && attr->value)
464 {
465 /*
466 * Paper check.
467 */
468
469 cupsWritePrintData("PC\002\000\000", 5);
470 putchar(atoi(attr->value));
471 }
472
473 if ((attr = ppdFindAttr(ppd, "cupsESCPPP", spec)) != NULL && attr->value)
474 {
475 /*
476 * Paper path.
477 */
478
479 int a, b;
480
481 a = b = 0;
482 sscanf(attr->value, "%d%d", &a, &b);
483
484 cupsWritePrintData("PP\003\000\000", 5);
485 putchar(a);
486 putchar(b);
487 }
488
489 if ((attr = ppdFindAttr(ppd, "cupsESCPEX", spec)) != NULL && attr->value)
490 {
491 /*
492 * Set media position.
493 */
494
495 cupsWritePrintData("EX\006\000\000\000\000\000\005", 9);
496 putchar(atoi(attr->value));
497 }
498 }
499
500 if ((attr = ppdFindAttr(ppd, "cupsESCPMS", spec)) != NULL && attr->value)
501 {
502 /*
503 * Set media size...
504 */
505
506 cupsWritePrintData("MS\010\000\000", 5);
507 putchar(atoi(attr->value));
508
509 switch (header->PageSize[1])
510 {
511 case 1191 : /* A3 */
512 putchar(0x01);
513 putchar(0x00);
514 putchar(0x00);
515 putchar(0x00);
516 putchar(0x00);
517 putchar(0x00);
518 break;
519 case 1032 : /* B4 */
520 putchar(0x02);
521 putchar(0x00);
522 putchar(0x00);
523 putchar(0x00);
524 putchar(0x00);
525 putchar(0x00);
526 break;
527 case 842 : /* A4 */
528 putchar(0x03);
529 putchar(0x00);
530 putchar(0x00);
531 putchar(0x00);
532 putchar(0x00);
533 putchar(0x00);
534 break;
535 case 595 : /* A4.Transverse */
536 putchar(0x03);
537 putchar(0x01);
538 putchar(0x00);
539 putchar(0x00);
540 putchar(0x00);
541 putchar(0x00);
542 break;
543 case 729 : /* B5 */
544 putchar(0x04);
545 putchar(0x00);
546 putchar(0x00);
547 putchar(0x00);
548 putchar(0x00);
549 putchar(0x00);
550 break;
551 case 516 : /* B5.Transverse */
552 putchar(0x04);
553 putchar(0x01);
554 putchar(0x00);
555 putchar(0x00);
556 putchar(0x00);
557 putchar(0x00);
558 break;
559 case 1369 : /* Super A3/B */
560 putchar(0x20);
561 putchar(0x00);
562 putchar(0x00);
563 putchar(0x00);
564 putchar(0x00);
565 putchar(0x00);
566 break;
567 case 792 : /* Letter */
568 putchar(0x08);
569 putchar(0x00);
570 putchar(0x00);
571 putchar(0x00);
572 putchar(0x00);
573 putchar(0x00);
574 break;
575 case 612 : /* Letter.Transverse */
576 putchar(0x08);
577 putchar(0x01);
578 putchar(0x00);
579 putchar(0x00);
580 putchar(0x00);
581 putchar(0x00);
582 break;
583 case 1004 : /* Legal */
584 putchar(0x0a);
585 putchar(0x00);
586 putchar(0x00);
587 putchar(0x00);
588 putchar(0x00);
589 putchar(0x00);
590 break;
591 case 1224 : /* Tabloid */
592 putchar(0x2d);
593 putchar(0x00);
594 putchar(0x00);
595 putchar(0x00);
596 putchar(0x00);
597 putchar(0x00);
598 break;
599 default : /* Custom size */
600 putchar(0xff);
601 putchar(0xff);
602 i = 360 * header->PageSize[0] / 72;
603 putchar(i);
604 putchar(i >> 8);
605 i = 360 * header->PageSize[1] / 72;
606 putchar(i);
607 putchar(i >> 8);
608 break;
609 }
610 }
611
612 sprintf(spec, "%d", header->CutMedia);
613
614 if ((attr = ppdFindAttr(ppd, "cupsESCPAC", spec)) != NULL && attr->value)
615 {
616 /*
617 * Enable/disable cutter.
618 */
619
620 cupsWritePrintData("AC\002\000\000", 5);
621 putchar(atoi(attr->value));
622
623 if ((attr = ppdFindAttr(ppd, "cupsESCPSN80", header->MediaType)) != NULL && attr->value)
624 {
625 /*
626 * Cutting method...
627 */
628
629 cupsWritePrintData("SN\003\000\000\200", 6);
630 putchar(atoi(attr->value));
631 }
632
633 if ((attr = ppdFindAttr(ppd, "cupsESCPSN81", header->MediaType)) != NULL && attr->value)
634 {
635 /*
636 * Cutting pressure...
637 */
638
639 cupsWritePrintData("SN\003\000\000\201", 6);
640 putchar(atoi(attr->value));
641 }
642 }
643
644 if ((attr = ppdFindAttr(ppd, "cupsESCPCO", spec)) != NULL && attr->value)
645 {
646 /*
647 * Enable/disable cutter.
648 */
649
650 cupsWritePrintData("CO\010\000\000\000", 6);
651 putchar(atoi(attr->value));
652 cupsWritePrintData("\000\000\000\000\000", 5);
653 }
654
655 /*
656 * Exit remote mode...
657 */
658
659 cupsWritePrintData("\033\000\000\000", 4);
660 }
661
662 /*
663 * Enter graphics mode...
664 */
665
666 cupsWritePrintData("\033(G\001\000\001", 6);
667
668 /*
669 * Set the line feed increment...
670 */
671
672 /* TODO: get this from the PPD file... */
673 for (units = 1440; units < header->HWResolution[0]; units *= 2);
674
675 if (ppd->model_number & ESCP_EXT_UNITS)
676 {
677 cupsWritePrintData("\033(U\005\000", 5);
678 putchar(units / header->HWResolution[1]);
679 putchar(units / header->HWResolution[1]);
680 putchar(units / header->HWResolution[0]);
681 putchar(units);
682 putchar(units >> 8);
683 }
684 else
685 {
686 cupsWritePrintData("\033(U\001\000", 5);
687 putchar(3600 / header->HWResolution[1]);
688 }
689
690 /*
691 * Set the page length...
692 */
693
694 PrinterLength = header->PageSize[1] * header->HWResolution[1] / 72;
695
696 if (ppd->model_number & ESCP_PAGE_SIZE)
697 {
698 /*
699 * Set page size (expands bottom margin)...
700 */
701
702 cupsWritePrintData("\033(S\010\000", 5);
703
704 i = header->PageSize[0] * header->HWResolution[1] / 72;
705 putchar(i);
706 putchar(i >> 8);
707 putchar(i >> 16);
708 putchar(i >> 24);
709
710 i = header->PageSize[1] * header->HWResolution[1] / 72;
711 putchar(i);
712 putchar(i >> 8);
713 putchar(i >> 16);
714 putchar(i >> 24);
715 }
716 else
717 {
718 cupsWritePrintData("\033(C\002\000", 5);
719 putchar(PrinterLength & 255);
720 putchar(PrinterLength >> 8);
721 }
722
723 /*
724 * Set the top and bottom margins...
725 */
726
727 PrinterTop = (int)((ppd->sizes[1].length - ppd->sizes[1].top) *
728 header->HWResolution[1] / 72.0);
729
730 if (ppd->model_number & ESCP_EXT_MARGINS)
731 {
732 cupsWritePrintData("\033(c\010\000", 5);
733
734 putchar(PrinterTop);
735 putchar(PrinterTop >> 8);
736 putchar(PrinterTop >> 16);
737 putchar(PrinterTop >> 24);
738
739 putchar(PrinterLength);
740 putchar(PrinterLength >> 8);
741 putchar(PrinterLength >> 16);
742 putchar(PrinterLength >> 24);
743 }
744 else
745 {
746 cupsWritePrintData("\033(c\004\000", 5);
747
748 putchar(PrinterTop & 255);
749 putchar(PrinterTop >> 8);
750
751 putchar(PrinterLength & 255);
752 putchar(PrinterLength >> 8);
753 }
754
755 /*
756 * Set the top position...
757 */
758
759 cupsWritePrintData("\033(V\002\000\000\000", 7);
760
761 /*
762 * Enable unidirectional printing depending on the mode...
763 */
764
765 if ((attr = cupsFindAttr(ppd, "cupsESCPDirection", colormodel,
766 header->MediaType, resolution, spec,
767 sizeof(spec))) != NULL)
768 printf("\033U%c", atoi(attr->value));
769
770 /*
771 * Enable/disable microweaving as needed...
772 */
773
774 if ((attr = cupsFindAttr(ppd, "cupsESCPMicroWeave", colormodel,
775 header->MediaType, resolution, spec,
776 sizeof(spec))) != NULL)
777 printf("\033(i\001%c%c", 0, atoi(attr->value));
778
779 /*
780 * Set the dot size and print speed as needed...
781 */
782
783 if ((attr = cupsFindAttr(ppd, "cupsESCPDotSize", colormodel,
784 header->MediaType, resolution, spec,
785 sizeof(spec))) != NULL)
786 printf("\033(e\002%c%c%c", 0, 0, atoi(attr->value));
787
788 if (ppd->model_number & ESCP_ESCK)
789 {
790 /*
791 * Set the print mode...
792 */
793
794 if (PrinterPlanes == 1)
795 {
796 /*
797 * Fast black printing.
798 */
799
800 cupsWritePrintData("\033(K\002\000\000\001", 7);
801 }
802 else
803 {
804 /*
805 * Color printing.
806 */
807
808 cupsWritePrintData("\033(K\002\000\000\002", 7);
809 }
810 }
811
812 /*
813 * Get softweave settings from header...
814 */
815
816 if (header->cupsRowCount <= 1)
817 {
818 DotRowCount = 1;
819 DotColStep = 1;
820 DotRowStep = 1;
821 DotRowFeed = 1;
822 }
823 else
824 {
825 DotRowCount = header->cupsRowCount;
826 DotRowFeed = header->cupsRowFeed;
827 DotRowStep = header->cupsRowStep % 100;
828 DotColStep = header->cupsRowStep / 100;
829
830 if (DotColStep == 0)
831 DotColStep ++;
832 }
833
834 /*
835 * Setup softweave parameters...
836 */
837
838 DotRowCurrent = 0;
839 DotRowMax = DotRowCount * DotRowStep;
840 DotBufferSize = (header->cupsWidth / DotColStep * BitPlanes + 7) / 8;
841
842 fprintf(stderr, "DEBUG: DotBufferSize = %d\n", DotBufferSize);
843 fprintf(stderr, "DEBUG: DotColStep = %d\n", DotColStep);
844 fprintf(stderr, "DEBUG: DotRowMax = %d\n", DotRowMax);
845 fprintf(stderr, "DEBUG: DotRowStep = %d\n", DotRowStep);
846 fprintf(stderr, "DEBUG: DotRowFeed = %d\n", DotRowFeed);
847 fprintf(stderr, "DEBUG: DotRowCount = %d\n", DotRowCount);
848
849 DotAvailList = NULL;
850 DotUsedList = NULL;
851 DotBuffers[0] = NULL;
852
853 fprintf(stderr, "DEBUG: model_number = %x\n", ppd->model_number);
854
855 if (DotRowMax > 1)
856 {
857 /*
858 * Compute offsets for the color jets on the print head...
859 */
860
861 bands = DotRowStep * DotColStep * PrinterPlanes * 4;
862
863 memset(DotRowOffset, 0, sizeof(DotRowOffset));
864
865 if (PrinterPlanes == 1)
866 {
867 /*
868 * Use full height of print head...
869 */
870
871 if ((attr = ppdFindAttr(ppd, "cupsESCPBlack", resolution)) != NULL &&
872 attr->value)
873 {
874 /*
875 * Use custom black head data...
876 */
877
878 sscanf(attr->value, "%d%d", &DotRowCount, &DotRowStep);
879 }
880 }
881 else if (ppd->model_number & ESCP_STAGGER)
882 {
883 /*
884 * Use staggered print head...
885 */
886
887 fputs("DEBUG: Offset head detected...\n", stderr);
888
889 if ((attr = ppdFindAttr(ppd, "cupsESCPOffsets", resolution)) != NULL &&
890 attr->value)
891 {
892 /*
893 * Use only 1/3 of the print head when printing color...
894 */
895
896 sscanf(attr->value, "%d%d%d%d", DotRowOffset + 0,
897 DotRowOffset + 1, DotRowOffset + 2, DotRowOffset + 3);
898 }
899 }
900
901 for (i = 0; i < PrinterPlanes; i ++)
902 fprintf(stderr, "DEBUG: DotRowOffset[%d] = %d\n", i, DotRowOffset[i]);
903
904 /*
905 * Allocate bands...
906 */
907
908 for (i = 0; i < bands; i ++)
909 {
910 band = (cups_weave_t *)calloc(1, sizeof(cups_weave_t));
911 band->next = DotAvailList;
912 DotAvailList = band;
913
914 band->buffer = calloc(DotRowCount, DotBufferSize);
915 }
916
917 if (!DotAvailList)
918 {
919 fputs("ERROR: Unable to allocate band list\n", stderr);
920 exit(1);
921 }
922
923 fputs("DEBUG: Pointer list at start of page...\n", stderr);
924
925 for (band = DotAvailList; band != NULL; band = band->next)
926 fprintf(stderr, "DEBUG: %p\n", band);
927
928 fputs("DEBUG: ----END----\n", stderr);
929
930 /*
931 * Fill the initial bands...
932 */
933
934 modrow = DotColStep * DotRowStep;
935
936 if (DotRowFeed == 0)
937 {
938 /*
939 * Automatically compute the optimal feed value...
940 */
941
942 DotRowFeed = DotRowCount / DotColStep - DotRowStep;
943
944 while ((((DotRowFeed % 2) == 0) == ((DotRowCount % 2) == 0) ||
945 ((DotRowFeed % 3) == 0) == ((DotRowCount % 3) == 0) ||
946 ((DotRowFeed % 5) == 0) == ((DotRowCount % 5) == 0)) &&
947 DotRowFeed > 1)
948 DotRowFeed --;
949
950 if (DotRowFeed < 1)
951 DotRowFeed = 1;
952
953 fprintf(stderr, "DEBUG: Auto DotRowFeed = %d, modrow=%d...\n",
954 DotRowFeed, modrow);
955 }
956
957 memset(DotBands, 0, sizeof(DotBands));
958
959 for (i = modrow, subrow = modrow - 1, y = DotRowFeed;
960 i > 0;
961 i --, y += DotRowFeed)
962 {
963 while (DotBands[subrow][0])
964 {
965 /*
966 * This subrow is already used, move to another one...
967 */
968
969 subrow = (subrow + 1) % modrow;
970 }
971
972 for (plane = 0; plane < PrinterPlanes; plane ++)
973 {
974 /*
975 * Pull the next available band from the list...
976 */
977
978 band = DotAvailList;
979 DotAvailList = DotAvailList->next;
980 DotBands[subrow][plane] = band;
981
982 /*
983 * Start the band in the first few passes, with the number of rows
984 * varying to allow for a nice interleaved pattern...
985 */
986
987 band->x = subrow / DotRowStep;
988 band->y = (subrow % DotRowStep) + DotRowOffset[plane];
989 band->plane = plane;
990 band->row = 0;
991 band->count = DotRowCount - y / DotRowStep;
992
993 if (band->count < 1)
994 band->count = 1;
995 else if (band->count > DotRowCount)
996 band->count = DotRowCount;
997
998 fprintf(stderr, "DEBUG: DotBands[%d][%d] = %p, x = %d, y = %d, plane = %d, count = %d\n",
999 subrow, plane, band, band->x, band->y, band->plane, band->count);
1000 }
1001
1002 subrow = (subrow + DotRowFeed) % modrow;
1003 }
1004 }
1005 else
1006 {
1007 /*
1008 * Allocate memory for a single line of graphics...
1009 */
1010
1011 ptr = calloc(PrinterPlanes, DotBufferSize);
1012
1013 for (plane = 0; plane < PrinterPlanes; plane ++, ptr += DotBufferSize)
1014 DotBuffers[plane] = ptr;
1015 }
1016
1017 /*
1018 * Set the output resolution...
1019 */
1020
1021 cupsWritePrintData("\033(D\004\000", 5);
1022 putchar(units);
1023 putchar(units >> 8);
1024 putchar(units * DotRowStep / header->HWResolution[1]);
1025 putchar(units * DotColStep / header->HWResolution[0]);
1026
1027 /*
1028 * Set the top of form...
1029 */
1030
1031 OutputFeed = 0;
1032
1033 /*
1034 * Allocate buffers as needed...
1035 */
1036
1037 PixelBuffer = malloc(header->cupsBytesPerLine);
1038 InputBuffer = malloc(header->cupsWidth * PrinterPlanes * 2);
1039 OutputBuffers[0] = malloc(PrinterPlanes * header->cupsWidth);
1040
1041 for (i = 1; i < PrinterPlanes; i ++)
1042 OutputBuffers[i] = OutputBuffers[0] + i * header->cupsWidth;
1043
1044 if (RGB)
1045 CMYKBuffer = malloc(header->cupsWidth * PrinterPlanes);
1046
1047 CompBuffer = malloc(10 * DotBufferSize * DotRowMax);
1048 }
1049
1050
1051 /*
1052 * 'EndPage()' - Finish a page of graphics.
1053 */
1054
1055 void
1056 EndPage(ppd_file_t *ppd, /* I - PPD file */
1057 cups_page_header2_t *header) /* I - Page header */
1058 {
1059 int i; /* Looping var */
1060 cups_weave_t *band, /* Current band */
1061 *next; /* Next band in list */
1062 int plane; /* Current plane */
1063 int subrow; /* Current subrow */
1064 int subrows; /* Number of subrows */
1065
1066
1067 /*
1068 * Output the last bands of print data as necessary...
1069 */
1070
1071 if (DotRowMax > 1)
1072 {
1073 /*
1074 * Move the remaining bands to the used or avail lists...
1075 */
1076
1077 subrows = DotRowStep * DotColStep;
1078
1079 for (subrow = 0; subrow < subrows; subrow ++)
1080 for (plane = 0; plane < PrinterPlanes; plane ++)
1081 {
1082 if (DotBands[subrow][plane]->dirty)
1083 {
1084 /*
1085 * Insert into the used list...
1086 */
1087
1088 DotBands[subrow][plane]->count = DotBands[subrow][plane]->row;
1089
1090 AddBand(DotBands[subrow][plane]);
1091 }
1092 else
1093 {
1094 /*
1095 * Nothing here, so move it to the available list...
1096 */
1097
1098 DotBands[subrow][plane]->next = DotAvailList;
1099 DotAvailList = DotBands[subrow][plane];
1100 }
1101
1102 DotBands[subrow][plane] = NULL;
1103 }
1104
1105 /*
1106 * Loop until all bands are written...
1107 */
1108
1109 fputs("DEBUG: Pointer list at end of page...\n", stderr);
1110
1111 for (band = DotUsedList; band != NULL; band = band->next)
1112 fprintf(stderr, "DEBUG: %p (used)\n", band);
1113 for (band = DotAvailList; band != NULL; band = band->next)
1114 fprintf(stderr, "DEBUG: %p (avail)\n", band);
1115
1116 fputs("DEBUG: ----END----\n", stderr);
1117
1118 for (band = DotUsedList; band != NULL; band = next)
1119 {
1120 next = band->next;
1121
1122 OutputBand(ppd, header, band);
1123
1124 fprintf(stderr, "DEBUG: freeing used band %p, prev = %p, next = %p\n",
1125 band, band->prev, band->next);
1126
1127 free(band->buffer);
1128 free(band);
1129 }
1130
1131 /*
1132 * Free memory for the available bands, if any...
1133 */
1134
1135 for (band = DotAvailList; band != NULL; band = next)
1136 {
1137 next = band->next;
1138
1139 fprintf(stderr, "DEBUG: freeing avail band %p, prev = %p, next = %p\n",
1140 band, band->prev, band->next);
1141
1142 free(band->buffer);
1143 free(band);
1144 }
1145 }
1146 else
1147 free(DotBuffers[0]);
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
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
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
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
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);
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);
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
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 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
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 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 */
1746 main(int argc, /* I - Number of command-line arguments */
1747 char *argv[]) /* I - Command-line arguments */
1748 {
1749 int fd; /* File descriptor */
1750 cups_raster_t *ras; /* Raster stream for printing */
1751 cups_page_header2_t header; /* Page header from file */
1752 int page; /* Current page */
1753 int y; /* Current line */
1754 ppd_file_t *ppd; /* PPD file */
1755 int num_options; /* Number of options */
1756 cups_option_t *options; /* Options */
1757 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1758 struct sigaction action; /* Actions for POSIX signals */
1759 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1760
1761
1762 /*
1763 * Make sure status messages are not buffered...
1764 */
1765
1766 setbuf(stderr, NULL);
1767
1768 /*
1769 * Check command-line...
1770 */
1771
1772 if (argc < 6 || argc > 7)
1773 {
1774 _cupsLangPrintFilter(stderr, "ERROR",
1775 _("%s job-id user title copies options [file]"),
1776 "rastertoescpx");
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 _cupsLangPrintFilter(stderr, "ERROR",
1794 _("The PPD file could not be opened."));
1795
1796 status = ppdLastError(&linenum);
1797
1798 fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
1799
1800 return (1);
1801 }
1802
1803 ppdMarkDefaults(ppd);
1804 cupsMarkOptions(ppd, num_options, options);
1805
1806 /*
1807 * Open the page stream...
1808 */
1809
1810 if (argc == 7)
1811 {
1812 if ((fd = open(argv[6], O_RDONLY)) == -1)
1813 {
1814 _cupsLangPrintError("ERROR", _("Unable to open raster file"));
1815 return (1);
1816 }
1817 }
1818 else
1819 fd = 0;
1820
1821 ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
1822
1823 /*
1824 * Register a signal handler to eject the current page if the
1825 * job is cancelled.
1826 */
1827
1828 Canceled = 0;
1829
1830 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1831 sigset(SIGTERM, CancelJob);
1832 #elif defined(HAVE_SIGACTION)
1833 memset(&action, 0, sizeof(action));
1834
1835 sigemptyset(&action.sa_mask);
1836 action.sa_handler = CancelJob;
1837 sigaction(SIGTERM, &action, NULL);
1838 #else
1839 signal(SIGTERM, CancelJob);
1840 #endif /* HAVE_SIGSET */
1841
1842 /*
1843 * Initialize the print device...
1844 */
1845
1846 Setup(ppd);
1847
1848 /*
1849 * Process pages as needed...
1850 */
1851
1852 page = 0;
1853
1854 while (cupsRasterReadHeader2(ras, &header))
1855 {
1856 /*
1857 * Write a status message with the page number and number of copies.
1858 */
1859
1860 if (Canceled)
1861 break;
1862
1863 page ++;
1864
1865 fprintf(stderr, "PAGE: %d 1\n", page);
1866 _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), page);
1867
1868 StartPage(ppd, &header);
1869
1870 for (y = 0; y < header.cupsHeight; y ++)
1871 {
1872 /*
1873 * Let the user know how far we have progressed...
1874 */
1875
1876 if (Canceled)
1877 break;
1878
1879 if ((y & 127) == 0)
1880 {
1881 _cupsLangPrintFilter(stderr, "INFO",
1882 _("Printing page %d, %d%% complete."),
1883 page, 100 * y / header.cupsHeight);
1884 fprintf(stderr, "ATTR: job-media-progress=%d\n",
1885 100 * y / header.cupsHeight);
1886 }
1887
1888 /*
1889 * Read and write a line of graphics or whitespace...
1890 */
1891
1892 ProcessLine(ppd, ras, &header, y);
1893 }
1894
1895 /*
1896 * Eject the page...
1897 */
1898
1899 _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), page);
1900
1901 EndPage(ppd, &header);
1902
1903 if (Canceled)
1904 break;
1905 }
1906
1907 Shutdown(ppd);
1908
1909 cupsFreeOptions(num_options, options);
1910
1911 cupsRasterClose(ras);
1912
1913 if (fd != 0)
1914 close(fd);
1915
1916 if (page == 0)
1917 {
1918 _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
1919 return (1);
1920 }
1921 else
1922 {
1923 _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
1924 return (0);
1925 }
1926 }
1927
1928
1929 /*
1930 * End of "$Id$".
1931 */