]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/rastertolabel.c
Merge changes from CUPS 1.4svn-r7394.
[thirdparty/cups.git] / filter / rastertolabel.c
1 /*
2 * "$Id: rastertolabel.c 6819 2007-08-20 21:11:57Z mike $"
3 *
4 * Label printer filter for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 2001-2007 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 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
19 * Setup() - Prepare the printer for printing.
20 * StartPage() - Start a page of graphics.
21 * EndPage() - Finish a page of graphics.
22 * CancelJob() - Cancel the current job...
23 * OutputLine() - Output a line of graphics.
24 * PCLCompress() - Output a PCL (mode 3) compressed line.
25 * ZPLCompress() - Output a run-length compression sequence.
26 * main() - Main entry and processing of driver.
27 */
28
29 /*
30 * Include necessary headers...
31 */
32
33 #include <cups/cups.h>
34 #include <cups/string.h>
35 #include <cups/i18n.h>
36 #include <cups/raster.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <signal.h>
41
42
43 /*
44 * This driver filter currently supports Dymo, Intellitech, and Zebra
45 * label printers.
46 *
47 * The Dymo portion of the driver has been tested with the 300, 330,
48 * and 330 Turbo label printers; it may also work with other models.
49 * The Dymo printers support printing at 136, 203, and 300 DPI.
50 *
51 * The Intellitech portion of the driver has been tested with the
52 * Intellibar 408, 412, and 808 and supports their PCL variant.
53 *
54 * The Zebra portion of the driver has been tested with the LP-2844,
55 * LP-2844Z, QL-320, and QL-420 label printers; it may also work with
56 * other models. The driver supports EPL line mode, EPL page mode,
57 * ZPL, and CPCL as defined in Zebra's on-line developer documentation.
58 */
59
60 /*
61 * Model number constants...
62 */
63
64 #define DYMO_3x0 0 /* Dymo Labelwriter 300/330/330 Turbo */
65
66 #define ZEBRA_EPL_LINE 0x10 /* Zebra EPL line mode printers */
67 #define ZEBRA_EPL_PAGE 0x11 /* Zebra EPL page mode printers */
68 #define ZEBRA_ZPL 0x12 /* Zebra ZPL-based printers */
69 #define ZEBRA_CPCL 0x13 /* Zebra CPCL-based printers */
70
71 #define INTELLITECH_PCL 0x20 /* Intellitech PCL-based printers */
72
73
74 /*
75 * Globals...
76 */
77
78 unsigned char *Buffer; /* Output buffer */
79 unsigned char *CompBuffer; /* Compression buffer */
80 unsigned char *LastBuffer; /* Last buffer */
81 int LastSet; /* Number of repeat characters */
82 int ModelNumber, /* cupsModelNumber attribute */
83 Page, /* Current page */
84 Feed, /* Number of lines to skip */
85 Canceled; /* Non-zero if job is canceled */
86
87
88 /*
89 * Prototypes...
90 */
91
92 void Setup(ppd_file_t *ppd);
93 void StartPage(ppd_file_t *ppd, cups_page_header2_t *header);
94 void EndPage(ppd_file_t *ppd, cups_page_header2_t *header);
95 void CancelJob(int sig);
96 void OutputLine(ppd_file_t *ppd, cups_page_header2_t *header, int y);
97 void PCLCompress(unsigned char *line, int length);
98 void ZPLCompress(char repeat_char, int repeat_count);
99
100
101 /*
102 * 'Setup()' - Prepare the printer for printing.
103 */
104
105 void
106 Setup(ppd_file_t *ppd) /* I - PPD file */
107 {
108 int i; /* Looping var */
109
110
111 /*
112 * Get the model number from the PPD file...
113 */
114
115 if (ppd)
116 ModelNumber = ppd->model_number;
117
118 /*
119 * Initialize based on the model number...
120 */
121
122 switch (ModelNumber)
123 {
124 case DYMO_3x0 :
125 /*
126 * Clear any remaining data...
127 */
128
129 for (i = 0; i < 100; i ++)
130 putchar(0x1b);
131
132 /*
133 * Reset the printer...
134 */
135
136 fputs("\033@", stdout);
137 break;
138
139 case ZEBRA_EPL_LINE :
140 break;
141
142 case ZEBRA_EPL_PAGE :
143 break;
144
145 case ZEBRA_ZPL :
146 break;
147
148 case ZEBRA_CPCL :
149 break;
150
151 case INTELLITECH_PCL :
152 /*
153 * Send a PCL reset sequence.
154 */
155
156 putchar(0x1b);
157 putchar('E');
158 break;
159 }
160 }
161
162
163 /*
164 * 'StartPage()' - Start a page of graphics.
165 */
166
167 void
168 StartPage(ppd_file_t *ppd, /* I - PPD file */
169 cups_page_header2_t *header) /* I - Page header */
170 {
171 ppd_choice_t *choice; /* Marked choice */
172 int length; /* Actual label length */
173
174
175 /*
176 * Show page device dictionary...
177 */
178
179 fprintf(stderr, "DEBUG: StartPage...\n");
180 fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass);
181 fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor);
182 fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType);
183 fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType);
184
185 fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance);
186 fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia);
187 fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate);
188 fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia);
189 fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex);
190 fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0],
191 header->HWResolution[1]);
192 fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n",
193 header->ImagingBoundingBox[0], header->ImagingBoundingBox[1],
194 header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]);
195 fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet);
196 fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog);
197 fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge);
198 fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0],
199 header->Margins[1]);
200 fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed);
201 fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition);
202 fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight);
203 fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint);
204 fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint);
205 fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies);
206 fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation);
207 fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp);
208 fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0],
209 header->PageSize[1]);
210 fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations);
211 fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch);
212 fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble);
213 fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth);
214 fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight);
215 fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType);
216 fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header->cupsBitsPerColor);
217 fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header->cupsBitsPerPixel);
218 fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header->cupsBytesPerLine);
219 fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header->cupsColorOrder);
220 fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header->cupsColorSpace);
221 fprintf(stderr, "DEBUG: cupsCompression = %d\n", header->cupsCompression);
222 fprintf(stderr, "DEBUG: cupsRowCount = %d\n", header->cupsRowCount);
223 fprintf(stderr, "DEBUG: cupsRowFeed = %d\n", header->cupsRowFeed);
224 fprintf(stderr, "DEBUG: cupsRowStep = %d\n", header->cupsRowStep);
225
226 switch (ModelNumber)
227 {
228 case DYMO_3x0 :
229 /*
230 * Setup printer/job attributes...
231 */
232
233 length = header->PageSize[1] * header->HWResolution[1] / 72;
234
235 printf("\033L%c%c", length >> 8, length);
236 printf("\033D%c", header->cupsBytesPerLine);
237
238 printf("\033%c", header->cupsCompression + 'c'); /* Darkness */
239 break;
240
241 case ZEBRA_EPL_LINE :
242 /*
243 * Set print rate...
244 */
245
246 if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL &&
247 strcmp(choice->choice, "Default"))
248 printf("\033S%.0f", atof(choice->choice) * 2.0 - 2.0);
249
250 /*
251 * Set darkness...
252 */
253
254 if (header->cupsCompression > 0 && header->cupsCompression <= 100)
255 printf("\033D%d", 7 * header->cupsCompression / 100);
256
257 /*
258 * Set left margin to 0...
259 */
260
261 fputs("\033M01", stdout);
262
263 /*
264 * Start buffered output...
265 */
266
267 fputs("\033B", stdout);
268 break;
269
270 case ZEBRA_EPL_PAGE :
271 /*
272 * Start a new label...
273 */
274
275 puts("");
276 puts("N");
277
278 /*
279 * Set hardware options...
280 */
281
282 if (!strcmp(header->MediaType, "Direct"))
283 puts("OD");
284
285 /*
286 * Set print rate...
287 */
288
289 if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL &&
290 strcmp(choice->choice, "Default"))
291 {
292 float val = atof(choice->choice);
293
294 if (val >= 3.0)
295 printf("S%.0f\n", val);
296 else
297 printf("S%.0f\n", val * 2.0 - 2.0);
298 }
299
300 /*
301 * Set darkness...
302 */
303
304 if (header->cupsCompression > 0 && header->cupsCompression <= 100)
305 printf("D%d\n", 15 * header->cupsCompression / 100);
306
307 /*
308 * Set label size...
309 */
310
311 printf("q%d\n", (header->cupsWidth + 7) & ~7);
312 break;
313
314 case ZEBRA_ZPL :
315 /*
316 * Set darkness...
317 */
318
319 if (header->cupsCompression > 0 && header->cupsCompression <= 100)
320 printf("~SD%02d\n", 30 * header->cupsCompression / 100);
321
322 /*
323 * Start bitmap graphics...
324 */
325
326 printf("~DGR:CUPS.GRF,%d,%d,\n",
327 header->cupsHeight * header->cupsBytesPerLine,
328 header->cupsBytesPerLine);
329
330 /*
331 * Allocate compression buffers...
332 */
333
334 CompBuffer = malloc(2 * header->cupsBytesPerLine + 1);
335 LastBuffer = malloc(header->cupsBytesPerLine);
336 LastSet = 0;
337 break;
338
339 case ZEBRA_CPCL :
340 /*
341 * Start label...
342 */
343
344 printf("! 0 %u %u %u %u\r\n", header->HWResolution[0],
345 header->HWResolution[1], header->cupsHeight,
346 header->NumCopies);
347 printf("PAGE-WIDTH %d\r\n", header->cupsWidth);
348 printf("PAGE-HEIGHT %d\r\n", header->cupsWidth);
349 break;
350
351 case INTELLITECH_PCL :
352 /*
353 * Set the media size...
354 */
355
356 printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */
357 printf("\033&l0O"); /* Set portrait orientation */
358
359 switch (header->PageSize[1])
360 {
361 case 540 : /* Monarch Envelope */
362 printf("\033&l80A"); /* Set page size */
363 break;
364
365 case 624 : /* DL Envelope */
366 printf("\033&l90A"); /* Set page size */
367 break;
368
369 case 649 : /* C5 Envelope */
370 printf("\033&l91A"); /* Set page size */
371 break;
372
373 case 684 : /* COM-10 Envelope */
374 printf("\033&l81A"); /* Set page size */
375 break;
376
377 case 756 : /* Executive */
378 printf("\033&l1A"); /* Set page size */
379 break;
380
381 case 792 : /* Letter */
382 printf("\033&l2A"); /* Set page size */
383 break;
384
385 case 842 : /* A4 */
386 printf("\033&l26A"); /* Set page size */
387 break;
388
389 case 1008 : /* Legal */
390 printf("\033&l3A"); /* Set page size */
391 break;
392
393 default : /* Custom size */
394 printf("\033!f%dZ", header->PageSize[1] * 300 / 72);
395 break;
396 }
397
398 printf("\033&l%dP", /* Set page length */
399 header->PageSize[1] / 12);
400 printf("\033&l0E"); /* Set top margin to 0 */
401 printf("\033&l%dX", header->NumCopies);
402 /* Set number copies */
403 printf("\033&l0L"); /* Turn off perforation skip */
404
405 /*
406 * Print settings...
407 */
408
409 if (Page == 1)
410 {
411 if (header->cupsRowFeed) /* inPrintRate */
412 printf("\033!p%dS", header->cupsRowFeed);
413
414 if (header->cupsCompression != ~0)
415 /* inPrintDensity */
416 printf("\033&d%dA", 30 * header->cupsCompression / 100 - 15);
417
418 if ((choice = ppdFindMarkedChoice(ppd, "inPrintMode")) != NULL)
419 {
420 if (!strcmp(choice->choice, "Standard"))
421 fputs("\033!p0M", stdout);
422 else if (!strcmp(choice->choice, "Tear"))
423 {
424 fputs("\033!p1M", stdout);
425
426 if (header->cupsRowCount) /* inTearInterval */
427 printf("\033!n%dT", header->cupsRowCount);
428 }
429 else
430 {
431 fputs("\033!p2M", stdout);
432
433 if (header->cupsRowStep) /* inCutInterval */
434 printf("\033!n%dC", header->cupsRowStep);
435 }
436 }
437 }
438
439 /*
440 * Setup graphics...
441 */
442
443 printf("\033*t%dR", header->HWResolution[0]);
444 /* Set resolution */
445
446 printf("\033*r%dS", header->cupsWidth);
447 /* Set width */
448 printf("\033*r%dT", header->cupsHeight);
449 /* Set height */
450
451 printf("\033&a0H"); /* Set horizontal position */
452 printf("\033&a0V"); /* Set vertical position */
453 printf("\033*r1A"); /* Start graphics */
454 printf("\033*b3M"); /* Set compression */
455
456 /*
457 * Allocate compression buffers...
458 */
459
460 CompBuffer = malloc(2 * header->cupsBytesPerLine + 1);
461 LastBuffer = malloc(header->cupsBytesPerLine);
462 LastSet = 0;
463 break;
464 }
465
466 /*
467 * Allocate memory for a line of graphics...
468 */
469
470 Buffer = malloc(header->cupsBytesPerLine);
471 Feed = 0;
472 }
473
474
475 /*
476 * 'EndPage()' - Finish a page of graphics.
477 */
478
479 void
480 EndPage(ppd_file_t *ppd, /* I - PPD file */
481 cups_page_header2_t *header) /* I - Page header */
482 {
483 int val; /* Option value */
484 ppd_choice_t *choice; /* Marked choice */
485 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
486 struct sigaction action; /* Actions for POSIX signals */
487 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
488
489
490 switch (ModelNumber)
491 {
492 case DYMO_3x0 :
493 /*
494 * Eject the current page...
495 */
496
497 fputs("\033E", stdout);
498 break;
499
500 case ZEBRA_EPL_LINE :
501 /*
502 * End buffered output, eject the label...
503 */
504
505 fputs("\033E\014", stdout);
506 break;
507
508 case ZEBRA_EPL_PAGE :
509 /*
510 * Print the label...
511 */
512
513 puts("P1");
514 break;
515
516 case ZEBRA_ZPL :
517 if (Canceled)
518 {
519 /*
520 * Cancel bitmap download...
521 */
522
523 puts("~DN");
524 break;
525 }
526
527 /*
528 * Start label...
529 */
530
531 puts("^XA");
532
533 /*
534 * Set print rate...
535 */
536
537 if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL &&
538 strcmp(choice->choice, "Default"))
539 {
540 val = atoi(choice->choice);
541 printf("^PR%d,%d,%d\n", val, val, val);
542 }
543
544 /*
545 * Put label home in default position (0,0)...
546 */
547
548 printf("^LH0,0\n");
549
550 /*
551 * Set media tracking...
552 */
553
554 if (ppdIsMarked(ppd, "zeMediaTracking", "Continuous"))
555 {
556 /*
557 * Add label length command for continuous...
558 */
559
560 printf("^LL%d\n", header->cupsHeight);
561 printf("^MNN\n");
562 }
563 else if (ppdIsMarked(ppd, "zeMediaTracking", "Web"))
564 printf("^MNY\n");
565 else if (ppdIsMarked(ppd, "zeMediaTracking", "Mark"))
566 printf("^MNM\n");
567
568 /*
569 * Set label top
570 */
571
572 if (header->cupsRowStep != 200)
573 printf("^LT%u\n", header->cupsRowStep);
574
575 /*
576 * Set media type...
577 */
578
579 if (!strcmp(header->MediaType, "Thermal"))
580 printf("^MTT\n");
581 else if (!strcmp(header->MediaType, "Direct"))
582 printf("^MTD\n");
583
584 /*
585 * Set print mode...
586 */
587
588 if ((choice = ppdFindMarkedChoice(ppd, "zePrintMode")) != NULL &&
589 strcmp(choice->choice, "Saved"))
590 {
591 printf("^MM");
592
593 if (!strcmp(choice->choice, "Tear"))
594 printf("T,Y\n");
595 else if (!strcmp(choice->choice, "Peel"))
596 printf("P,Y\n");
597 else if (!strcmp(choice->choice, "Rewind"))
598 printf("R,Y\n");
599 else if (!strcmp(choice->choice, "Applicator"))
600 printf("A,Y\n");
601 else
602 printf("C,Y\n");
603 }
604
605 /*
606 * Set tear-off adjust position...
607 */
608
609 if (header->AdvanceDistance != 1000)
610 {
611 if ((int)header->AdvanceDistance < 0)
612 printf("~TA%04d\n", (int)header->AdvanceDistance);
613 else
614 printf("~TA%03d\n", (int)header->AdvanceDistance);
615 }
616
617 /*
618 * Allow for reprinting after an error...
619 */
620
621 if (ppdIsMarked(ppd, "zeErrorReprint", "Always"))
622 printf("^JZY\n");
623 else if (ppdIsMarked(ppd, "zeErrorReprint", "Never"))
624 printf("^JZN\n");
625
626 /*
627 * Print multiple copies
628 */
629
630 if (header->NumCopies > 1)
631 printf("^PQ%d, 0, 0, N\n", header->NumCopies);
632
633 /*
634 * Display the label image...
635 */
636
637 puts("^FO0,0^XGR:CUPS.GRF,1,1^FS");
638
639 /*
640 * End the label and eject...
641 */
642
643 puts("^IDR:CUPS.GRF^FS");
644 puts("^XZ");
645
646 /*
647 * Free compression buffers...
648 */
649
650 free(CompBuffer);
651 free(LastBuffer);
652 break;
653
654 case ZEBRA_CPCL :
655 /*
656 * Set tear-off adjust position...
657 */
658
659 if (header->AdvanceDistance != 1000)
660 printf("PRESENT-AT %d 1\r\n", (int)header->AdvanceDistance);
661
662 /*
663 * Allow for reprinting after an error...
664 */
665
666 if (ppdIsMarked(ppd, "zeErrorReprint", "Always"))
667 puts("ON-OUT-OF-PAPER WAIT\r");
668 else if (ppdIsMarked(ppd, "zeErrorReprint", "Never"))
669 puts("ON-OUT-OF-PAPER PURGE\r");
670
671 /*
672 * Cut label?
673 */
674
675 if (header->CutMedia)
676 puts("CUT\r");
677
678 /*
679 * Set darkness...
680 */
681
682 if (header->cupsCompression > 0)
683 printf("TONE %u\r\n", 2 * header->cupsCompression);
684
685 /*
686 * Set print rate...
687 */
688
689 if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL &&
690 strcmp(choice->choice, "Default"))
691 {
692 val = atoi(choice->choice);
693 printf("SPEED %d\r\n", val);
694 }
695
696 /*
697 * Print the label...
698 */
699
700 if ((choice = ppdFindMarkedChoice(ppd, "zeMediaTracking")) == NULL ||
701 strcmp(choice->choice, "Continuous"))
702 puts("FORM\r");
703
704 puts("PRINT\r");
705 break;
706
707 case INTELLITECH_PCL :
708 printf("\033*rB"); /* End GFX */
709 printf("\014"); /* Eject current page */
710 break;
711 }
712
713 fflush(stdout);
714
715 /*
716 * Free memory...
717 */
718
719 free(Buffer);
720 }
721
722
723 /*
724 * 'CancelJob()' - Cancel the current job...
725 */
726
727 void
728 CancelJob(int sig) /* I - Signal */
729 {
730 /*
731 * Tell the main loop to stop...
732 */
733
734 (void)sig;
735
736 Canceled = 1;
737 }
738
739
740 /*
741 * 'OutputLine()' - Output a line of graphics...
742 */
743
744 void
745 OutputLine(ppd_file_t *ppd, /* I - PPD file */
746 cups_page_header2_t *header, /* I - Page header */
747 int y) /* I - Line number */
748 {
749 int i; /* Looping var */
750 unsigned char *ptr; /* Pointer into buffer */
751 unsigned char *compptr; /* Pointer into compression buffer */
752 char repeat_char; /* Repeated character */
753 int repeat_count; /* Number of repeated characters */
754 static const char *hex = "0123456789ABCDEF";
755 /* Hex digits */
756
757
758 switch (ModelNumber)
759 {
760 case DYMO_3x0 :
761 /*
762 * See if the line is blank; if not, write it to the printer...
763 */
764
765 if (Buffer[0] ||
766 memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine - 1))
767 {
768 if (Feed)
769 {
770 while (Feed > 255)
771 {
772 printf("\033f\001%c", 255);
773 Feed -= 255;
774 }
775
776 printf("\033f\001%c", Feed);
777 Feed = 0;
778 }
779
780 putchar(0x16);
781 fwrite(Buffer, header->cupsBytesPerLine, 1, stdout);
782 fflush(stdout);
783
784 #ifdef __sgi
785 /*
786 * This hack works around a bug in the IRIX serial port driver when
787 * run at high baud rates (e.g. 115200 baud)... This results in
788 * slightly slower label printing, but at least the labels come
789 * out properly.
790 */
791
792 sginap(1);
793 #endif /* __sgi */
794 }
795 else
796 Feed ++;
797 break;
798
799 case ZEBRA_EPL_LINE :
800 printf("\033g%03d", header->cupsBytesPerLine);
801 fwrite(Buffer, 1, header->cupsBytesPerLine, stdout);
802 fflush(stdout);
803 break;
804
805 case ZEBRA_EPL_PAGE :
806 if (Buffer[0] || memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine))
807 {
808 printf("GW0,%d,%d,1\n", y, header->cupsBytesPerLine);
809 for (i = header->cupsBytesPerLine, ptr = Buffer; i > 0; i --, ptr ++)
810 putchar(~*ptr);
811 putchar('\n');
812 fflush(stdout);
813 }
814 break;
815
816 case ZEBRA_ZPL :
817 /*
818 * Determine if this row is the same as the previous line.
819 * If so, output a ':' and return...
820 */
821
822 if (LastSet)
823 {
824 if (!memcmp(Buffer, LastBuffer, header->cupsBytesPerLine))
825 {
826 putchar(':');
827 return;
828 }
829 }
830
831 /*
832 * Convert the line to hex digits...
833 */
834
835 for (ptr = Buffer, compptr = CompBuffer, i = header->cupsBytesPerLine;
836 i > 0;
837 i --, ptr ++)
838 {
839 *compptr++ = hex[*ptr >> 4];
840 *compptr++ = hex[*ptr & 15];
841 }
842
843 *compptr = '\0';
844
845 /*
846 * Run-length compress the graphics...
847 */
848
849 for (compptr = CompBuffer + 1, repeat_char = CompBuffer[0], repeat_count = 1;
850 *compptr;
851 compptr ++)
852 if (*compptr == repeat_char)
853 repeat_count ++;
854 else
855 {
856 ZPLCompress(repeat_char, repeat_count);
857 repeat_char = *compptr;
858 repeat_count = 1;
859 }
860
861 if (repeat_char == '0')
862 {
863 /*
864 * Handle 0's on the end of the line...
865 */
866
867 if (repeat_count & 1)
868 {
869 repeat_count --;
870 putchar('0');
871 }
872
873 if (repeat_count > 0)
874 putchar(',');
875 }
876 else
877 ZPLCompress(repeat_char, repeat_count);
878
879 fflush(stdout);
880
881 /*
882 * Save this line for the next round...
883 */
884
885 memcpy(LastBuffer, Buffer, header->cupsBytesPerLine);
886 LastSet = 1;
887 break;
888
889 case ZEBRA_CPCL :
890 if (Buffer[0] || memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine))
891 {
892 printf("CG %u 1 0 %d ", header->cupsBytesPerLine, y);
893 fwrite(Buffer, 1, header->cupsBytesPerLine, stdout);
894 puts("\r");
895 fflush(stdout);
896 }
897 break;
898
899 case INTELLITECH_PCL :
900 if (Buffer[0] ||
901 memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine - 1))
902 {
903 if (Feed)
904 {
905 printf("\033*b%dY", Feed);
906 Feed = 0;
907 LastSet = 0;
908 }
909
910 PCLCompress(Buffer, header->cupsBytesPerLine);
911 }
912 else
913 Feed ++;
914 break;
915 }
916 }
917
918
919 /*
920 * 'PCLCompress()' - Output a PCL (mode 3) compressed line.
921 */
922
923 void
924 PCLCompress(unsigned char *line, /* I - Line to compress */
925 int length) /* I - Length of line */
926 {
927 unsigned char *line_ptr, /* Current byte pointer */
928 *line_end, /* End-of-line byte pointer */
929 *comp_ptr, /* Pointer into compression buffer */
930 *start, /* Start of compression sequence */
931 *seed; /* Seed buffer pointer */
932 int count, /* Count of bytes for output */
933 offset; /* Offset of bytes for output */
934
935
936 /*
937 * Do delta-row compression...
938 */
939
940 line_ptr = line;
941 line_end = line + length;
942
943 comp_ptr = CompBuffer;
944 seed = LastBuffer;
945
946 while (line_ptr < line_end)
947 {
948 /*
949 * Find the next non-matching sequence...
950 */
951
952 start = line_ptr;
953
954 if (!LastSet)
955 {
956 /*
957 * The seed buffer is invalid, so do the next 8 bytes, max...
958 */
959
960 offset = 0;
961
962 if ((count = line_end - line_ptr) > 8)
963 count = 8;
964
965 line_ptr += count;
966 }
967 else
968 {
969 /*
970 * The seed buffer is valid, so compare against it...
971 */
972
973 while (*line_ptr == *seed &&
974 line_ptr < line_end)
975 {
976 line_ptr ++;
977 seed ++;
978 }
979
980 if (line_ptr == line_end)
981 break;
982
983 offset = line_ptr - start;
984
985 /*
986 * Find up to 8 non-matching bytes...
987 */
988
989 start = line_ptr;
990 count = 0;
991 while (*line_ptr != *seed &&
992 line_ptr < line_end &&
993 count < 8)
994 {
995 line_ptr ++;
996 seed ++;
997 count ++;
998 }
999 }
1000
1001 /*
1002 * Place mode 3 compression data in the buffer; see HP manuals
1003 * for details...
1004 */
1005
1006 if (offset >= 31)
1007 {
1008 /*
1009 * Output multi-byte offset...
1010 */
1011
1012 *comp_ptr++ = ((count - 1) << 5) | 31;
1013
1014 offset -= 31;
1015 while (offset >= 255)
1016 {
1017 *comp_ptr++ = 255;
1018 offset -= 255;
1019 }
1020
1021 *comp_ptr++ = offset;
1022 }
1023 else
1024 {
1025 /*
1026 * Output single-byte offset...
1027 */
1028
1029 *comp_ptr++ = ((count - 1) << 5) | offset;
1030 }
1031
1032 memcpy(comp_ptr, start, count);
1033 comp_ptr += count;
1034 }
1035
1036 line_ptr = CompBuffer;
1037 line_end = comp_ptr;
1038
1039 /*
1040 * Set the length of the data and write it...
1041 */
1042
1043 printf("\033*b%dW", (int)(comp_ptr - CompBuffer));
1044 fwrite(CompBuffer, comp_ptr - CompBuffer, 1, stdout);
1045
1046 /*
1047 * Save this line as a "seed" buffer for the next...
1048 */
1049
1050 memcpy(LastBuffer, line, length);
1051 LastSet = 1;
1052 }
1053
1054
1055 /*
1056 * 'ZPLCompress()' - Output a run-length compression sequence.
1057 */
1058
1059 void
1060 ZPLCompress(char repeat_char, /* I - Character to repeat */
1061 int repeat_count) /* I - Number of repeated characters */
1062 {
1063 if (repeat_count > 1)
1064 {
1065 /*
1066 * Print as many z's as possible - they are the largest denomination
1067 * representing 400 characters (zC stands for 400 adjacent C's)
1068 */
1069
1070 while (repeat_count >= 400)
1071 {
1072 putchar('z');
1073 repeat_count -= 400;
1074 }
1075
1076 /*
1077 * Then print 'g' through 'y' as multiples of 20 characters...
1078 */
1079
1080 if (repeat_count >= 20)
1081 {
1082 putchar('f' + repeat_count / 20);
1083 repeat_count %= 20;
1084 }
1085
1086 /*
1087 * Finally, print 'G' through 'Y' as 1 through 19 characters...
1088 */
1089
1090 if (repeat_count > 0)
1091 putchar('F' + repeat_count);
1092 }
1093
1094 /*
1095 * Then the character to be repeated...
1096 */
1097
1098 putchar(repeat_char);
1099 }
1100
1101
1102 /*
1103 * 'main()' - Main entry and processing of driver.
1104 */
1105
1106 int /* O - Exit status */
1107 main(int argc, /* I - Number of command-line arguments */
1108 char *argv[]) /* I - Command-line arguments */
1109 {
1110 int fd; /* File descriptor */
1111 cups_raster_t *ras; /* Raster stream for printing */
1112 cups_page_header2_t header; /* Page header from file */
1113 int y; /* Current line */
1114 ppd_file_t *ppd; /* PPD file */
1115 int num_options; /* Number of options */
1116 cups_option_t *options; /* Options */
1117 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1118 struct sigaction action; /* Actions for POSIX signals */
1119 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1120
1121
1122 /*
1123 * Make sure status messages are not buffered...
1124 */
1125
1126 setbuf(stderr, NULL);
1127
1128 /*
1129 * Check command-line...
1130 */
1131
1132 if (argc < 6 || argc > 7)
1133 {
1134 /*
1135 * We don't have the correct number of arguments; write an error message
1136 * and return.
1137 */
1138
1139 fprintf(stderr, _("Usage: %s job-id user title copies options [file]\n"),
1140 argv[0]);
1141 return (1);
1142 }
1143
1144 /*
1145 * Open the page stream...
1146 */
1147
1148 if (argc == 7)
1149 {
1150 if ((fd = open(argv[6], O_RDONLY)) == -1)
1151 {
1152 perror("ERROR: Unable to open raster file - ");
1153 sleep(1);
1154 return (1);
1155 }
1156 }
1157 else
1158 fd = 0;
1159
1160 ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
1161
1162 /*
1163 * Register a signal handler to eject the current page if the
1164 * job is cancelled.
1165 */
1166
1167 Canceled = 0;
1168
1169 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1170 sigset(SIGTERM, CancelJob);
1171 #elif defined(HAVE_SIGACTION)
1172 memset(&action, 0, sizeof(action));
1173
1174 sigemptyset(&action.sa_mask);
1175 action.sa_handler = CancelJob;
1176 sigaction(SIGTERM, &action, NULL);
1177 #else
1178 signal(SIGTERM, CancelJob);
1179 #endif /* HAVE_SIGSET */
1180
1181 /*
1182 * Open the PPD file and apply options...
1183 */
1184
1185 num_options = cupsParseOptions(argv[5], 0, &options);
1186
1187 if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL)
1188 {
1189 ppdMarkDefaults(ppd);
1190 cupsMarkOptions(ppd, num_options, options);
1191 }
1192
1193 /*
1194 * Initialize the print device...
1195 */
1196
1197 Setup(ppd);
1198
1199 /*
1200 * Process pages as needed...
1201 */
1202
1203 Page = 0;
1204
1205 while (cupsRasterReadHeader2(ras, &header))
1206 {
1207 /*
1208 * Write a status message with the page number and number of copies.
1209 */
1210
1211 if (Canceled)
1212 break;
1213
1214 Page ++;
1215
1216 fprintf(stderr, "PAGE: %d 1\n", Page);
1217
1218 /*
1219 * Start the page...
1220 */
1221
1222 StartPage(ppd, &header);
1223
1224 /*
1225 * Loop for each line on the page...
1226 */
1227
1228 for (y = 0; y < header.cupsHeight && !Canceled; y ++)
1229 {
1230 /*
1231 * Let the user know how far we have progressed...
1232 */
1233
1234 if (Canceled)
1235 break;
1236
1237 if ((y & 15) == 0)
1238 fprintf(stderr, _("INFO: Printing page %d, %d%% complete...\n"), Page,
1239 100 * y / header.cupsHeight);
1240
1241 /*
1242 * Read a line of graphics...
1243 */
1244
1245 if (cupsRasterReadPixels(ras, Buffer, header.cupsBytesPerLine) < 1)
1246 break;
1247
1248 /*
1249 * Write it to the printer...
1250 */
1251
1252 OutputLine(ppd, &header, y);
1253 }
1254
1255 /*
1256 * Eject the page...
1257 */
1258
1259 EndPage(ppd, &header);
1260
1261 if (Canceled)
1262 break;
1263 }
1264
1265 /*
1266 * Close the raster stream...
1267 */
1268
1269 cupsRasterClose(ras);
1270 if (fd != 0)
1271 close(fd);
1272
1273 /*
1274 * Close the PPD file and free the options...
1275 */
1276
1277 ppdClose(ppd);
1278 cupsFreeOptions(num_options, options);
1279
1280 /*
1281 * If no pages were printed, send an error message...
1282 */
1283
1284 if (Page == 0)
1285 fputs(_("ERROR: No pages found!\n"), stderr);
1286 else
1287 fputs(_("INFO: Ready to print.\n"), stderr);
1288
1289 return (Page == 0);
1290 }
1291
1292
1293 /*
1294 * End of "$Id: rastertolabel.c 6819 2007-08-20 21:11:57Z mike $".
1295 */