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