1/* 2 * "$Id: rastertolabel.c 11780 2014-03-28 20:51:12Z msweet $" 3 * 4 * Label printer filter for CUPS. 5 * 6 * Copyright 2007-2012 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/ppd.h> 35#include <cups/string-private.h> 36#include <cups/language-private.h> 37#include <cups/raster.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 online 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 78unsigned char *Buffer; /* Output buffer */ 79unsigned char *CompBuffer; /* Compression buffer */ 80unsigned char *LastBuffer; /* Last buffer */ 81int LastSet; /* Number of repeat characters */ 82int 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 92void Setup(ppd_file_t *ppd); 93void StartPage(ppd_file_t *ppd, cups_page_header2_t *header); 94void EndPage(ppd_file_t *ppd, cups_page_header2_t *header); 95void CancelJob(int sig); 96void OutputLine(ppd_file_t *ppd, cups_page_header2_t *header, int y); 97void PCLCompress(unsigned char *line, int length); 98void ZPLCompress(char repeat_char, int repeat_count); 99 100 101/* 102 * 'Setup()' - Prepare the printer for printing. 103 */ 104 105void 106Setup(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 167void 168StartPage(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 479void 480EndPage(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 486 487 switch (ModelNumber) 488 { 489 case DYMO_3x0 : 490 /* 491 * Eject the current page... 492 */ 493 494 fputs("\033E", stdout); 495 break; 496 497 case ZEBRA_EPL_LINE : 498 /* 499 * End buffered output, eject the label... 500 */ 501 502 fputs("\033E\014", stdout); 503 break; 504 505 case ZEBRA_EPL_PAGE : 506 /* 507 * Print the label... 508 */ 509 510 puts("P1"); 511 break; 512 513 case ZEBRA_ZPL : 514 if (Canceled) 515 { 516 /* 517 * Cancel bitmap download... 518 */ 519 520 puts("~DN"); 521 break; 522 } 523 524 /* 525 * Start label... 526 */ 527 528 puts("^XA"); 529 530 /* 531 * Set print rate... 532 */ 533 534 if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL && 535 strcmp(choice->choice, "Default")) 536 { 537 val = atoi(choice->choice); 538 printf("^PR%d,%d,%d\n", val, val, val); 539 } 540 541 /* 542 * Put label home in default position (0,0)... 543 */ 544 545 printf("^LH0,0\n"); 546 547 /* 548 * Set media tracking... 549 */ 550 551 if (ppdIsMarked(ppd, "zeMediaTracking", "Continuous")) 552 { 553 /* 554 * Add label length command for continuous... 555 */ 556 557 printf("^LL%d\n", header->cupsHeight); 558 printf("^MNN\n"); 559 } 560 else if (ppdIsMarked(ppd, "zeMediaTracking", "Web")) 561 printf("^MNY\n"); 562 else if (ppdIsMarked(ppd, "zeMediaTracking", "Mark")) 563 printf("^MNM\n"); 564 565 /* 566 * Set label top 567 */ 568 569 if (header->cupsRowStep != 200) 570 printf("^LT%d\n", header->cupsRowStep); 571 572 /* 573 * Set media type... 574 */ 575 576 if (!strcmp(header->MediaType, "Thermal")) 577 printf("^MTT\n"); 578 else if (!strcmp(header->MediaType, "Direct")) 579 printf("^MTD\n"); 580 581 /* 582 * Set print mode... 583 */ 584 585 if ((choice = ppdFindMarkedChoice(ppd, "zePrintMode")) != NULL && 586 strcmp(choice->choice, "Saved")) 587 { 588 printf("^MM"); 589 590 if (!strcmp(choice->choice, "Tear")) 591 printf("T,Y\n"); 592 else if (!strcmp(choice->choice, "Peel")) 593 printf("P,Y\n"); 594 else if (!strcmp(choice->choice, "Rewind")) 595 printf("R,Y\n"); 596 else if (!strcmp(choice->choice, "Applicator")) 597 printf("A,Y\n"); 598 else 599 printf("C,Y\n"); 600 } 601 602 /* 603 * Set tear-off adjust position... 604 */ 605 606 if (header->AdvanceDistance != 1000) 607 { 608 if ((int)header->AdvanceDistance < 0) 609 printf("~TA%04d\n", (int)header->AdvanceDistance); 610 else 611 printf("~TA%03d\n", (int)header->AdvanceDistance); 612 } 613 614 /* 615 * Allow for reprinting after an error... 616 */ 617 618 if (ppdIsMarked(ppd, "zeErrorReprint", "Always")) 619 printf("^JZY\n"); 620 else if (ppdIsMarked(ppd, "zeErrorReprint", "Never")) 621 printf("^JZN\n"); 622 623 /* 624 * Print multiple copies 625 */ 626 627 if (header->NumCopies > 1) 628 printf("^PQ%d, 0, 0, N\n", header->NumCopies); 629 630 /* 631 * Display the label image... 632 */ 633 634 puts("^FO0,0^XGR:CUPS.GRF,1,1^FS"); 635 636 /* 637 * End the label and eject... 638 */ 639 640 puts("^IDR:CUPS.GRF^FS"); 641 puts("^XZ"); 642 break; 643 644 case ZEBRA_CPCL : 645 /* 646 * Set tear-off adjust position... 647 */ 648 649 if (header->AdvanceDistance != 1000) 650 printf("PRESENT-AT %d 1\r\n", (int)header->AdvanceDistance); 651 652 /* 653 * Allow for reprinting after an error... 654 */ 655 656 if (ppdIsMarked(ppd, "zeErrorReprint", "Always")) 657 puts("ON-OUT-OF-PAPER WAIT\r"); 658 else if (ppdIsMarked(ppd, "zeErrorReprint", "Never")) 659 puts("ON-OUT-OF-PAPER PURGE\r"); 660 661 /* 662 * Cut label? 663 */ 664 665 if (header->CutMedia) 666 puts("CUT\r"); 667 668 /* 669 * Set darkness... 670 */ 671 672 if (header->cupsCompression > 0) 673 printf("TONE %u\r\n", 2 * header->cupsCompression); 674 675 /* 676 * Set print rate... 677 */ 678 679 if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL && 680 strcmp(choice->choice, "Default")) 681 { 682 val = atoi(choice->choice); 683 printf("SPEED %d\r\n", val); 684 } 685 686 /* 687 * Print the label... 688 */ 689 690 if ((choice = ppdFindMarkedChoice(ppd, "zeMediaTracking")) == NULL || 691 strcmp(choice->choice, "Continuous")) 692 puts("FORM\r"); 693 694 puts("PRINT\r"); 695 break; 696 697 case INTELLITECH_PCL : 698 printf("\033*rB"); /* End GFX */ 699 printf("\014"); /* Eject current page */ 700 break; 701 } 702 703 fflush(stdout); 704 705 /* 706 * Free memory... 707 */ 708 709 free(Buffer); 710 711 if (CompBuffer) 712 { 713 free(CompBuffer); 714 CompBuffer = NULL; 715 } 716 717 if (LastBuffer) 718 { 719 free(LastBuffer); 720 LastBuffer = NULL; 721 } 722} 723 724 725/* 726 * 'CancelJob()' - Cancel the current job... 727 */ 728 729void 730CancelJob(int sig) /* I - Signal */ 731{ 732 /* 733 * Tell the main loop to stop... 734 */ 735 736 (void)sig; 737 738 Canceled = 1; 739} 740 741 742/* 743 * 'OutputLine()' - Output a line of graphics... 744 */ 745 746void 747OutputLine(ppd_file_t *ppd, /* I - PPD file */ 748 cups_page_header2_t *header, /* I - Page header */ 749 int y) /* I - Line number */ 750{ 751 int i; /* Looping var */ 752 unsigned char *ptr; /* Pointer into buffer */ 753 unsigned char *compptr; /* Pointer into compression buffer */ 754 char repeat_char; /* Repeated character */ 755 int repeat_count; /* Number of repeated characters */ 756 static const char *hex = "0123456789ABCDEF"; 757 /* Hex digits */ 758 759 760 switch (ModelNumber) 761 { 762 case DYMO_3x0 : 763 /* 764 * See if the line is blank; if not, write it to the printer... 765 */ 766 767 if (Buffer[0] || 768 memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine - 1)) 769 { 770 if (Feed) 771 { 772 while (Feed > 255) 773 { 774 printf("\033f\001%c", 255); 775 Feed -= 255; 776 } 777 778 printf("\033f\001%c", Feed); 779 Feed = 0; 780 } 781 782 putchar(0x16); 783 fwrite(Buffer, header->cupsBytesPerLine, 1, stdout); 784 fflush(stdout); 785 } 786 else 787 Feed ++; 788 break; 789 790 case ZEBRA_EPL_LINE : 791 printf("\033g%03d", header->cupsBytesPerLine); 792 fwrite(Buffer, 1, header->cupsBytesPerLine, stdout); 793 fflush(stdout); 794 break; 795 796 case ZEBRA_EPL_PAGE : 797 if (Buffer[0] || memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine)) 798 { 799 printf("GW0,%d,%d,1\n", y, header->cupsBytesPerLine); 800 for (i = header->cupsBytesPerLine, ptr = Buffer; i > 0; i --, ptr ++) 801 putchar(~*ptr); 802 putchar('\n'); 803 fflush(stdout); 804 } 805 break; 806 807 case ZEBRA_ZPL : 808 /* 809 * Determine if this row is the same as the previous line. 810 * If so, output a ':' and return... 811 */ 812 813 if (LastSet) 814 { 815 if (!memcmp(Buffer, LastBuffer, header->cupsBytesPerLine)) 816 { 817 putchar(':'); 818 return; 819 } 820 } 821 822 /* 823 * Convert the line to hex digits... 824 */ 825 826 for (ptr = Buffer, compptr = CompBuffer, i = header->cupsBytesPerLine; 827 i > 0; 828 i --, ptr ++) 829 { 830 *compptr++ = hex[*ptr >> 4]; 831 *compptr++ = hex[*ptr & 15]; 832 } 833 834 *compptr = '\0'; 835 836 /* 837 * Run-length compress the graphics... 838 */ 839 840 for (compptr = CompBuffer + 1, repeat_char = CompBuffer[0], repeat_count = 1; 841 *compptr; 842 compptr ++) 843 if (*compptr == repeat_char) 844 repeat_count ++; 845 else 846 { 847 ZPLCompress(repeat_char, repeat_count); 848 repeat_char = *compptr; 849 repeat_count = 1; 850 } 851 852 if (repeat_char == '0') 853 { 854 /* 855 * Handle 0's on the end of the line... 856 */ 857 858 if (repeat_count & 1) 859 { 860 repeat_count --; 861 putchar('0'); 862 } 863 864 if (repeat_count > 0) 865 putchar(','); 866 } 867 else 868 ZPLCompress(repeat_char, repeat_count); 869 870 fflush(stdout); 871 872 /* 873 * Save this line for the next round... 874 */ 875 876 memcpy(LastBuffer, Buffer, header->cupsBytesPerLine); 877 LastSet = 1; 878 break; 879 880 case ZEBRA_CPCL : 881 if (Buffer[0] || memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine)) 882 { 883 printf("CG %u 1 0 %d ", header->cupsBytesPerLine, y); 884 fwrite(Buffer, 1, header->cupsBytesPerLine, stdout); 885 puts("\r"); 886 fflush(stdout); 887 } 888 break; 889 890 case INTELLITECH_PCL : 891 if (Buffer[0] || 892 memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine - 1)) 893 { 894 if (Feed) 895 { 896 printf("\033*b%dY", Feed); 897 Feed = 0; 898 LastSet = 0; 899 } 900 901 PCLCompress(Buffer, header->cupsBytesPerLine); 902 } 903 else 904 Feed ++; 905 break; 906 } 907} 908 909 910/* 911 * 'PCLCompress()' - Output a PCL (mode 3) compressed line. 912 */ 913 914void 915PCLCompress(unsigned char *line, /* I - Line to compress */ 916 int length) /* I - Length of line */ 917{ 918 unsigned char *line_ptr, /* Current byte pointer */ 919 *line_end, /* End-of-line byte pointer */ 920 *comp_ptr, /* Pointer into compression buffer */ 921 *start, /* Start of compression sequence */ 922 *seed; /* Seed buffer pointer */ 923 int count, /* Count of bytes for output */ 924 offset; /* Offset of bytes for output */ 925 926 927 /* 928 * Do delta-row compression... 929 */ 930 931 line_ptr = line; 932 line_end = line + length; 933 934 comp_ptr = CompBuffer; 935 seed = LastBuffer; 936 937 while (line_ptr < line_end) 938 { 939 /* 940 * Find the next non-matching sequence... 941 */ 942 943 start = line_ptr; 944 945 if (!LastSet) 946 { 947 /* 948 * The seed buffer is invalid, so do the next 8 bytes, max... 949 */ 950 951 offset = 0; 952 953 if ((count = line_end - line_ptr) > 8) 954 count = 8; 955 956 line_ptr += count; 957 } 958 else 959 { 960 /* 961 * The seed buffer is valid, so compare against it... 962 */ 963 964 while (*line_ptr == *seed && 965 line_ptr < line_end) 966 { 967 line_ptr ++; 968 seed ++; 969 } 970 971 if (line_ptr == line_end) 972 break; 973 974 offset = line_ptr - start; 975 976 /* 977 * Find up to 8 non-matching bytes... 978 */ 979 980 start = line_ptr; 981 count = 0; 982 while (*line_ptr != *seed && 983 line_ptr < line_end && 984 count < 8) 985 { 986 line_ptr ++; 987 seed ++; 988 count ++; 989 } 990 } 991 992 /* 993 * Place mode 3 compression data in the buffer; see HP manuals 994 * for details... 995 */ 996 997 if (offset >= 31) 998 { 999 /* 1000 * Output multi-byte offset... 1001 */ 1002 1003 *comp_ptr++ = ((count - 1) << 5) | 31; 1004 1005 offset -= 31; 1006 while (offset >= 255) 1007 { 1008 *comp_ptr++ = 255; 1009 offset -= 255; 1010 } 1011 1012 *comp_ptr++ = offset; 1013 } 1014 else 1015 { 1016 /* 1017 * Output single-byte offset... 1018 */ 1019 1020 *comp_ptr++ = ((count - 1) << 5) | offset; 1021 } 1022 1023 memcpy(comp_ptr, start, count); 1024 comp_ptr += count; 1025 } 1026 1027 /* 1028 * Set the length of the data and write it... 1029 */ 1030 1031 printf("\033*b%dW", (int)(comp_ptr - CompBuffer)); 1032 fwrite(CompBuffer, comp_ptr - CompBuffer, 1, stdout); 1033 1034 /* 1035 * Save this line as a "seed" buffer for the next... 1036 */ 1037 1038 memcpy(LastBuffer, line, length); 1039 LastSet = 1; 1040} 1041 1042 1043/* 1044 * 'ZPLCompress()' - Output a run-length compression sequence. 1045 */ 1046 1047void 1048ZPLCompress(char repeat_char, /* I - Character to repeat */ 1049 int repeat_count) /* I - Number of repeated characters */ 1050{ 1051 if (repeat_count > 1) 1052 { 1053 /* 1054 * Print as many z's as possible - they are the largest denomination 1055 * representing 400 characters (zC stands for 400 adjacent C's) 1056 */ 1057 1058 while (repeat_count >= 400) 1059 { 1060 putchar('z'); 1061 repeat_count -= 400; 1062 } 1063 1064 /* 1065 * Then print 'g' through 'y' as multiples of 20 characters... 1066 */ 1067 1068 if (repeat_count >= 20) 1069 { 1070 putchar('f' + repeat_count / 20); 1071 repeat_count %= 20; 1072 } 1073 1074 /* 1075 * Finally, print 'G' through 'Y' as 1 through 19 characters... 1076 */ 1077 1078 if (repeat_count > 0) 1079 putchar('F' + repeat_count); 1080 } 1081 1082 /* 1083 * Then the character to be repeated... 1084 */ 1085 1086 putchar(repeat_char); 1087} 1088 1089 1090/* 1091 * 'main()' - Main entry and processing of driver. 1092 */ 1093 1094int /* O - Exit status */ 1095main(int argc, /* I - Number of command-line arguments */ 1096 char *argv[]) /* I - Command-line arguments */ 1097{ 1098 int fd; /* File descriptor */ 1099 cups_raster_t *ras; /* Raster stream for printing */ 1100 cups_page_header2_t header; /* Page header from file */ 1101 int y; /* Current line */ 1102 ppd_file_t *ppd; /* PPD file */ 1103 int num_options; /* Number of options */ 1104 cups_option_t *options; /* Options */ 1105#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) 1106 struct sigaction action; /* Actions for POSIX signals */ 1107#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ 1108 1109 1110 /* 1111 * Make sure status messages are not buffered... 1112 */ 1113 1114 setbuf(stderr, NULL); 1115 1116 /* 1117 * Check command-line... 1118 */ 1119 1120 if (argc < 6 || argc > 7) 1121 { 1122 /* 1123 * We don't have the correct number of arguments; write an error message 1124 * and return. 1125 */ 1126 1127 _cupsLangPrintFilter(stderr, "ERROR", 1128 _("%s job-id user title copies options [file]"), 1129 "rastertolabel"); 1130 return (1); 1131 } 1132 1133 /* 1134 * Open the page stream... 1135 */ 1136 1137 if (argc == 7) 1138 { 1139 if ((fd = open(argv[6], O_RDONLY)) == -1) 1140 { 1141 _cupsLangPrintError("ERROR", _("Unable to open raster file")); 1142 sleep(1); 1143 return (1); 1144 } 1145 } 1146 else 1147 fd = 0; 1148 1149 ras = cupsRasterOpen(fd, CUPS_RASTER_READ); 1150 1151 /* 1152 * Register a signal handler to eject the current page if the 1153 * job is cancelled. 1154 */ 1155 1156 Canceled = 0; 1157 1158#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ 1159 sigset(SIGTERM, CancelJob); 1160#elif defined(HAVE_SIGACTION) 1161 memset(&action, 0, sizeof(action)); 1162 1163 sigemptyset(&action.sa_mask); 1164 action.sa_handler = CancelJob; 1165 sigaction(SIGTERM, &action, NULL); 1166#else 1167 signal(SIGTERM, CancelJob); 1168#endif /* HAVE_SIGSET */ 1169 1170 /* 1171 * Open the PPD file and apply options... 1172 */ 1173 1174 num_options = cupsParseOptions(argv[5], 0, &options); 1175 1176 ppd = ppdOpenFile(getenv("PPD")); 1177 if (!ppd) 1178 { 1179 ppd_status_t status; /* PPD error */ 1180 int linenum; /* Line number */ 1181 1182 _cupsLangPrintFilter(stderr, "ERROR", 1183 _("The PPD file could not be opened.")); 1184 1185 status = ppdLastError(&linenum); 1186 1187 fprintf(stderr, "DEBUG: %s on line %d.\n", ppdErrorString(status), linenum); 1188 1189 return (1); 1190 } 1191 1192 ppdMarkDefaults(ppd); 1193 cupsMarkOptions(ppd, num_options, options); 1194 1195 /* 1196 * Initialize the print device... 1197 */ 1198 1199 Setup(ppd); 1200 1201 /* 1202 * Process pages as needed... 1203 */ 1204 1205 Page = 0; 1206 1207 while (cupsRasterReadHeader2(ras, &header)) 1208 { 1209 /* 1210 * Write a status message with the page number and number of copies. 1211 */ 1212 1213 if (Canceled) 1214 break; 1215 1216 Page ++; 1217 1218 fprintf(stderr, "PAGE: %d 1\n", Page); 1219 _cupsLangPrintFilter(stderr, "INFO", _("Starting page %d."), Page); 1220 1221 /* 1222 * Start the page... 1223 */ 1224 1225 StartPage(ppd, &header); 1226 1227 /* 1228 * Loop for each line on the page... 1229 */ 1230 1231 for (y = 0; y < header.cupsHeight && !Canceled; y ++) 1232 { 1233 /* 1234 * Let the user know how far we have progressed... 1235 */ 1236 1237 if (Canceled) 1238 break; 1239 1240 if ((y & 15) == 0) 1241 { 1242 _cupsLangPrintFilter(stderr, "INFO", 1243 _("Printing page %d, %d%% complete."), 1244 Page, 100 * y / header.cupsHeight); 1245 fprintf(stderr, "ATTR: job-media-progress=%d\n", 1246 100 * y / header.cupsHeight); 1247 } 1248 1249 /* 1250 * Read a line of graphics... 1251 */ 1252 1253 if (cupsRasterReadPixels(ras, Buffer, header.cupsBytesPerLine) < 1) 1254 break; 1255 1256 /* 1257 * Write it to the printer... 1258 */ 1259 1260 OutputLine(ppd, &header, y); 1261 } 1262 1263 /* 1264 * Eject the page... 1265 */ 1266 1267 _cupsLangPrintFilter(stderr, "INFO", _("Finished page %d."), Page); 1268 1269 EndPage(ppd, &header); 1270 1271 if (Canceled) 1272 break; 1273 } 1274 1275 /* 1276 * Close the raster stream... 1277 */ 1278 1279 cupsRasterClose(ras); 1280 if (fd != 0) 1281 close(fd); 1282 1283 /* 1284 * Close the PPD file and free the options... 1285 */ 1286 1287 ppdClose(ppd); 1288 cupsFreeOptions(num_options, options); 1289 1290 /* 1291 * If no pages were printed, send an error message... 1292 */ 1293 1294 if (Page == 0) 1295 { 1296 _cupsLangPrintFilter(stderr, "ERROR", _("No pages were found.")); 1297 return (1); 1298 } 1299 else 1300 return (0); 1301} 1302 1303 1304/* 1305 * End of "$Id: rastertolabel.c 11780 2014-03-28 20:51:12Z msweet $". 1306 */ 1307