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