]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/rastertodymo.c
Fix C99-ism in do_config_server() code.
[thirdparty/cups.git] / filter / rastertodymo.c
CommitLineData
74456259 1/*
c9d3f842 2 * "$Id$"
74456259 3 *
725dbff8 4 * Label printer filter for the Common UNIX Printing System (CUPS).
74456259 5 *
c9d3f842 6 * Copyright 2001-2005 by Easy Software Products.
74456259 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
c9d3f842 18 * Hollywood, Maryland 20636 USA
74456259 19 *
9639c4de 20 * Voice: (301) 373-9600
74456259 21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
dab1a4d8 24 * This file is subject to the Apple OS-Developed Software exception.
25 *
74456259 26 * Contents:
27 *
28 * Setup() - Prepare the printer for printing.
29 * StartPage() - Start a page of graphics.
30 * EndPage() - Finish a page of graphics.
74456259 31 * CancelJob() - Cancel the current job...
74456259 32 * OutputLine() - Output a line of graphics.
6c5fbfa1 33 * ZPLCompress() - Output a run-length compression sequence.
74456259 34 * main() - Main entry and processing of driver.
35 */
36
37/*
38 * Include necessary headers...
39 */
40
41#include <cups/cups.h>
42#include <cups/string.h>
43#include "raster.h"
44#include <stdlib.h>
45#include <unistd.h>
46#include <fcntl.h>
47#include <signal.h>
48
49
725dbff8 50/*
51 * This driver filter currently supports Dymo and Zebra label printers.
52 *
53 * The Dymo portion of the driver has been tested with the 300, 330,
54 * and 330 Turbo label printers; it may also work with older models.
55 * The Dymo printers support printing at 136, 203, and 300 DPI.
56 *
ea19a116 57 * The Zebra portion of the driver has been tested with the LP-2844Z label
725dbff8 58 * printer; it may also work with other models. The driver supports both
ea19a116 59 * EPL and ZPL as defined in Zebra's on-line developer documentation.
725dbff8 60 */
61
62/*
63 * Model number constants...
64 */
65
66#define DYMO_3x0 0 /* Dymo Labelwriter 300/330/330 Turbo */
67
ea19a116 68#define ZEBRA_EPL_LINE 0x10 /* Zebra EPL line mode printers */
69#define ZEBRA_EPL_PAGE 0x11 /* Zebra EPL page mode printers */
70#define ZEBRA_ZPL 0x12 /* Zebra ZPL-based printers */
725dbff8 71
72
74456259 73/*
74 * Globals...
75 */
76
77unsigned char *Buffer; /* Output buffer */
6c5fbfa1 78char *CompBuffer; /* Compression buffer */
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);
92void StartPage(ppd_file_t *ppd, cups_page_header_t *header);
93void EndPage(ppd_file_t *ppd, cups_page_header_t *header);
74456259 94void CancelJob(int sig);
6c5fbfa1 95void OutputLine(ppd_file_t *ppd, cups_page_header_t *header, int y);
96void ZPLCompress(char repeat_char, int repeat_count);
74456259 97
98
99/*
100 * 'Setup()' - Prepare the printer for printing.
101 */
102
103void
6c5fbfa1 104Setup(ppd_file_t *ppd) /* I - PPD file */
74456259 105{
725dbff8 106 int i; /* Looping var */
74456259 107
108
109 /*
725dbff8 110 * Get the model number from the PPD file...
74456259 111 */
112
6c5fbfa1 113 if (ppd)
725dbff8 114 ModelNumber = ppd->model_number;
c67094f2 115
116 /*
725dbff8 117 * Initialize based on the model number...
c67094f2 118 */
119
725dbff8 120 switch (ModelNumber)
121 {
122 case DYMO_3x0 :
123 /*
124 * Clear any remaining data...
125 */
126
127 for (i = 0; i < 100; i ++)
128 putchar(0x1b);
129
130 /*
131 * Reset the printer...
132 */
133
134 fputs("\033@", stdout);
135 break;
136
ea19a116 137 case ZEBRA_EPL_LINE :
138 break;
139
140 case ZEBRA_EPL_PAGE :
141 break;
142
725dbff8 143 case ZEBRA_ZPL :
725dbff8 144 break;
145 }
74456259 146}
147
148
149/*
150 * 'StartPage()' - Start a page of graphics.
151 */
152
153void
6c5fbfa1 154StartPage(ppd_file_t *ppd, /* I - PPD file */
155 cups_page_header_t *header) /* I - Page header */
74456259 156{
9a12ff91 157 int length; /* Actual label length */
74456259 158#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
159 struct sigaction action; /* Actions for POSIX signals */
160#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
161
162
163 /*
164 * Register a signal handler to eject the current page if the
ea19a116 165 * job is canceled.
74456259 166 */
167
168#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
169 sigset(SIGTERM, CancelJob);
170#elif defined(HAVE_SIGACTION)
171 memset(&action, 0, sizeof(action));
172
173 sigemptyset(&action.sa_mask);
174 action.sa_handler = CancelJob;
175 sigaction(SIGTERM, &action, NULL);
176#else
177 signal(SIGTERM, CancelJob);
178#endif /* HAVE_SIGSET */
179
725dbff8 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;
74456259 194
ea19a116 195 case ZEBRA_EPL_LINE :
196 /*
197 * Set darkness...
198 */
199
200 printf("D%d", 7 * header->cupsCompression / 100);
201
202 /*
203 * Start buffered output...
204 */
205
206 putchar('B');
207 break;
208
209 case ZEBRA_EPL_PAGE :
210 /*
211 * Set darkness...
212 */
213
214 printf("D%d", 15 * header->cupsCompression / 100);
215
216 /*
217 * Set label size...
218 */
219
220 printf("q%d\n", header->cupsWidth);
221 break;
222
725dbff8 223 case ZEBRA_ZPL :
725dbff8 224 /*
225 * Set darkness...
226 */
9a12ff91 227
6c5fbfa1 228 if (header->cupsCompression > 0)
229 printf("~SD%02d\n", 30 * header->cupsCompression / 100);
74456259 230
725dbff8 231 /*
232 * Start bitmap graphics...
233 */
234
235 printf("~DGR:CUPS.GRF,%d,%d,\n",
236 header->cupsHeight * header->cupsBytesPerLine,
237 header->cupsBytesPerLine);
6c5fbfa1 238
239 /*
240 * Allocate compression buffers...
241 */
242
243 CompBuffer = malloc(2 * header->cupsBytesPerLine + 1);
244 LastBuffer = malloc(header->cupsBytesPerLine);
245 LastSet = 0;
725dbff8 246 break;
247 }
74456259 248
249 /*
250 * Allocate memory for a line of graphics...
251 */
252
253 Buffer = malloc(header->cupsBytesPerLine);
254 Feed = 0;
255}
256
257
258/*
259 * 'EndPage()' - Finish a page of graphics.
260 */
261
262void
6c5fbfa1 263EndPage(ppd_file_t *ppd, /* I - PPD file */
264 cups_page_header_t *header) /* I - Page header */
74456259 265{
6c5fbfa1 266 int val; /* Option value */
267 ppd_choice_t *choice; /* Marked choice */
74456259 268#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
725dbff8 269 struct sigaction action; /* Actions for POSIX signals */
74456259 270#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
271
272
725dbff8 273 switch (ModelNumber)
274 {
275 case DYMO_3x0 :
276 /*
277 * Eject the current page...
278 */
279
280 fputs("\033E", stdout);
ea19a116 281 break;
74456259 282
ea19a116 283 case ZEBRA_EPL_LINE :
284 /*
285 * End buffered output, eject the label...
286 */
287
288 putchar('E');
289 break;
290
291 case ZEBRA_EPL_PAGE :
292 /*
293 * Print the label...
294 */
295
296 puts("P1");
725dbff8 297 break;
298
299 case ZEBRA_ZPL :
ea19a116 300 if (Canceled)
725dbff8 301 {
302 /*
303 * Cancel bitmap download...
304 */
305
306 puts("~DN");
307 break;
308 }
309
310 /*
6c5fbfa1 311 * Start label...
725dbff8 312 */
74456259 313
725dbff8 314 puts("^XA");
725dbff8 315
316 /*
6c5fbfa1 317 * Set print rate...
725dbff8 318 */
319
6c5fbfa1 320 if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL &&
321 strcmp(choice->choice, "Default"))
322 {
323 val = atoi(choice->choice);
324 printf("^PR%d,%d,%d\n", val, val, val);
325 }
326
327 /*
328 * Put label home in default position (0,0)...
329 */
330
331 printf("^LH0,0\n");
332
333 /*
334 * Set media tracking...
335 */
336
337 if (ppdIsMarked(ppd, "zeMediaTracking", "Continuous"))
338 {
339 /*
340 * Add label length command for continuous...
341 */
342
343 printf("^LL%d\n", header->cupsHeight);
344 printf("^MNN\n");
345 }
346 else if (ppdIsMarked(ppd, "zeMediaTracking", "Web"))
347 printf("^MNY\n");
348 else if (ppdIsMarked(ppd, "zeMediaTracking", "Mark"))
349 printf("^MNM\n");
350
351 /*
352 * Set label top
353 */
354
355 if (header->cupsRowStep != 200)
356 printf("^LT%u\n", header->cupsRowStep);
357
358 /*
359 * Set media type...
360 */
361
362 if (!strcmp(header->MediaType, "Thermal"))
363 printf("^MTT\n");
364 else if (!strcmp(header->MediaType, "Direct"))
365 printf("^MTD\n");
366
367 /*
368 * Set print mode...
369 */
370
371 if ((choice = ppdFindMarkedChoice(ppd, "zePrintMode")) != NULL &&
372 strcmp(choice->choice, "Saved"))
373 {
374 printf("^MM");
375
376 if (!strcmp(choice->choice, "Tear"))
377 printf("T,Y\n");
378 else if (!strcmp(choice->choice, "Peel"))
379 printf("P,Y\n");
380 else if (!strcmp(choice->choice, "Rewind"))
381 printf("R,Y\n");
382 else if (!strcmp(choice->choice, "Applicator"))
383 printf("A,Y\n");
384 else
385 printf("C,Y\n");
386 }
387
388 /*
389 * Set tear-off adjust position...
390 */
391
392 if (header->AdvanceDistance != 1000)
393 {
394 if ((int)header->AdvanceDistance < 0)
395 printf("~TA%04d\n", (int)header->AdvanceDistance);
396 else
397 printf("~TA%03d\n", (int)header->AdvanceDistance);
398 }
399
400 /*
401 * Allow for reprinting after an error...
402 */
403
404 if (ppdIsMarked(ppd, "zeErrorReprint", "Always"))
405 printf("^JZY\n");
406 else if (ppdIsMarked(ppd, "zeErrorReprint", "Never"))
407 printf("^JZN\n");
408
409 /*
410 * Print multiple copies
411 */
412
413 if (header->NumCopies > 1)
414 printf("^PQ%d, 0, 0, N\n", header->NumCopies);
725dbff8 415
416 /*
417 * Display the label image...
418 */
419
6c5fbfa1 420 puts("^FO0,0^XGR:CUPS.GRF,1,1^FS");
725dbff8 421
422 /*
423 * End the label and eject...
424 */
425
426 puts("^XZ");
6c5fbfa1 427
428 /*
429 * Free compression buffers...
430 */
431
432 free(CompBuffer);
433 free(LastBuffer);
725dbff8 434 break;
435 }
74456259 436
ea19a116 437 fflush(stdout);
438
74456259 439 /*
440 * Unregister the signal handler...
441 */
442
443#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
444 sigset(SIGTERM, SIG_IGN);
445#elif defined(HAVE_SIGACTION)
446 memset(&action, 0, sizeof(action));
447
448 sigemptyset(&action.sa_mask);
449 action.sa_handler = SIG_IGN;
450 sigaction(SIGTERM, &action, NULL);
451#else
452 signal(SIGTERM, SIG_IGN);
453#endif /* HAVE_SIGSET */
454
455 /*
456 * Free memory...
457 */
458
459 free(Buffer);
460}
461
462
463/*
464 * 'CancelJob()' - Cancel the current job...
465 */
466
467void
468CancelJob(int sig) /* I - Signal */
469{
725dbff8 470 /*
471 * Tell the main loop to stop...
472 */
74456259 473
474 (void)sig;
475
ea19a116 476 Canceled = 1;
725dbff8 477}
74456259 478
74456259 479
725dbff8 480/*
481 * 'OutputLine()' - Output a line of graphics...
482 */
483
484void
6c5fbfa1 485OutputLine(ppd_file_t *ppd, /* I - PPD file */
486 cups_page_header_t *header, /* I - Page header */
ea19a116 487 int y) /* I - Line number */
725dbff8 488{
489 int i; /* Looping var */
490 unsigned char *ptr; /* Pointer into buffer */
6c5fbfa1 491 char *compptr; /* Pointer into compression buffer */
492 char repeat_char; /* Repeated character */
493 int repeat_count; /* Number of repeated characters */
494 static const char *hex = "0123456789ABCDEF";
495 /* Hex digits */
725dbff8 496
74456259 497
725dbff8 498 switch (ModelNumber)
499 {
500 case DYMO_3x0 :
501 /*
502 * See if the line is blank; if not, write it to the printer...
503 */
504
505 if (Buffer[0] ||
506 memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine - 1))
507 {
508 if (Feed)
509 {
510 while (Feed > 255)
511 {
512 printf("\033f\001%c", 255);
513 Feed -= 255;
514 }
515
516 printf("\033f\001%c", Feed);
517 Feed = 0;
518 }
74456259 519
725dbff8 520 putchar(0x16);
521 fwrite(Buffer, header->cupsBytesPerLine, 1, stdout);
522 fflush(stdout);
523
524#ifdef __sgi
525 /*
526 * This hack works around a bug in the IRIX serial port driver when
527 * run at high baud rates (e.g. 115200 baud)... This results in
528 * slightly slower label printing, but at least the labels come
529 * out properly.
530 */
531
532 sginap(1);
533#endif /* __sgi */
534 }
535 else
536 Feed ++;
537 break;
538
ea19a116 539 case ZEBRA_EPL_LINE :
540 printf("g%03d", header->cupsBytesPerLine);
541 fwrite(Buffer, 1, header->cupsBytesPerLine, stdout);
542 fflush(stdout);
543 break;
544
545 case ZEBRA_EPL_PAGE :
546 printf("GW0,%d,%d,1", y, header->cupsBytesPerLine);
547 fwrite(Buffer, 1, header->cupsBytesPerLine, stdout);
548 putchar('\n');
549 fflush(stdout);
550 break;
551
725dbff8 552 case ZEBRA_ZPL :
6c5fbfa1 553 /*
554 * Determine if this row is the same as the previous line.
555 * If so, output a ':' and return...
556 */
557
558 if (LastSet)
559 {
560 if (!memcmp(Buffer, LastBuffer, header->cupsBytesPerLine))
725dbff8 561 {
6c5fbfa1 562 putchar(':');
563 return;
725dbff8 564 }
6c5fbfa1 565 }
566
567 /*
568 * Convert the line to hex digits...
569 */
570
571 for (ptr = Buffer, compptr = CompBuffer, i = header->cupsBytesPerLine;
572 i > 0;
573 i --, ptr ++)
574 {
575 *compptr++ = hex[*ptr >> 4];
576 *compptr++ = hex[*ptr & 15];
577 }
578
579 *compptr = '\0';
580
581 /*
582 * Run-length compress the graphics...
583 */
584
585 for (compptr = CompBuffer, repeat_char = CompBuffer[0], repeat_count = 1;
586 *compptr;
587 compptr ++)
588 if (*compptr == repeat_char)
589 repeat_count ++;
725dbff8 590 else
6c5fbfa1 591 {
592 ZPLCompress(repeat_char, repeat_count);
593 repeat_char = *compptr;
594 repeat_count = 1;
595 }
596
597 if (repeat_char == '0')
598 {
599 /*
600 * Handle 0's on the end of the line...
601 */
725dbff8 602
6c5fbfa1 603 if (repeat_count & 1)
604 putchar('0');
605
606 putchar(',');
607 }
608 else
609 ZPLCompress(repeat_char, repeat_count);
610
611 /*
612 * Save this line for the next round...
613 */
614
615 memcpy(LastBuffer, Buffer, header->cupsBytesPerLine);
616 LastSet = 1;
725dbff8 617 break;
618 }
74456259 619}
620
621
6c5fbfa1 622/*
623 * 'ZPLCompress()' - Output a run-length compression sequence.
624 */
625
626void
627ZPLCompress(char repeat_char, /* I - Character to repeat */
628 int repeat_count) /* I - Number of repeated characters */
629{
630 if (repeat_count > 1)
631 {
632 /*
633 * Print as many z's as possible - they are the largest denomination
634 * representing 400 characters (zC stands for 400 adjacent C's)
635 */
636
637 while (repeat_count >= 400)
638 {
639 putchar('z');
640 repeat_count -= 400;
641 }
642
643 /*
644 * Then print 'g' through 'y' as multiples of 20 characters...
645 */
646
647 if (repeat_count >= 20)
648 {
649 putchar('f' + repeat_count / 20);
650 repeat_count %= 20;
651 }
652
653 /*
654 * Finally, print 'G' through 'Y' as 1 through 19 characters...
655 */
656
657 if (repeat_count > 0)
658 putchar('F' + repeat_count);
659 }
660
661 /*
662 * Then the character to be repeated...
663 */
664
665 putchar(repeat_char);
666}
667
668
74456259 669/*
670 * 'main()' - Main entry and processing of driver.
671 */
672
725dbff8 673int /* O - Exit status */
674main(int argc, /* I - Number of command-line arguments */
675 char *argv[]) /* I - Command-line arguments */
74456259 676{
725dbff8 677 int fd; /* File descriptor */
678 cups_raster_t *ras; /* Raster stream for printing */
679 cups_page_header_t header; /* Page header from file */
680 int y; /* Current line */
6c5fbfa1 681 ppd_file_t *ppd; /* PPD file */
682 int num_options; /* Number of options */
683 cups_option_t *options; /* Options */
74456259 684
685
686 /*
687 * Make sure status messages are not buffered...
688 */
689
690 setbuf(stderr, NULL);
691
692 /*
693 * Check command-line...
694 */
695
696 if (argc < 6 || argc > 7)
697 {
698 /*
699 * We don't have the correct number of arguments; write an error message
700 * and return.
701 */
702
703 fputs("ERROR: rastertodymo job-id user title copies options [file]\n", stderr);
704 return (1);
705 }
706
707 /*
708 * Open the page stream...
709 */
710
711 if (argc == 7)
712 {
725dbff8 713 if ((fd = open(argv[6], O_RDONLY)) == -1)
74456259 714 {
715 perror("ERROR: Unable to open raster file - ");
716 sleep(1);
717 return (1);
718 }
719 }
720 else
2e32fcdb 721 fd = 0;
74456259 722
2e32fcdb 723 ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
74456259 724
6c5fbfa1 725 /*
726 * Open the PPD file and apply options...
727 */
728
729 num_options = cupsParseOptions(argv[5], 0, &options);
730
731 if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL)
732 {
733 ppdMarkDefaults(ppd);
734 cupsMarkOptions(ppd, num_options, options);
735 }
736
74456259 737 /*
738 * Initialize the print device...
739 */
740
6c5fbfa1 741 Setup(ppd);
74456259 742
743 /*
744 * Process pages as needed...
745 */
746
725dbff8 747 Page = 0;
ea19a116 748 Canceled = 0;
74456259 749
750 while (cupsRasterReadHeader(ras, &header))
751 {
752 /*
753 * Write a status message with the page number and number of copies.
754 */
755
756 Page ++;
757
758 fprintf(stderr, "PAGE: %d 1\n", Page);
759
760 /*
761 * Start the page...
762 */
763
6c5fbfa1 764 StartPage(ppd, &header);
74456259 765
766 /*
767 * Loop for each line on the page...
768 */
769
ea19a116 770 for (y = 0; y < header.cupsHeight && !Canceled; y ++)
74456259 771 {
772 /*
773 * Let the user know how far we have progressed...
774 */
775
776 if ((y & 15) == 0)
777 fprintf(stderr, "INFO: Printing page %d, %d%% complete...\n", Page,
778 100 * y / header.cupsHeight);
779
780 /*
781 * Read a line of graphics...
782 */
783
784 if (cupsRasterReadPixels(ras, Buffer, header.cupsBytesPerLine) < 1)
785 break;
786
787 /*
725dbff8 788 * Write it to the printer...
74456259 789 */
790
6c5fbfa1 791 OutputLine(ppd, &header, y);
74456259 792 }
793
794 /*
795 * Eject the page...
796 */
797
6c5fbfa1 798 EndPage(ppd, &header);
725dbff8 799
ea19a116 800 if (Canceled)
725dbff8 801 break;
74456259 802 }
803
804 /*
805 * Close the raster stream...
806 */
807
808 cupsRasterClose(ras);
725dbff8 809 if (fd != 0)
2e32fcdb 810 close(fd);
74456259 811
6c5fbfa1 812 /*
813 * Close the PPD file and free the options...
814 */
815
816 ppdClose(ppd);
817 cupsFreeOptions(num_options, options);
818
74456259 819 /*
820 * If no pages were printed, send an error message...
821 */
822
823 if (Page == 0)
824 fputs("ERROR: No pages found!\n", stderr);
825 else
725dbff8 826 fputs("INFO: Ready to print.\n", stderr);
74456259 827
828 return (Page == 0);
829}
830
831
832/*
c9d3f842 833 * End of "$Id$".
74456259 834 */