]>
git.ipfire.org Git - thirdparty/cups.git/blob - filter/imagetops.c
2 * "$Id: imagetops.c 4741 2005-10-02 04:25:52Z mike $"
4 * Image file to PostScript filter for the Common UNIX Printing System (CUPS).
6 * Copyright 1993-2005 by Easy Software Products.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * main() - Main entry...
29 * ps_hex() - Print binary data as a series of hexadecimal numbers.
30 * ps_ascii85() - Print binary data as a series of base-85 numbers.
34 * Include necessary headers...
46 int Flip
= 0, /* Flip/mirror pages */
47 XPosition
= 0, /* Horizontal position on page */
48 YPosition
= 0, /* Vertical position on page */
49 Collate
= 0, /* Collate copies? */
50 Copies
= 1; /* Number of copies */
57 static void ps_hex(cups_ib_t
*, int, int);
58 static void ps_ascii85(cups_ib_t
*, int, int);
62 * 'main()' - Main entry...
65 int /* O - Exit status */
66 main(int argc
, /* I - Number of command-line arguments */
67 char *argv
[]) /* I - Command-line arguments */
69 cups_image_t
*img
; /* Image to print */
70 float xprint
, /* Printable area */
72 xinches
, /* Total size in inches */
74 float xsize
, /* Total size in points */
78 float aspect
; /* Aspect ratio */
79 int xpages
, /* # x pages */
80 ypages
, /* # y pages */
81 xpage
, /* Current x page */
82 ypage
, /* Current y page */
83 page
; /* Current page number */
84 int x0
, y0
, /* Corners of the page in image coords */
86 cups_ib_t
*row
; /* Current row */
87 int y
; /* Current Y coordinate in image */
88 int colorspace
; /* Output colorspace */
89 int out_offset
, /* Offset into output buffer */
90 out_length
; /* Length of output buffer */
91 ppd_file_t
*ppd
; /* PPD file */
92 ppd_choice_t
*choice
; /* PPD option choice */
93 int num_options
; /* Number of print options */
94 cups_option_t
*options
; /* Print options */
95 const char *val
; /* Option value */
96 int slowcollate
; /* Collate copies the slow way */
97 float g
; /* Gamma correction value */
98 float b
; /* Brightness factor */
99 float zoom
; /* Zoom facter */
100 int xppi
, yppi
; /* Pixels-per-inch */
101 int hue
, sat
; /* Hue and saturation adjustment */
102 int realcopies
; /* Real copies being printed */
103 float left
, top
; /* Left and top of image */
104 char filename
[1024]; /* Name of file to print */
105 time_t curtime
; /* Current time */
106 struct tm
*curtm
; /* Current date */
107 char curdate
[255]; /* Current date string */
111 * Make sure status messages are not buffered...
114 setbuf(stderr
, NULL
);
117 * Check command-line...
120 if (argc
< 6 || argc
> 7)
122 fputs("ERROR: imagetops job-id user title copies options [file]\n", stderr
);
126 fprintf(stderr
, "INFO: %s %s %s %s %s %s %s\n", argv
[0], argv
[1], argv
[2],
127 argv
[3], argv
[4], argv
[5], argv
[6] ? argv
[6] : "(null)");
130 * Copy stdin as needed...
135 int fd
; /* File to write to */
136 char buffer
[8192]; /* Buffer to read into */
137 int bytes
; /* # of bytes to read */
140 if ((fd
= cupsTempFd(filename
, sizeof(filename
))) < 0)
142 perror("ERROR: Unable to copy image file");
146 fprintf(stderr
, "DEBUG: imagetoraster - copying to temp print file \"%s\"\n",
149 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), stdin
)) > 0)
150 write(fd
, buffer
, bytes
);
155 strlcpy(filename
, argv
[6], sizeof(filename
));
158 * Process command-line options and write the prolog...
169 Copies
= atoi(argv
[4]);
172 num_options
= cupsParseOptions(argv
[5], 0, &options
);
174 ppd
= SetCommonOptions(num_options
, options
, 0);
176 if ((val
= cupsGetOption("multiple-document-handling", num_options
, options
)) != NULL
)
179 * This IPP attribute is unnecessarily complicated...
181 * single-document, separate-documents-collated-copies, and
182 * single-document-new-sheet all require collated copies.
184 * separate-documents-uncollated-copies allows for uncollated copies.
187 Collate
= strcasecmp(val
, "separate-documents-uncollated-copies") != 0;
190 if ((val
= cupsGetOption("Collate", num_options
, options
)) != NULL
&&
191 strcasecmp(val
, "True") == 0)
194 if ((val
= cupsGetOption("gamma", num_options
, options
)) != NULL
)
195 g
= atoi(val
) * 0.001f
;
197 if ((val
= cupsGetOption("brightness", num_options
, options
)) != NULL
)
198 b
= atoi(val
) * 0.01f
;
200 if ((val
= cupsGetOption("scaling", num_options
, options
)) != NULL
)
201 zoom
= atoi(val
) * 0.01;
203 if ((val
= cupsGetOption("ppi", num_options
, options
)) != NULL
)
204 if (sscanf(val
, "%dx%d", &xppi
, &yppi
) < 2)
207 if ((val
= cupsGetOption("position", num_options
, options
)) != NULL
)
209 if (strcasecmp(val
, "center") == 0)
214 else if (strcasecmp(val
, "top") == 0)
219 else if (strcasecmp(val
, "left") == 0)
224 else if (strcasecmp(val
, "right") == 0)
229 else if (strcasecmp(val
, "top-left") == 0)
234 else if (strcasecmp(val
, "top-right") == 0)
239 else if (strcasecmp(val
, "bottom") == 0)
244 else if (strcasecmp(val
, "bottom-left") == 0)
249 else if (strcasecmp(val
, "bottom-right") == 0)
256 if ((val
= cupsGetOption("saturation", num_options
, options
)) != NULL
)
259 if ((val
= cupsGetOption("hue", num_options
, options
)) != NULL
)
262 if ((val
= cupsGetOption("mirror", num_options
, options
)) != NULL
&&
263 strcasecmp(val
, "True") == 0)
267 * Open the input image to print...
270 colorspace
= ColorDevice
? CUPS_IMAGE_RGB_CMYK
: CUPS_IMAGE_WHITE
;
272 img
= cupsImageOpen(filename
, colorspace
, CUPS_IMAGE_WHITE
, sat
, hue
, NULL
);
279 fputs("ERROR: Unable to open image file for printing!\n", stderr
);
284 colorspace
= cupsImageGetColorSpace(img
);
287 * Scale as necessary...
290 if (zoom
== 0.0 && xppi
== 0)
292 xppi
= cupsImageGetXPPI(img
);
293 yppi
= cupsImageGetYPPI(img
);
299 fprintf(stderr
, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n",
305 * Scale the image as neccesary to match the desired pixels-per-inch.
310 xprint
= (PageTop
- PageBottom
) / 72.0;
311 yprint
= (PageRight
- PageLeft
) / 72.0;
315 xprint
= (PageRight
- PageLeft
) / 72.0;
316 yprint
= (PageTop
- PageBottom
) / 72.0;
319 fprintf(stderr
, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
322 xinches
= (float)cupsImageGetWidth(img
) / (float)xppi
;
323 yinches
= (float)cupsImageGetHeight(img
) / (float)yppi
;
325 fprintf(stderr
, "DEBUG: Image size is %.1f x %.1f inches...\n",
328 if ((val
= cupsGetOption("natural-scaling", num_options
, options
)) != NULL
)
330 xinches
= xinches
* atoi(val
) / 100;
331 yinches
= yinches
* atoi(val
) / 100;
334 if (cupsGetOption("orientation-requested", num_options
, options
) == NULL
&&
335 cupsGetOption("landscape", num_options
, options
) == NULL
)
338 * Rotate the image if it will fit landscape but not portrait...
341 fputs("DEBUG: Auto orientation...\n", stderr
);
343 if ((xinches
> xprint
|| yinches
> yprint
) &&
344 xinches
<= yprint
&& yinches
<= xprint
)
347 * Rotate the image as needed...
350 fputs("DEBUG: Using landscape orientation...\n", stderr
);
352 Orientation
= (Orientation
+ 1) & 3;
362 * Scale percentage of page size...
365 xprint
= (PageRight
- PageLeft
) / 72.0;
366 yprint
= (PageTop
- PageBottom
) / 72.0;
367 aspect
= (float)cupsImageGetYPPI(img
) / (float)cupsImageGetXPPI(img
);
369 fprintf(stderr
, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
372 fprintf(stderr
, "DEBUG: cupsImageGetXPPI(img) = %d, cupsImageGetYPPI(img) = %d, aspect = %f\n",
373 cupsImageGetXPPI(img
), cupsImageGetYPPI(img
), aspect
);
375 xsize
= xprint
* zoom
;
376 ysize
= xsize
* cupsImageGetHeight(img
) / cupsImageGetWidth(img
) / aspect
;
378 if (ysize
> (yprint
* zoom
))
380 ysize
= yprint
* zoom
;
381 xsize
= ysize
* cupsImageGetWidth(img
) * aspect
/ cupsImageGetHeight(img
);
384 xsize2
= yprint
* zoom
;
385 ysize2
= xsize2
* cupsImageGetHeight(img
) / cupsImageGetWidth(img
) / aspect
;
387 if (ysize2
> (xprint
* zoom
))
389 ysize2
= xprint
* zoom
;
390 xsize2
= ysize2
* cupsImageGetWidth(img
) * aspect
/ cupsImageGetHeight(img
);
393 fprintf(stderr
, "DEBUG: Portrait size is %.2f x %.2f inches\n", xsize
, ysize
);
394 fprintf(stderr
, "DEBUG: Landscape size is %.2f x %.2f inches\n", xsize2
, ysize2
);
396 if (cupsGetOption("orientation-requested", num_options
, options
) == NULL
&&
397 cupsGetOption("landscape", num_options
, options
) == NULL
)
400 * Choose the rotation with the largest area, but prefer
401 * portrait if they are equal...
404 fputs("DEBUG: Auto orientation...\n", stderr
);
406 if ((xsize
* ysize
) < (xsize2
* xsize2
))
409 * Do landscape orientation...
412 fputs("DEBUG: Using landscape orientation...\n", stderr
);
417 xprint
= (PageTop
- PageBottom
) / 72.0;
418 yprint
= (PageRight
- PageLeft
) / 72.0;
423 * Do portrait orientation...
426 fputs("DEBUG: Using portrait orientation...\n", stderr
);
433 else if (Orientation
& 1)
435 fputs("DEBUG: Using landscape orientation...\n", stderr
);
439 xprint
= (PageTop
- PageBottom
) / 72.0;
440 yprint
= (PageRight
- PageLeft
) / 72.0;
444 fputs("DEBUG: Using portrait orientation...\n", stderr
);
448 xprint
= (PageRight
- PageLeft
) / 72.0;
449 yprint
= (PageTop
- PageBottom
) / 72.0;
454 * Compute the number of pages to print and the size of the image on each
458 xpages
= ceil(xinches
/ xprint
);
459 ypages
= ceil(yinches
/ yprint
);
461 xprint
= xinches
/ xpages
;
462 yprint
= yinches
/ ypages
;
464 fprintf(stderr
, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n",
465 xpages
, xprint
, ypages
, yprint
);
468 * Update the page size for custom sizes...
471 if ((choice
= ppdFindMarkedChoice(ppd
, "PageSize")) != NULL
&&
472 strcasecmp(choice
->choice
, "Custom") == 0)
474 float width
, /* New width in points */
475 length
; /* New length in points */
476 char s
[255]; /* New custom page size... */
480 * Use the correct width and length for the current orientation...
485 width
= yprint
* 72.0;
486 length
= xprint
* 72.0;
490 width
= xprint
* 72.0;
491 length
= yprint
* 72.0;
495 * Add margins to page size...
498 width
+= ppd
->custom_margins
[0] + ppd
->custom_margins
[2];
499 length
+= ppd
->custom_margins
[1] + ppd
->custom_margins
[3];
502 * Enforce minimums...
505 if (width
< ppd
->custom_min
[0])
506 width
= ppd
->custom_min
[0];
508 if (length
< ppd
->custom_min
[1])
509 length
= ppd
->custom_min
[1];
511 fprintf(stderr
, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n",
512 width
/ 72.0, length
/ 72.0);
515 * Set the new custom size...
518 sprintf(s
, "Custom.%.0fx%.0f", width
, length
);
519 ppdMarkOption(ppd
, "PageSize", s
);
522 * Update page variables...
527 PageLeft
= ppd
->custom_margins
[0];
528 PageRight
= width
- ppd
->custom_margins
[2];
529 PageBottom
= ppd
->custom_margins
[1];
530 PageTop
= length
- ppd
->custom_margins
[3];
534 * See if we need to collate, and if so how we need to do it...
537 if (xpages
== 1 && ypages
== 1)
540 slowcollate
= Collate
&& ppdFindOption(ppd
, "Collate") == NULL
;
542 if (Copies
> 1 && !slowcollate
)
551 * Write any "exit server" options that have been selected...
554 ppdEmit(ppd
, stdout
, PPD_ORDER_EXIT
);
557 * Write any JCL commands that are needed to print PostScript code...
560 ppdEmitJCL(ppd
, stdout
, atoi(argv
[1]), argv
[2], argv
[3]);
563 * Start sending the document with any commands needed...
566 curtime
= time(NULL
);
567 curtm
= localtime(&curtime
);
569 puts("%!PS-Adobe-3.0");
570 printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft
, PageBottom
,
572 printf("%%%%LanguageLevel: %d\n", LanguageLevel
);
573 printf("%%%%Pages: %d\n", xpages
* ypages
* Copies
);
574 puts("%%DocumentData: Clean7Bit");
575 puts("%%DocumentNeededResources: font Helvetica-Bold");
576 puts("%%Creator: imagetops/" CUPS_SVERSION
);
577 strftime(curdate
, sizeof(curdate
), "%c", curtm
);
578 printf("%%%%CreationDate: %s\n", curdate
);
579 printf("%%%%Title: %s\n", argv
[3]);
580 printf("%%%%For: %s\n", argv
[2]);
582 puts("%%Orientation: Landscape");
584 puts("%%Orientation: Portrait");
585 puts("%%EndComments");
586 puts("%%BeginProlog");
588 if (ppd
!= NULL
&& ppd
->patches
!= NULL
)
591 ppdEmit(ppd
, stdout
, PPD_ORDER_DOCUMENT
);
592 ppdEmit(ppd
, stdout
, PPD_ORDER_ANY
);
593 ppdEmit(ppd
, stdout
, PPD_ORDER_PROLOG
);
595 if (g
!= 1.0 || b
!= 1.0)
596 printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
597 "ifelse %.3f mul } bind settransfer\n", g
, b
);
603 WriteLabelProlog(cupsGetOption("page-label", num_options
, options
),
604 PageBottom
, PageTop
, PageWidth
);
608 WriteLabelProlog(cupsGetOption("page-label", num_options
, options
),
609 PageLeft
, PageRight
, PageLength
);
613 WriteLabelProlog(cupsGetOption("page-label", num_options
, options
),
614 PageLength
- PageTop
, PageLength
- PageBottom
,
619 WriteLabelProlog(cupsGetOption("page-label", num_options
, options
),
620 PageWidth
- PageRight
, PageWidth
- PageLeft
,
627 if (ppd
== NULL
|| ppd
->language_level
== 1)
628 printf("/#copies %d def\n", realcopies
);
630 printf("<</NumCopies %d>>setpagedevice\n", realcopies
);
636 * Output the pages...
639 row
= malloc(cupsImageGetWidth(img
) * abs(colorspace
) + 3);
641 fprintf(stderr
, "DEBUG: XPosition=%d, YPosition=%d, Orientation=%d\n",
642 XPosition
, YPosition
, Orientation
);
643 fprintf(stderr
, "DEBUG: xprint=%.0f, yprint=%.0f\n", xprint
, yprint
);
644 fprintf(stderr
, "DEBUG: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f\n",
645 PageLeft
, PageRight
, PageWidth
);
646 fprintf(stderr
, "DEBUG: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f\n",
647 PageBottom
, PageTop
, PageLength
);
658 left
= (PageRight
+ PageLeft
- xprint
* 72) / 2;
661 left
= PageRight
- xprint
* 72;
668 top
= PageBottom
+ yprint
* 72;
671 top
= (PageTop
+ PageBottom
+ yprint
* 72) / 2;
686 left
= (PageTop
+ PageBottom
- xprint
* 72) / 2;
689 left
= PageTop
- xprint
* 72;
696 top
= PageLeft
+ yprint
* 72;
699 top
= (PageRight
+ PageLeft
+ yprint
* 72) / 2;
714 left
= (PageRight
+ PageLeft
- xprint
* 72) / 2;
717 left
= PageRight
- xprint
* 72;
724 top
= PageBottom
+ yprint
* 72;
727 top
= (PageTop
+ PageBottom
+ yprint
* 72) / 2;
742 left
= (PageTop
+ PageBottom
- xprint
* 72) / 2;
745 left
= PageTop
- xprint
* 72;
752 top
= PageLeft
+ yprint
* 72;
755 top
= (PageRight
+ PageLeft
+ yprint
* 72) / 2;
764 fprintf(stderr
, "DEBUG: left=%.2f, top=%.2f\n", left
, top
);
766 for (page
= 1; Copies
> 0; Copies
--)
767 for (xpage
= 0; xpage
< xpages
; xpage
++)
768 for (ypage
= 0; ypage
< ypages
; ypage
++, page
++)
770 if (ppd
&& ppd
->num_filters
== 0)
771 fprintf(stderr
, "PAGE: %d %d\n", page
, realcopies
);
773 fprintf(stderr
, "INFO: Printing page %d...\n", page
);
775 printf("%%%%Page: %d %d\n", page
, page
);
777 ppdEmit(ppd
, stdout
, PPD_ORDER_PAGE
);
782 printf("%.0f 0 translate -1 1 scale\n", PageWidth
);
786 case 1 : /* Landscape */
787 printf("%.0f 0 translate 90 rotate\n", PageWidth
);
789 case 2 : /* Reverse Portrait */
790 printf("%.0f %.0f translate 180 rotate\n", PageWidth
, PageLength
);
792 case 3 : /* Reverse Landscape */
793 printf("0 %.0f translate -90 rotate\n", PageLength
);
799 x0
= cupsImageGetWidth(img
) * xpage
/ xpages
;
800 x1
= cupsImageGetWidth(img
) * (xpage
+ 1) / xpages
- 1;
801 y0
= cupsImageGetHeight(img
) * ypage
/ ypages
;
802 y1
= cupsImageGetHeight(img
) * (ypage
+ 1) / ypages
- 1;
804 printf("%.1f %.1f translate\n", left
, top
);
806 printf("%.3f %.3f scale\n\n",
807 xprint
* 72.0 / (x1
- x0
+ 1),
808 yprint
* 72.0 / (y1
- y0
+ 1));
810 if (LanguageLevel
== 1)
812 printf("/picture %d string def\n", (x1
- x0
+ 1) * abs(colorspace
));
813 printf("%d %d 8[1 0 0 -1 0 1]", (x1
- x0
+ 1), (y1
- y0
+ 1));
815 if (colorspace
== CUPS_IMAGE_WHITE
)
816 puts("{currentfile picture readhexstring pop} image");
818 printf("{currentfile picture readhexstring pop} false %d colorimage\n",
821 for (y
= y0
; y
<= y1
; y
++)
823 cupsImageGetRow(img
, x0
, y
, x1
- x0
+ 1, row
);
824 ps_hex(row
, (x1
- x0
+ 1) * abs(colorspace
), y
== y1
);
831 case CUPS_IMAGE_WHITE
:
832 puts("/DeviceGray setcolorspace");
834 case CUPS_IMAGE_RGB
:
835 puts("/DeviceRGB setcolorspace");
837 case CUPS_IMAGE_CMYK
:
838 puts("/DeviceCMYK setcolorspace");
846 "/BitsPerComponent 8",
847 x1
- x0
+ 1, y1
- y0
+ 1);
851 case CUPS_IMAGE_WHITE
:
852 fputs("/Decode[0 1]", stdout
);
854 case CUPS_IMAGE_RGB
:
855 fputs("/Decode[0 1 0 1 0 1]", stdout
);
857 case CUPS_IMAGE_CMYK
:
858 fputs("/Decode[0 1 0 1 0 1 0 1]", stdout
);
862 fputs("/DataSource currentfile /ASCII85Decode filter", stdout
);
864 if (((x1
- x0
+ 1) / xprint
) < 100.0)
865 fputs("/Interpolate true", stdout
);
867 puts("/cupsImageMatrix[1 0 0 -1 0 1]>>image");
869 for (y
= y0
, out_offset
= 0; y
<= y1
; y
++)
871 cupsImageGetRow(img
, x0
, y
, x1
- x0
+ 1, row
+ out_offset
);
873 out_length
= (x1
- x0
+ 1) * abs(colorspace
) + out_offset
;
874 out_offset
= out_length
& 3;
876 ps_ascii85(row
, out_length
, y
== y1
);
879 memcpy(row
, row
+ out_length
- out_offset
, out_offset
);
892 * End the job with the appropriate JCL command or CTRL-D otherwise.
895 ppdEmitJCLEnd(ppd
, stdout
);
909 * 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
913 ps_hex(cups_ib_t
*data
, /* I - Data to print */
914 int length
, /* I - Number of bytes to print */
915 int last_line
) /* I - Last line of raster data? */
917 static int col
= 0; /* Current column */
918 static char *hex
= "0123456789ABCDEF";
925 * Put the hex chars out to the file; note that we don't use printf()
926 * for speed reasons...
929 putchar(hex
[*data
>> 4]);
930 putchar(hex
[*data
& 15]);
943 if (last_line
&& col
)
952 * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
956 ps_ascii85(cups_ib_t
*data
, /* I - Data to print */
957 int length
, /* I - Number of bytes to print */
958 int last_line
) /* I - Last line of raster data? */
960 unsigned b
; /* Binary data word */
961 unsigned char c
[5]; /* ASCII85 encoded chars */
962 static int col
= 0; /* Current column */
967 b
= (((((data
[0] << 8) | data
[1]) << 8) | data
[2]) << 8) | data
[3];
976 c
[4] = (b
% 85) + '!';
978 c
[3] = (b
% 85) + '!';
980 c
[2] = (b
% 85) + '!';
982 c
[1] = (b
% 85) + '!';
986 fwrite(c
, 5, 1, stdout
);
1004 memset(data
+ length
, 0, 4 - length
);
1005 b
= (((((data
[0] << 8) | data
[1]) << 8) | data
[2]) << 8) | data
[3];
1007 c
[4] = (b
% 85) + '!';
1009 c
[3] = (b
% 85) + '!';
1011 c
[2] = (b
% 85) + '!';
1013 c
[1] = (b
% 85) + '!';
1017 fwrite(c
, length
+ 1, 1, stdout
);
1027 * End of "$Id: imagetops.c 4741 2005-10-02 04:25:52Z mike $".