]>
git.ipfire.org Git - thirdparty/cups.git/blob - filter/imagetops.c
2 * "$Id: imagetops.c 6649 2007-07-11 21:46:42Z mike $"
4 * Image file to PostScript filter for CUPS.
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1993-2007 by Easy Software Products.
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * main() - Main entry...
20 * ps_hex() - Print binary data as a series of hexadecimal numbers.
21 * ps_ascii85() - Print binary data as a series of base-85 numbers.
25 * Include necessary headers...
31 #include <cups/language-private.h>
39 int Flip
= 0, /* Flip/mirror pages */
40 XPosition
= 0, /* Horizontal position on page */
41 YPosition
= 0, /* Vertical position on page */
42 Collate
= 0, /* Collate copies? */
43 Copies
= 1; /* Number of copies */
50 static void ps_hex(cups_ib_t
*, int, int);
51 static void ps_ascii85(cups_ib_t
*, int, int);
55 * 'main()' - Main entry...
58 int /* O - Exit status */
59 main(int argc
, /* I - Number of command-line arguments */
60 char *argv
[]) /* I - Command-line arguments */
62 cups_image_t
*img
; /* Image to print */
63 float xprint
, /* Printable area */
65 xinches
, /* Total size in inches */
67 float xsize
, /* Total size in points */
71 float aspect
; /* Aspect ratio */
72 int xpages
, /* # x pages */
73 ypages
, /* # y pages */
74 xpage
, /* Current x page */
75 ypage
, /* Current y page */
76 page
; /* Current page number */
77 int xc0
, yc0
, /* Corners of the page in image coords */
79 cups_ib_t
*row
; /* Current row */
80 int y
; /* Current Y coordinate in image */
81 int colorspace
; /* Output colorspace */
82 int out_offset
, /* Offset into output buffer */
83 out_length
; /* Length of output buffer */
84 ppd_file_t
*ppd
; /* PPD file */
85 ppd_choice_t
*choice
; /* PPD option choice */
86 int num_options
; /* Number of print options */
87 cups_option_t
*options
; /* Print options */
88 const char *val
; /* Option value */
89 int slowcollate
; /* Collate copies the slow way */
90 float g
; /* Gamma correction value */
91 float b
; /* Brightness factor */
92 float zoom
; /* Zoom facter */
93 int xppi
, yppi
; /* Pixels-per-inch */
94 int hue
, sat
; /* Hue and saturation adjustment */
95 int realcopies
, /* Real copies being printed */
96 emit_jcl
; /* Emit JCL? */
97 float left
, top
; /* Left and top of image */
98 char filename
[1024]; /* Name of file to print */
99 time_t curtime
; /* Current time */
100 struct tm
*curtm
; /* Current date */
101 char curdate
[255]; /* Current date string */
105 * Make sure status messages are not buffered...
108 setbuf(stderr
, NULL
);
111 * Ignore broken pipe signals...
114 signal(SIGPIPE
, SIG_IGN
);
117 * Check command-line...
120 if (argc
< 6 || argc
> 7)
122 _cupsLangPrintf(stderr
,
123 _("Usage: %s job-id user title copies options file"),
129 * Copy stdin as needed...
134 int fd
; /* File to write to */
135 char buffer
[8192]; /* Buffer to read into */
136 int bytes
; /* # of bytes to read */
139 if ((fd
= cupsTempFd(filename
, sizeof(filename
))) < 0)
141 _cupsLangPrintError("ERROR", _("Unable to copy print file"));
145 fprintf(stderr
, "DEBUG: imagetops - copying to temp print file \"%s\".\n",
148 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), stdin
)) > 0)
149 write(fd
, buffer
, bytes
);
154 strlcpy(filename
, argv
[6], sizeof(filename
));
157 * Process command-line options and write the prolog...
168 Copies
= atoi(argv
[4]);
171 num_options
= cupsParseOptions(argv
[5], 0, &options
);
173 ppd
= SetCommonOptions(num_options
, options
, 0);
175 if ((val
= cupsGetOption("multiple-document-handling", num_options
, options
)) != NULL
)
178 * This IPP attribute is unnecessarily complicated...
180 * single-document, separate-documents-collated-copies, and
181 * single-document-new-sheet all require collated copies.
183 * separate-documents-uncollated-copies allows for uncollated copies.
186 Collate
= strcasecmp(val
, "separate-documents-uncollated-copies") != 0;
189 if ((val
= cupsGetOption("Collate", num_options
, options
)) != NULL
&&
190 strcasecmp(val
, "True") == 0)
193 if ((val
= cupsGetOption("gamma", num_options
, options
)) != NULL
)
196 * Get gamma value from 1 to 10000...
199 g
= atoi(val
) * 0.001f
;
207 if ((val
= cupsGetOption("brightness", num_options
, options
)) != NULL
)
210 * Get brightness value from 10 to 1000.
213 b
= atoi(val
) * 0.01f
;
221 if ((val
= cupsGetOption("scaling", num_options
, options
)) != NULL
)
222 zoom
= atoi(val
) * 0.01;
223 else if ((val
= cupsGetOption("fitplot", num_options
, options
)) != NULL
&&
224 !strcasecmp(val
, "true"))
226 else if ((val
= cupsGetOption("fit-to-page", num_options
, options
)) != NULL
&&
227 !strcasecmp(val
, "true"))
230 if ((val
= cupsGetOption("ppi", num_options
, options
)) != NULL
)
231 if (sscanf(val
, "%dx%d", &xppi
, &yppi
) < 2)
234 if ((val
= cupsGetOption("position", num_options
, options
)) != NULL
)
236 if (strcasecmp(val
, "center") == 0)
241 else if (strcasecmp(val
, "top") == 0)
246 else if (strcasecmp(val
, "left") == 0)
251 else if (strcasecmp(val
, "right") == 0)
256 else if (strcasecmp(val
, "top-left") == 0)
261 else if (strcasecmp(val
, "top-right") == 0)
266 else if (strcasecmp(val
, "bottom") == 0)
271 else if (strcasecmp(val
, "bottom-left") == 0)
276 else if (strcasecmp(val
, "bottom-right") == 0)
283 if ((val
= cupsGetOption("saturation", num_options
, options
)) != NULL
)
286 if ((val
= cupsGetOption("hue", num_options
, options
)) != NULL
)
289 if ((choice
= ppdFindMarkedChoice(ppd
, "MirrorPrint")) != NULL
)
291 val
= choice
->choice
;
295 val
= cupsGetOption("mirror", num_options
, options
);
297 if (val
&& (!strcasecmp(val
, "true") || !strcasecmp(val
, "on") ||
298 !strcasecmp(val
, "yes")))
301 if ((val
= cupsGetOption("emit-jcl", num_options
, options
)) != NULL
&&
302 (!strcasecmp(val
, "false") || !strcasecmp(val
, "off") ||
303 !strcasecmp(val
, "no") || !strcmp(val
, "0")))
309 * Open the input image to print...
312 colorspace
= ColorDevice
? CUPS_IMAGE_RGB_CMYK
: CUPS_IMAGE_WHITE
;
314 img
= cupsImageOpen(filename
, colorspace
, CUPS_IMAGE_WHITE
, sat
, hue
, NULL
);
321 _cupsLangPrintFilter(stderr
, "ERROR",
322 _("The print file could not be opened."));
327 colorspace
= cupsImageGetColorSpace(img
);
330 * Scale as necessary...
333 if (zoom
== 0.0 && xppi
== 0)
335 xppi
= cupsImageGetXPPI(img
);
336 yppi
= cupsImageGetYPPI(img
);
342 fprintf(stderr
, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n",
348 * Scale the image as neccesary to match the desired pixels-per-inch.
353 xprint
= (PageTop
- PageBottom
) / 72.0;
354 yprint
= (PageRight
- PageLeft
) / 72.0;
358 xprint
= (PageRight
- PageLeft
) / 72.0;
359 yprint
= (PageTop
- PageBottom
) / 72.0;
362 fprintf(stderr
, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
365 xinches
= (float)cupsImageGetWidth(img
) / (float)xppi
;
366 yinches
= (float)cupsImageGetHeight(img
) / (float)yppi
;
368 fprintf(stderr
, "DEBUG: Image size is %.1f x %.1f inches...\n",
371 if ((val
= cupsGetOption("natural-scaling", num_options
, options
)) != NULL
)
373 xinches
= xinches
* atoi(val
) / 100;
374 yinches
= yinches
* atoi(val
) / 100;
377 if (cupsGetOption("orientation-requested", num_options
, options
) == NULL
&&
378 cupsGetOption("landscape", num_options
, options
) == NULL
)
381 * Rotate the image if it will fit landscape but not portrait...
384 fputs("DEBUG: Auto orientation...\n", stderr
);
386 if ((xinches
> xprint
|| yinches
> yprint
) &&
387 xinches
<= yprint
&& yinches
<= xprint
)
390 * Rotate the image as needed...
393 fputs("DEBUG: Using landscape orientation...\n", stderr
);
395 Orientation
= (Orientation
+ 1) & 3;
405 * Scale percentage of page size...
408 xprint
= (PageRight
- PageLeft
) / 72.0;
409 yprint
= (PageTop
- PageBottom
) / 72.0;
410 aspect
= (float)cupsImageGetYPPI(img
) / (float)cupsImageGetXPPI(img
);
412 fprintf(stderr
, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
415 fprintf(stderr
, "DEBUG: cupsImageGetXPPI(img) = %d, cupsImageGetYPPI(img) = %d, aspect = %f\n",
416 cupsImageGetXPPI(img
), cupsImageGetYPPI(img
), aspect
);
418 xsize
= xprint
* zoom
;
419 ysize
= xsize
* cupsImageGetHeight(img
) / cupsImageGetWidth(img
) / aspect
;
421 if (ysize
> (yprint
* zoom
))
423 ysize
= yprint
* zoom
;
424 xsize
= ysize
* cupsImageGetWidth(img
) * aspect
/ cupsImageGetHeight(img
);
427 xsize2
= yprint
* zoom
;
428 ysize2
= xsize2
* cupsImageGetHeight(img
) / cupsImageGetWidth(img
) / aspect
;
430 if (ysize2
> (xprint
* zoom
))
432 ysize2
= xprint
* zoom
;
433 xsize2
= ysize2
* cupsImageGetWidth(img
) * aspect
/ cupsImageGetHeight(img
);
436 fprintf(stderr
, "DEBUG: Portrait size is %.2f x %.2f inches\n", xsize
, ysize
);
437 fprintf(stderr
, "DEBUG: Landscape size is %.2f x %.2f inches\n", xsize2
, ysize2
);
439 if (cupsGetOption("orientation-requested", num_options
, options
) == NULL
&&
440 cupsGetOption("landscape", num_options
, options
) == NULL
)
443 * Choose the rotation with the largest area, but prefer
444 * portrait if they are equal...
447 fputs("DEBUG: Auto orientation...\n", stderr
);
449 if ((xsize
* ysize
) < (xsize2
* xsize2
))
452 * Do landscape orientation...
455 fputs("DEBUG: Using landscape orientation...\n", stderr
);
460 xprint
= (PageTop
- PageBottom
) / 72.0;
461 yprint
= (PageRight
- PageLeft
) / 72.0;
466 * Do portrait orientation...
469 fputs("DEBUG: Using portrait orientation...\n", stderr
);
476 else if (Orientation
& 1)
478 fputs("DEBUG: Using landscape orientation...\n", stderr
);
482 xprint
= (PageTop
- PageBottom
) / 72.0;
483 yprint
= (PageRight
- PageLeft
) / 72.0;
487 fputs("DEBUG: Using portrait orientation...\n", stderr
);
491 xprint
= (PageRight
- PageLeft
) / 72.0;
492 yprint
= (PageTop
- PageBottom
) / 72.0;
497 * Compute the number of pages to print and the size of the image on each
501 xpages
= ceil(xinches
/ xprint
);
502 ypages
= ceil(yinches
/ yprint
);
504 xprint
= xinches
/ xpages
;
505 yprint
= yinches
/ ypages
;
507 fprintf(stderr
, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n",
508 xpages
, xprint
, ypages
, yprint
);
511 * Update the page size for custom sizes...
514 if ((choice
= ppdFindMarkedChoice(ppd
, "PageSize")) != NULL
&&
515 strcasecmp(choice
->choice
, "Custom") == 0)
517 float width
, /* New width in points */
518 length
; /* New length in points */
519 char s
[255]; /* New custom page size... */
523 * Use the correct width and length for the current orientation...
528 width
= yprint
* 72.0;
529 length
= xprint
* 72.0;
533 width
= xprint
* 72.0;
534 length
= yprint
* 72.0;
538 * Add margins to page size...
541 width
+= ppd
->custom_margins
[0] + ppd
->custom_margins
[2];
542 length
+= ppd
->custom_margins
[1] + ppd
->custom_margins
[3];
545 * Enforce minimums...
548 if (width
< ppd
->custom_min
[0])
549 width
= ppd
->custom_min
[0];
551 if (length
< ppd
->custom_min
[1])
552 length
= ppd
->custom_min
[1];
554 fprintf(stderr
, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n",
555 width
/ 72.0, length
/ 72.0);
558 * Set the new custom size...
561 sprintf(s
, "Custom.%.0fx%.0f", width
, length
);
562 ppdMarkOption(ppd
, "PageSize", s
);
565 * Update page variables...
570 PageLeft
= ppd
->custom_margins
[0];
571 PageRight
= width
- ppd
->custom_margins
[2];
572 PageBottom
= ppd
->custom_margins
[1];
573 PageTop
= length
- ppd
->custom_margins
[3];
577 * See if we need to collate, and if so how we need to do it...
580 if (xpages
== 1 && ypages
== 1)
583 slowcollate
= Collate
&& ppdFindOption(ppd
, "Collate") == NULL
;
585 if (Copies
> 1 && !slowcollate
)
594 * Write any "exit server" options that have been selected...
597 ppdEmit(ppd
, stdout
, PPD_ORDER_EXIT
);
600 * Write any JCL commands that are needed to print PostScript code...
604 ppdEmitJCL(ppd
, stdout
, atoi(argv
[1]), argv
[2], argv
[3]);
607 * Start sending the document with any commands needed...
610 curtime
= time(NULL
);
611 curtm
= localtime(&curtime
);
613 puts("%!PS-Adobe-3.0");
614 printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft
, PageBottom
,
616 printf("%%%%LanguageLevel: %d\n", LanguageLevel
);
617 printf("%%%%Pages: %d\n", xpages
* ypages
* Copies
);
618 puts("%%DocumentData: Clean7Bit");
619 puts("%%DocumentNeededResources: font Helvetica-Bold");
620 puts("%%Creator: imagetops/" CUPS_SVERSION
);
621 strftime(curdate
, sizeof(curdate
), "%c", curtm
);
622 printf("%%%%CreationDate: %s\n", curdate
);
623 WriteTextComment("Title", argv
[3]);
624 WriteTextComment("For", argv
[2]);
626 puts("%%Orientation: Landscape");
628 puts("%%Orientation: Portrait");
629 puts("%%EndComments");
630 puts("%%BeginProlog");
632 if (ppd
!= NULL
&& ppd
->patches
!= NULL
)
635 ppdEmit(ppd
, stdout
, PPD_ORDER_DOCUMENT
);
636 ppdEmit(ppd
, stdout
, PPD_ORDER_ANY
);
637 ppdEmit(ppd
, stdout
, PPD_ORDER_PROLOG
);
639 if (g
!= 1.0 || b
!= 1.0)
640 printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
641 "ifelse %.3f mul } bind settransfer\n", g
, b
);
647 WriteLabelProlog(cupsGetOption("page-label", num_options
, options
),
648 PageBottom
, PageTop
, PageWidth
);
652 WriteLabelProlog(cupsGetOption("page-label", num_options
, options
),
653 PageLeft
, PageRight
, PageLength
);
657 WriteLabelProlog(cupsGetOption("page-label", num_options
, options
),
658 PageLength
- PageTop
, PageLength
- PageBottom
,
663 WriteLabelProlog(cupsGetOption("page-label", num_options
, options
),
664 PageWidth
- PageRight
, PageWidth
- PageLeft
,
671 if (ppd
== NULL
|| ppd
->language_level
== 1)
672 printf("/#copies %d def\n", realcopies
);
674 printf("<</NumCopies %d>>setpagedevice\n", realcopies
);
680 * Output the pages...
683 row
= malloc(cupsImageGetWidth(img
) * abs(colorspace
) + 3);
685 fprintf(stderr
, "DEBUG: XPosition=%d, YPosition=%d, Orientation=%d\n",
686 XPosition
, YPosition
, Orientation
);
687 fprintf(stderr
, "DEBUG: xprint=%.0f, yprint=%.0f\n", xprint
, yprint
);
688 fprintf(stderr
, "DEBUG: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f\n",
689 PageLeft
, PageRight
, PageWidth
);
690 fprintf(stderr
, "DEBUG: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f\n",
691 PageBottom
, PageTop
, PageLength
);
702 left
= (PageRight
+ PageLeft
- xprint
* 72) / 2;
705 left
= PageRight
- xprint
* 72;
712 top
= PageBottom
+ yprint
* 72;
715 top
= (PageTop
+ PageBottom
+ yprint
* 72) / 2;
730 left
= (PageTop
+ PageBottom
- xprint
* 72) / 2;
733 left
= PageTop
- xprint
* 72;
740 top
= PageLeft
+ yprint
* 72;
743 top
= (PageRight
+ PageLeft
+ yprint
* 72) / 2;
758 left
= (PageRight
+ PageLeft
- xprint
* 72) / 2;
761 left
= PageRight
- xprint
* 72;
768 top
= PageBottom
+ yprint
* 72;
771 top
= (PageTop
+ PageBottom
+ yprint
* 72) / 2;
786 left
= (PageTop
+ PageBottom
- xprint
* 72) / 2;
789 left
= PageTop
- xprint
* 72;
796 top
= PageLeft
+ yprint
* 72;
799 top
= (PageRight
+ PageLeft
+ yprint
* 72) / 2;
808 fprintf(stderr
, "DEBUG: left=%.2f, top=%.2f\n", left
, top
);
810 for (page
= 1; Copies
> 0; Copies
--)
811 for (xpage
= 0; xpage
< xpages
; xpage
++)
812 for (ypage
= 0; ypage
< ypages
; ypage
++, page
++)
814 if (ppd
&& ppd
->num_filters
== 0)
815 fprintf(stderr
, "PAGE: %d %d\n", page
, realcopies
);
817 _cupsLangPrintFilter(stderr
, "INFO", _("Printing page %d."), page
);
819 printf("%%%%Page: %d %d\n", page
, page
);
821 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
826 printf("%.0f 0 translate -1 1 scale\n", PageWidth
);
830 case 1 : /* Landscape */
831 printf("%.0f 0 translate 90 rotate\n", PageWidth
);
833 case 2 : /* Reverse Portrait */
834 printf("%.0f %.0f translate 180 rotate\n", PageWidth
, PageLength
);
836 case 3 : /* Reverse Landscape */
837 printf("0 %.0f translate -90 rotate\n", PageLength
);
843 xc0
= cupsImageGetWidth(img
) * xpage
/ xpages
;
844 xc1
= cupsImageGetWidth(img
) * (xpage
+ 1) / xpages
- 1;
845 yc0
= cupsImageGetHeight(img
) * ypage
/ ypages
;
846 yc1
= cupsImageGetHeight(img
) * (ypage
+ 1) / ypages
- 1;
848 printf("%.1f %.1f translate\n", left
, top
);
850 printf("%.3f %.3f scale\n\n",
851 xprint
* 72.0 / (xc1
- xc0
+ 1),
852 yprint
* 72.0 / (yc1
- yc0
+ 1));
854 if (LanguageLevel
== 1)
856 printf("/picture %d string def\n", (xc1
- xc0
+ 1) * abs(colorspace
));
857 printf("%d %d 8[1 0 0 -1 0 1]", (xc1
- xc0
+ 1), (yc1
- yc0
+ 1));
859 if (colorspace
== CUPS_IMAGE_WHITE
)
860 puts("{currentfile picture readhexstring pop} image");
862 printf("{currentfile picture readhexstring pop} false %d colorimage\n",
865 for (y
= yc0
; y
<= yc1
; y
++)
867 cupsImageGetRow(img
, xc0
, y
, xc1
- xc0
+ 1, row
);
868 ps_hex(row
, (xc1
- xc0
+ 1) * abs(colorspace
), y
== yc1
);
875 case CUPS_IMAGE_WHITE
:
876 puts("/DeviceGray setcolorspace");
878 case CUPS_IMAGE_RGB
:
879 puts("/DeviceRGB setcolorspace");
881 case CUPS_IMAGE_CMYK
:
882 puts("/DeviceCMYK setcolorspace");
890 "/BitsPerComponent 8",
891 xc1
- xc0
+ 1, yc1
- yc0
+ 1);
895 case CUPS_IMAGE_WHITE
:
896 fputs("/Decode[0 1]", stdout
);
898 case CUPS_IMAGE_RGB
:
899 fputs("/Decode[0 1 0 1 0 1]", stdout
);
901 case CUPS_IMAGE_CMYK
:
902 fputs("/Decode[0 1 0 1 0 1 0 1]", stdout
);
906 fputs("\n/DataSource currentfile/ASCII85Decode filter", stdout
);
908 if (((xc1
- xc0
+ 1) / xprint
) < 100.0)
909 fputs("/Interpolate true", stdout
);
911 puts("/ImageMatrix[1 0 0 -1 0 1]>>image");
913 for (y
= yc0
, out_offset
= 0; y
<= yc1
; y
++)
915 cupsImageGetRow(img
, xc0
, y
, xc1
- xc0
+ 1, row
+ out_offset
);
917 out_length
= (xc1
- xc0
+ 1) * abs(colorspace
) + out_offset
;
918 out_offset
= out_length
& 3;
920 ps_ascii85(row
, out_length
, y
== yc1
);
923 memcpy(row
, row
+ out_length
- out_offset
, out_offset
);
936 * End the job with the appropriate JCL command or CTRL-D otherwise.
941 if (ppd
&& ppd
->jcl_end
)
942 ppdEmitJCLEnd(ppd
, stdout
);
959 * 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
963 ps_hex(cups_ib_t
*data
, /* I - Data to print */
964 int length
, /* I - Number of bytes to print */
965 int last_line
) /* I - Last line of raster data? */
967 static int col
= 0; /* Current column */
968 static char *hex
= "0123456789ABCDEF";
975 * Put the hex chars out to the file; note that we don't use printf()
976 * for speed reasons...
979 putchar(hex
[*data
>> 4]);
980 putchar(hex
[*data
& 15]);
993 if (last_line
&& col
)
1002 * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
1006 ps_ascii85(cups_ib_t
*data
, /* I - Data to print */
1007 int length
, /* I - Number of bytes to print */
1008 int last_line
) /* I - Last line of raster data? */
1010 unsigned b
; /* Binary data word */
1011 unsigned char c
[5]; /* ASCII85 encoded chars */
1012 static int col
= 0; /* Current column */
1017 b
= (((((data
[0] << 8) | data
[1]) << 8) | data
[2]) << 8) | data
[3];
1026 c
[4] = (b
% 85) + '!';
1028 c
[3] = (b
% 85) + '!';
1030 c
[2] = (b
% 85) + '!';
1032 c
[1] = (b
% 85) + '!';
1036 fwrite(c
, 5, 1, stdout
);
1054 memset(data
+ length
, 0, 4 - length
);
1055 b
= (((((data
[0] << 8) | data
[1]) << 8) | data
[2]) << 8) | data
[3];
1057 c
[4] = (b
% 85) + '!';
1059 c
[3] = (b
% 85) + '!';
1061 c
[2] = (b
% 85) + '!';
1063 c
[1] = (b
% 85) + '!';
1067 fwrite(c
, length
+ 1, 1, stdout
);
1077 * End of "$Id: imagetops.c 6649 2007-07-11 21:46:42Z mike $".