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