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