1 /*
2 * EPSON ESC/P and ESC/P2 filter for CUPS.
3 *
4 * Copyright © 2020-2024 by OpenPrinting.
5 * Copyright 2007-2018 by Apple Inc.
6 * Copyright 1993-2007 by Easy Software Products.
7 *
8 * Licensed under Apache License v2.0. See the file "LICENSE" for more
9 * information.
10 */
11
12 /*
13 * Include necessary headers...
14 */
15
16 #include <cups/cups.h>
17 #include <cups/ppd.h>
18 #include <cups/string-private.h>
19 #include <cups/language-private.h>
20 #include <cups/raster.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <signal.h>
24
25
26 /*
27 * Model numbers...
28 */
29
30 #define EPSON_9PIN 0
31 #define EPSON_24PIN 1
32 #define EPSON_COLOR 2
33 #define EPSON_PHOTO 3
34 #define EPSON_ICOLOR 4
35 #define EPSON_IPHOTO 5
36
37
38 /*
39 * Macros...
40 */
41
42 #define pwrite(s,n) fwrite((s), 1, (n), stdout)
43
44
45 /*
46 * Globals...
47 */
48
49 unsigned char *Planes[6], /* Output buffers */
50 *CompBuffer, /* Compression buffer */
51 *LineBuffers[2]; /* Line bitmap buffers */
52 int Model, /* Model number */
53 EjectPage, /* Eject the page when done? */
54 Shingling, /* Shingle output? */
55 Canceled; /* Has the current job been canceled? */
56 unsigned NumPlanes, /* Number of color planes */
57 Feed, /* Number of lines to skip */
58 DotBit, /* Bit in buffers */
59 DotBytes, /* # bytes in a dot column */
60 DotColumns, /* # columns in 1/60 inch */
61 LineCount, /* # of lines processed */
62 EvenOffset, /* Offset into 'even' buffers */
63 OddOffset; /* Offset into 'odd' buffers */
64
65
66 /*
67 * Prototypes...
68 */
69
70 void Setup(void);
71 void StartPage(const ppd_file_t *ppd, const cups_page_header2_t *header);
72 void EndPage(const cups_page_header2_t *header);
73 void Shutdown(void);
74
75 void CancelJob(int sig);
76 void CompressData(const unsigned char *line, unsigned length, unsigned plane,
77 unsigned type, unsigned xstep, unsigned ystep);
78 void OutputLine(const cups_page_header2_t *header);
79 void OutputRows(const cups_page_header2_t *header, int row);
80
81
82 /*
83 * 'Setup()' - Prepare the printer for printing.
84 */
85
86 void
Setup(void)87 Setup(void)
88 {
89 const char *device_uri; /* The device for the printer... */
90
91
92 /*
93 * EPSON USB printers need an additional command issued at the
94 * beginning of each job to exit from "packet" mode...
95 */
96
97 if ((device_uri = getenv("DEVICE_URI")) != NULL &&
98 strncmp(device_uri, "usb:", 4) == 0 && Model >= EPSON_ICOLOR)
99 pwrite("\000\000\000\033\001@EJL 1284.4\n@EJL \n\033@", 29);
100 }
101
102
103 /*
104 * 'StartPage()' - Start a page of graphics.
105 */
106
107 void
StartPage(const ppd_file_t * ppd,const cups_page_header2_t * header)108 StartPage(
109 const ppd_file_t *ppd, /* I - PPD file */
110 const cups_page_header2_t *header) /* I - Page header */
111 {
112 int n, t; /* Numbers */
113 unsigned plane; /* Looping var */
114
115
116 /*
117 * Show page device dictionary...
118 */
119
120 fprintf(stderr, "DEBUG: StartPage...\n");
121 fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
122 fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0], header->HWResolution[1]);
123 fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", header->ImagingBoundingBox[0], header->ImagingBoundingBox[1], header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
124 fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0], header->Margins[1]);
125 fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
126 fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
127 fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
128 fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
129 fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0], header->PageSize[1]);
130 fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
131 fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
132 fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
133 fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
134 fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
135 fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
136 fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
137 fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
138 fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
139
140 /*
141 * Send a reset sequence.
142 */
143
144 if (ppd && ppd->nickname && strstr(ppd->nickname, "OKIDATA") != NULL)
145 printf("\033{A"); /* Set EPSON emulation mode */
146
147 printf("\033@");
148
149 /*
150 * See which type of printer we are using...
151 */
152
153 switch (Model)
154 {
155 case EPSON_9PIN :
156 case EPSON_24PIN :
157 printf("\033P\022"); /* Set 10 CPI */
158
159 if (header->HWResolution[0] == 360 || header->HWResolution[0] == 240)
160 {
161 printf("\033x1"); /* LQ printing */
162 printf("\033U1"); /* Unidirectional */
163 }
164 else
165 {
166 printf("\033x0"); /* Draft printing */
167 printf("\033U0"); /* Bidirectional */
168 }
169
170 printf("\033l%c\033Q%c", 0, /* Side margins */
171 (int)(10.0 * header->PageSize[0] / 72.0 + 0.5));
172 printf("\033\062\033C%c", /* Page length in 1/6th inches */
173 (int)(header->PageSize[1] / 12.0 + 0.5));
174 printf("\033N%c", 0); /* Bottom margin */
175 printf("\033O"); /* No perforation skip */
176
177 /*
178 * Setup various buffer limits...
179 */
180
181 DotBytes = header->cupsRowCount / 8;
182 DotColumns = header->HWResolution[0] / 60;
183 Shingling = 0;
184
185 if (Model == EPSON_9PIN)
186 printf("\033\063\030"); /* Set line feed */
187 else
188 switch (header->HWResolution[0])
189 {
190 case 60:
191 case 120 :
192 case 240 :
193 printf("\033\063\030"); /* Set line feed */
194 break;
195
196 case 180 :
197 case 360 :
198 Shingling = 1;
199
200 if (header->HWResolution[1] == 180)
201 printf("\033\063\010");/* Set line feed */
202 else
203 printf("\033+\010"); /* Set line feed */
204 break;
205 }
206 break;
207
208 default :
209 /*
210 * Set graphics mode...
211 */
212
213 pwrite("\033(G\001\000\001", 6); /* Graphics mode */
214
215 /*
216 * Set the media size...
217 */
218
219 if (Model < EPSON_ICOLOR)
220 {
221 pwrite("\033(U\001\000", 5); /* Resolution/units */
222 putchar((int)(3600 / header->HWResolution[1]));
223 }
224 else
225 {
226 pwrite("\033(U\005\000", 5);
227 putchar((int)(1440 / header->HWResolution[1]));
228 putchar((int)(1440 / header->HWResolution[1]));
229 putchar((int)(1440 / header->HWResolution[0]));
230 putchar(0xa0); /* n/1440ths... */
231 putchar(0x05);
232 }
233
234 n = (int)(header->PageSize[1] * header->HWResolution[1] / 72.0);
235
236 pwrite("\033(C\002\000", 5); /* Page length */
237 putchar(n);
238 putchar(n >> 8);
239
240 if (ppd)
241 t = (int)((ppd->sizes[1].length - ppd->sizes[1].top) * header->HWResolution[1] / 72.0);
242 else
243 t = 0;
244
245 pwrite("\033(c\004\000", 5); /* Top & bottom margins */
246 putchar(t);
247 putchar(t >> 8);
248 putchar(n);
249 putchar(n >> 8);
250
251 if (header->HWResolution[1] == 720)
252 {
253 pwrite("\033(i\001\000\001", 6); /* Microweave */
254 pwrite("\033(e\002\000\000\001", 7); /* Small dots */
255 }
256
257 pwrite("\033(V\002\000\000\000", 7); /* Set absolute position 0 */
258
259 DotBytes = 0;
260 DotColumns = 0;
261 Shingling = 0;
262 break;
263 }
264
265 /*
266 * Set other stuff...
267 */
268
269 if (header->cupsColorSpace == CUPS_CSPACE_CMY)
270 NumPlanes = 3;
271 else if (header->cupsColorSpace == CUPS_CSPACE_KCMY)
272 NumPlanes = 4;
273 else if (header->cupsColorSpace == CUPS_CSPACE_KCMYcm)
274 NumPlanes = 6;
275 else
276 NumPlanes = 1;
277
278 Feed = 0; /* No blank lines yet */
279
280 /*
281 * Allocate memory for a line/row of graphics...
282 */
283
284 if ((Planes[0] = malloc(header->cupsBytesPerLine + NumPlanes)) == NULL)
285 {
286 fputs("ERROR: Unable to allocate memory\n", stderr);
287 exit(1);
288 }
289
290 for (plane = 1; plane < NumPlanes; plane ++)
291 Planes[plane] = Planes[0] + plane * header->cupsBytesPerLine / NumPlanes;
292
293 if (header->cupsCompression || DotBytes)
294 {
295 if ((CompBuffer = calloc(2, header->cupsWidth + 1)) == NULL)
296 {
297 fputs("ERROR: Unable to allocate memory\n", stderr);
298 exit(1);
299 }
300 }
301 else
302 CompBuffer = NULL;
303
304 if (DotBytes)
305 {
306 if ((LineBuffers[0] = calloc((size_t)DotBytes, (header->cupsWidth + 7) * (size_t)(Shingling + 1))) == NULL)
307 {
308 fputs("ERROR: Unable to allocate memory\n", stderr);
309 exit(1);
310 }
311
312 LineBuffers[1] = LineBuffers[0] + DotBytes * header->cupsWidth;
313 DotBit = 128;
314 LineCount = 0;
315 EvenOffset = 0;
316 OddOffset = 0;
317 }
318 }
319
320
321 /*
322 * 'EndPage()' - Finish a page of graphics.
323 */
324
325 void
EndPage(const cups_page_header2_t * header)326 EndPage(
327 const cups_page_header2_t *header) /* I - Page header */
328 {
329 if (DotBytes && header)
330 {
331 /*
332 * Flush remaining graphics as needed...
333 */
334
335 if (!Shingling)
336 {
337 if (DotBit < 128 || EvenOffset)
338 OutputRows(header, 0);
339 }
340 else if (OddOffset > EvenOffset)
341 {
342 OutputRows(header, 1);
343 OutputRows(header, 0);
344 }
345 else
346 {
347 OutputRows(header, 0);
348 OutputRows(header, 1);
349 }
350 }
351
352 /*
353 * Eject the current page...
354 */
355
356 putchar(12); /* Form feed */
357 fflush(stdout);
358
359 /*
360 * Free memory...
361 */
362
363 free(Planes[0]);
364
365 if (CompBuffer)
366 free(CompBuffer);
367
368 if (DotBytes)
369 free(LineBuffers[0]);
370 }
371
372
373 /*
374 * 'Shutdown()' - Shutdown the printer.
375 */
376
377 void
Shutdown(void)378 Shutdown(void)
379 {
380 /*
381 * Send a reset sequence.
382 */
383
384 printf("\033@");
385 }
386
387
388 /*
389 * 'CancelJob()' - Cancel the current job...
390 */
391
392 void
CancelJob(int sig)393 CancelJob(int sig) /* I - Signal */
394 {
395 (void)sig;
396
397 Canceled = 1;
398 }
399
400
401 /*
402 * 'CompressData()' - Compress a line of graphics.
403 */
404
405 void
CompressData(const unsigned char * line,unsigned length,unsigned plane,unsigned type,unsigned xstep,unsigned ystep)406 CompressData(const unsigned char *line, /* I - Data to compress */
407 unsigned length,/* I - Number of bytes */
408 unsigned plane, /* I - Color plane */
409 unsigned type, /* I - Type of compression */
410 unsigned xstep, /* I - X resolution */
411 unsigned ystep) /* I - Y resolution */
412 {
413 const unsigned char *line_ptr, /* Current byte pointer */
414 *line_end, /* End-of-line byte pointer */
415 *start; /* Start of compression sequence */
416 unsigned char *comp_ptr, /* Pointer into compression buffer */
417 temp; /* Current byte */
418 int count; /* Count of bytes for output */
419 static int ctable[6] = { 0, 2, 1, 4, 18, 17 };
420 /* KCMYcm color values */
421
422
423 /*
424 * Setup pointers...
425 */
426
427 line_ptr = line;
428 line_end = line + length;
429
430 /*
431 * Do depletion for 720 DPI printing...
432 */
433
434 if (ystep == 5)
435 {
436 for (comp_ptr = (unsigned char *)line; comp_ptr < line_end;)
437 {
438 /*
439 * Grab the current byte...
440 */
441
442 temp = *comp_ptr;
443
444 /*
445 * Check adjacent bits...
446 */
447
448 if ((temp & 0xc0) == 0xc0)
449 temp &= 0xbf;
450 if ((temp & 0x60) == 0x60)
451 temp &= 0xdf;
452 if ((temp & 0x30) == 0x30)
453 temp &= 0xef;
454 if ((temp & 0x18) == 0x18)
455 temp &= 0xf7;
456 if ((temp & 0x0c) == 0x0c)
457 temp &= 0xfb;
458 if ((temp & 0x06) == 0x06)
459 temp &= 0xfd;
460 if ((temp & 0x03) == 0x03)
461 temp &= 0xfe;
462
463 *comp_ptr++ = temp;
464
465 /*
466 * Check the last bit in the current byte...
467 */
468
469 if ((temp & 0x01) && comp_ptr < line_end)
470 *comp_ptr &= 0x7f;
471 }
472 }
473
474 switch (type)
475 {
476 case 0 :
477 /*
478 * Do no compression...
479 */
480 break;
481
482 case 1 :
483 /*
484 * Do TIFF pack-bits encoding...
485 */
486
487 comp_ptr = CompBuffer;
488
489 while (line_ptr < line_end)
490 {
491 if ((line_ptr + 1) >= line_end)
492 {
493 /*
494 * Single byte on the end...
495 */
496
497 *comp_ptr++ = 0x00;
498 *comp_ptr++ = *line_ptr++;
499 }
500 else if (line_ptr[0] == line_ptr[1])
501 {
502 /*
503 * Repeated sequence...
504 */
505
506 line_ptr ++;
507 count = 2;
508
509 while (line_ptr < (line_end - 1) &&
510 line_ptr[0] == line_ptr[1] &&
511 count < 127)
512 {
513 line_ptr ++;
514 count ++;
515 }
516
517 *comp_ptr++ = (unsigned char)(257 - count);
518 *comp_ptr++ = *line_ptr++;
519 }
520 else
521 {
522 /*
523 * Non-repeated sequence...
524 */
525
526 start = line_ptr;
527 line_ptr ++;
528 count = 1;
529
530 while (line_ptr < (line_end - 1) &&
531 line_ptr[0] != line_ptr[1] &&
532 count < 127)
533 {
534 line_ptr ++;
535 count ++;
536 }
537
538 *comp_ptr++ = (unsigned char)(count - 1);
539
540 memcpy(comp_ptr, start, (size_t)count);
541 comp_ptr += count;
542 }
543 }
544
545 line_ptr = CompBuffer;
546 line_end = comp_ptr;
547 break;
548 }
549
550 putchar(0x0d); /* Move print head to left margin */
551
552 if (Model < EPSON_ICOLOR)
553 {
554 /*
555 * Do graphics the "old" way...
556 */
557
558 if (NumPlanes > 1)
559 {
560 /*
561 * Set the color...
562 */
563
564 if (plane > 3)
565 printf("\033(r%c%c%c%c", 2, 0, 1, ctable[plane] & 15);
566 /* Set extended color */
567 else if (NumPlanes == 3)
568 printf("\033r%c", ctable[plane + 1]);
569 /* Set color */
570 else
571 printf("\033r%c", ctable[plane]); /* Set color */
572 }
573
574 /*
575 * Send a raster plane...
576 */
577
578 length *= 8;
579 printf("\033."); /* Raster graphics */
580 putchar((int)type);
581 putchar((int)ystep);
582 putchar((int)xstep);
583 putchar(1);
584 putchar((int)length);
585 putchar((int)(length >> 8));
586 }
587 else
588 {
589 /*
590 * Do graphics the "new" way...
591 */
592
593 printf("\033i");
594 putchar(ctable[plane]);
595 putchar((int)type);
596 putchar(1);
597 putchar((int)length);
598 putchar((int)(length >> 8));
599 putchar(1);
600 putchar(0);
601 }
602
603 pwrite(line_ptr, (size_t)(line_end - line_ptr));
604 fflush(stdout);
605 }
606
607
608 /*
609 * 'OutputLine()' - Output a line of graphics.
610 */
611
612 void
OutputLine(const cups_page_header2_t * header)613 OutputLine(
614 const cups_page_header2_t *header) /* I - Page header */
615 {
616 if (header->cupsRowCount)
617 {
618 unsigned width;
619 unsigned char *tempptr,
620 *evenptr,
621 *oddptr;
622 unsigned int x;
623 unsigned char bit;
624 const unsigned char *pixel;
625 unsigned char *temp;
626
627
628 /*
629 * Collect bitmap data in the line buffers and write after each buffer.
630 */
631
632 for (x = header->cupsWidth, bit = 128, pixel = Planes[0],
633 temp = CompBuffer;
634 x > 0;
635 x --, temp ++)
636 {
637 if (*pixel & bit)
638 *temp |= DotBit;
639
640 if (bit > 1)
641 bit >>= 1;
642 else
643 {
644 bit = 128;
645 pixel ++;
646 }
647 }
648
649 if (DotBit > 1)
650 DotBit >>= 1;
651 else
652 {
653 /*
654 * Copy the holding buffer to the output buffer, shingling as necessary...
655 */
656
657 if (Shingling && LineCount != 0)
658 {
659 /*
660 * Shingle the output...
661 */
662
663 if (LineCount & 1)
664 {
665 evenptr = LineBuffers[1] + OddOffset;
666 oddptr = LineBuffers[0] + EvenOffset + DotBytes;
667 }
668 else
669 {
670 evenptr = LineBuffers[0] + EvenOffset;
671 oddptr = LineBuffers[1] + OddOffset + DotBytes;
672 }
673
674 for (width = header->cupsWidth, tempptr = CompBuffer;
675 width > 1;
676 width -= 2, tempptr += 2, oddptr += DotBytes * 2,
677 evenptr += DotBytes * 2)
678 {
679 evenptr[0] = tempptr[0];
680 oddptr[0] = tempptr[1];
681 }
682
683 if (width == 1)
684 {
685 evenptr[0] = tempptr[0];
686 oddptr[0] = tempptr[1];
687 }
688 }
689 else
690 {
691 /*
692 * Don't shingle the output...
693 */
694
695 for (width = header->cupsWidth, tempptr = CompBuffer,
696 evenptr = LineBuffers[0] + EvenOffset;
697 width > 0;
698 width --, tempptr ++, evenptr += DotBytes)
699 *evenptr = tempptr[0];
700 }
701
702 if (Shingling && LineCount != 0)
703 {
704 EvenOffset ++;
705 OddOffset ++;
706
707 if (EvenOffset == DotBytes)
708 {
709 EvenOffset = 0;
710 OutputRows(header, 0);
711 }
712
713 if (OddOffset == DotBytes)
714 {
715 OddOffset = 0;
716 OutputRows(header, 1);
717 }
718 }
719 else
720 {
721 EvenOffset ++;
722
723 if (EvenOffset == DotBytes)
724 {
725 EvenOffset = 0;
726 OutputRows(header, 0);
727 }
728 }
729
730 DotBit = 128;
731 LineCount ++;
732
733 memset(CompBuffer, 0, header->cupsWidth);
734 }
735 }
736 else
737 {
738 unsigned plane; /* Current plane */
739 unsigned bytes; /* Bytes per plane */
740 unsigned xstep, ystep; /* X & Y resolutions */
741
742 /*
743 * Write a single line of bitmap data as needed...
744 */
745
746 xstep = 3600 / header->HWResolution[0];
747 ystep = 3600 / header->HWResolution[1];
748 bytes = header->cupsBytesPerLine / NumPlanes;
749
750 for (plane = 0; plane < NumPlanes; plane ++)
751 {
752 /*
753 * Skip blank data...
754 */
755
756 if (!Planes[plane][0] &&
757 memcmp(Planes[plane], Planes[plane] + 1, (size_t)bytes - 1) == 0)
758 continue;
759
760 /*
761 * Output whitespace as needed...
762 */
763
764 if (Feed > 0)
765 {
766 pwrite("\033(v\002\000", 5); /* Relative vertical position */
767 putchar((int)Feed);
768 putchar((int)(Feed >> 8));
769
770 Feed = 0;
771 }
772
773 CompressData(Planes[plane], bytes, plane, header->cupsCompression, xstep, ystep);
774 }
775
776 Feed ++;
777 }
778 }
779
780
781 /*
782 * 'OutputRows()' - Output 8, 24, or 48 rows.
783 */
784
785 void
OutputRows(const cups_page_header2_t * header,int row)786 OutputRows(
787 const cups_page_header2_t *header, /* I - Page image header */
788 int row) /* I - Row number (0 or 1) */
789 {
790 unsigned i, n, /* Looping vars */
791 dot_count, /* Number of bytes to print */
792 dot_min; /* Minimum number of bytes */
793 unsigned char *dot_ptr, /* Pointer to print data */
794 *ptr; /* Current data */
795
796
797 dot_min = DotBytes * DotColumns;
798
799 if (LineBuffers[row][0] != 0 ||
800 memcmp(LineBuffers[row], LineBuffers[row] + 1, header->cupsWidth * DotBytes - 1))
801 {
802 /*
803 * Skip leading space...
804 */
805
806 i = 0;
807 dot_count = header->cupsWidth * DotBytes;
808 dot_ptr = LineBuffers[row];
809
810 while (dot_count >= dot_min && dot_ptr[0] == 0 &&
811 memcmp(dot_ptr, dot_ptr + 1, dot_min - 1) == 0)
812 {
813 i ++;
814 dot_ptr += dot_min;
815 dot_count -= dot_min;
816 }
817
818 /*
819 * Skip trailing space...
820 */
821
822 while (dot_count >= dot_min && dot_ptr[dot_count - dot_min] == 0 &&
823 memcmp(dot_ptr + dot_count - dot_min,
824 dot_ptr + dot_count - dot_min + 1, dot_min - 1) == 0)
825 dot_count -= dot_min;
826
827 /*
828 * Position print head for printing...
829 */
830
831 if (i == 0)
832 putchar('\r');
833 else
834 {
835 putchar(0x1b);
836 putchar('$');
837 putchar((int)(i & 255));
838 putchar((int)(i >> 8));
839 }
840
841 /*
842 * Start bitmap graphics for this line...
843 */
844
845 printf("\033*"); /* Select bit image */
846 switch (header->HWResolution[0])
847 {
848 case 60 : /* 60x60/72 DPI gfx */
849 putchar(0);
850 break;
851 case 120 : /* 120x60/72 DPI gfx */
852 putchar(1);
853 break;
854 case 180 : /* 180 DPI gfx */
855 putchar(39);
856 break;
857 case 240 : /* 240x72 DPI gfx */
858 putchar(3);
859 break;
860 case 360 : /* 360x180/360 DPI gfx */
861 if (header->HWResolution[1] == 180)
862 {
863 if (Shingling && LineCount != 0)
864 putchar(40); /* 360x180 fast */
865 else
866 putchar(41); /* 360x180 slow */
867 }
868 else
869 {
870 if (Shingling && LineCount != 0)
871 putchar(72); /* 360x360 fast */
872 else
873 putchar(73); /* 360x360 slow */
874 }
875 break;
876 }
877
878 n = dot_count / DotBytes;
879 putchar((int)(n & 255));
880 putchar((int)(n / 256));
881
882 /*
883 * Write the graphics data...
884 */
885
886 if (header->HWResolution[0] == 120 ||
887 header->HWResolution[0] == 240)
888 {
889 /*
890 * Need to interleave the dots to avoid hosing the print head...
891 */
892
893 for (n = dot_count / 2, ptr = dot_ptr; n > 0; n --, ptr += 2)
894 {
895 putchar(*ptr);
896 putchar(0);
897 }
898
899 if (dot_count & 1)
900 putchar(*ptr);
901
902 /*
903 * Move the head back and print the odd bytes...
904 */
905
906 if (i == 0)
907 putchar('\r');
908 else
909 {
910 putchar(0x1b);
911 putchar('$');
912 putchar((int)(i & 255));
913 putchar((int)(i >> 8));
914 }
915
916 if (header->HWResolution[0] == 120)
917 printf("\033*\001"); /* Select bit image */
918 else
919 printf("\033*\003"); /* Select bit image */
920
921 n = (unsigned)dot_count / DotBytes;
922 putchar((int)(n & 255));
923 putchar((int)(n / 256));
924
925 for (n = dot_count / 2, ptr = dot_ptr + 1; n > 0; n --, ptr += 2)
926 {
927 putchar(0);
928 putchar(*ptr);
929 }
930
931 if (dot_count & 1)
932 putchar(0);
933 }
934 else
935 pwrite(dot_ptr, dot_count);
936 }
937
938 /*
939 * Feed the paper...
940 */
941
942 putchar('\n');
943
944 if (Shingling && row == 1)
945 {
946 if (header->HWResolution[1] == 360)
947 printf("\n\n\n\n");
948 else
949 printf("\n");
950 }
951
952 fflush(stdout);
953
954 /*
955 * Clear the buffer...
956 */
957
958 memset(LineBuffers[row], 0, (size_t)header->cupsWidth * (size_t)DotBytes);
959 }
960
961
962 /*
963 * 'main()' - Main entry and processing of driver.
964 */
965
966 int /* O - Exit status */
main(int argc,char * argv[])967 main(int argc, /* I - Number of command-line arguments */
968 char *argv[]) /* I - Command-line arguments */
969 {
970 int fd; /* File descriptor */
971 cups_raster_t *ras; /* Raster stream for printing */
972 cups_page_header2_t header; /* Page header from file */
973 ppd_file_t *ppd; /* PPD file */
974 int page; /* Current page */
975 unsigned y; /* Current line */
976 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
977 struct sigaction action; /* Actions for POSIX signals */
978 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
979
980
981 /*
982 * Make sure status messages are not buffered...
983 */
984
985 setbuf(stderr, NULL);
986
987 /*
988 * Check command-line...
989 */
990
991 if (argc != 6 && argc != 7)
992 {
993 /*
994 * We don't have the correct number of arguments; write an error message
995 * and return.
996 */
997
998 _cupsLangPrintFilter(stderr, "ERROR",
999 _("%s job-id user title copies options [file]"),
1000 "rastertoepson");
1001 return (1);
1002 }
1003
1004 /*
1005 * Open the page stream...
1006 */
1007
1008 if (argc == 7)
1009 {
1010 if ((fd = open(argv[6], O_RDONLY)) == -1)
1011 {
1012 _cupsLangPrintError("ERROR", _("Unable to open raster file"));
1013 sleep(1);
1014 return (1);
1015 }
1016 }
1017 else
1018 fd = 0;
1019
1020 ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
1021
1022 /*
1023 * Register a signal handler to eject the current page if the
1024 * job is cancelled.
1025 */
1026
1027 Canceled = 0;
1028
1029 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1030 sigset(SIGTERM, CancelJob);
1031 #elif defined(HAVE_SIGACTION)
1032 memset(&action, 0, sizeof(action));
1033
1034 sigemptyset(&action.sa_mask);
1035 action.sa_handler = CancelJob;
1036 sigaction(SIGTERM, &action, NULL);
1037 #else
1038 signal(SIGTERM, CancelJob);
1039 #endif /* HAVE_SIGSET */
1040
1041 /*
1042 * Initialize the print device...
1043 */
1044
1045 ppd = ppdOpenFile(getenv("PPD"));
1046 if (!ppd)
1047 {
1048 ppd_status_t status; /* PPD error */
1049 int linenum; /* Line number */
1050
1051 _cupsLangPrintFilter(stderr, "ERROR",
1052 _("The PPD file could not be opened."));
1053
1054 status = ppdLastError(&linenum);
1055
1056 fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum);
1057
1058 return (1);
1059 }
1060
1061 Model = ppd->model_number;
1062
1063 Setup();
1064
1065 /*
1066 * Process pages as needed...
1067 */
1068
1069 page = 0;
1070
1071 while (cupsRasterReadHeader2(ras, &header))
1072 {
1073 /*
1074 * Write a status message with the page number and number of copies.
1075 */
1076
1077 if (Canceled)
1078 break;
1079
1080 page ++;
1081
1082 fprintf(stderr, "PAGE: %d %d\n", page, header.NumCopies);
1083 _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), page);
1084
1085 /*
1086 * Start the page...
1087 */
1088
1089 StartPage(ppd, &header);
1090
1091 /*
1092 * Loop for each line on the page...
1093 */
1094
1095 for (y = 0; y < header.cupsHeight; y ++)
1096 {
1097 /*
1098 * Let the user know how far we have progressed...
1099 */
1100
1101 if (Canceled)
1102 break;
1103
1104 if ((y & 127) == 0)
1105 {
1106 _cupsLangPrintFilter(stderr, "INFO",
1107 _("Printing page %d, %u%% complete."),
1108 page, 100 * y / header.cupsHeight);
1109 fprintf(stderr, "ATTR: job-media-progress=%u\n",
1110 100 * y / header.cupsHeight);
1111 }
1112
1113 /*
1114 * Read a line of graphics...
1115 */
1116
1117 if (cupsRasterReadPixels(ras, Planes[0], header.cupsBytesPerLine) < 1)
1118 break;
1119
1120 /*
1121 * Write it to the printer...
1122 */
1123
1124 OutputLine(&header);
1125 }
1126
1127 /*
1128 * Eject the page...
1129 */
1130
1131 _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), page);
1132
1133 EndPage(&header);
1134
1135 if (Canceled)
1136 break;
1137 }
1138
1139 /*
1140 * Shutdown the printer...
1141 */
1142
1143 Shutdown();
1144
1145 ppdClose(ppd);
1146
1147 /*
1148 * Close the raster stream...
1149 */
1150
1151 cupsRasterClose(ras);
1152 if (fd != 0)
1153 close(fd);
1154
1155 /*
1156 * If no pages were printed, send an error message...
1157 */
1158
1159 if (page == 0)
1160 {
1161 _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found."));
1162 return (1);
1163 }
1164 else
1165 return (0);
1166 }
1167