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