]> git.ipfire.org Git - thirdparty/cups.git/blame - filter/imagetops.c
Make CUPS API threadsafe (STR #1276), replace FILE's with
[thirdparty/cups.git] / filter / imagetops.c
CommitLineData
516ba4c9 1/*
c9d3f842 2 * "$Id$"
516ba4c9 3 *
ed19bd98 4 * Image file to PostScript filter for the Common UNIX Printing System (CUPS).
516ba4c9 5 *
c9d3f842 6 * Copyright 1993-2005 by Easy Software Products.
516ba4c9 7 *
ed19bd98 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:
516ba4c9 14 *
ed19bd98 15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
c9d3f842 18 * Hollywood, Maryland 20636 USA
af526a52 19 *
9639c4de 20 * Voice: (301) 373-9600
ed19bd98 21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
d850a9e1 23 *
dab1a4d8 24 * This file is subject to the Apple OS-Developed Software exception.
25 *
ed19bd98 26 * Contents:
516ba4c9 27 *
ed19bd98 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.
516ba4c9 31 */
32
33/*
34 * Include necessary headers...
35 */
36
ed19bd98 37#include "common.h"
516ba4c9 38#include "image.h"
ed19bd98 39#include <math.h>
516ba4c9 40
41
42/*
43 * Globals...
44 */
45
ed19bd98 46int Flip = 0, /* Flip/mirror pages */
c5da5726 47 XPosition = 0, /* Horizontal position on page */
48 YPosition = 0, /* Vertical position on page */
ed19bd98 49 Collate = 0, /* Collate copies? */
50 Copies = 1; /* Number of copies */
516ba4c9 51
52
53/*
54 * Local functions...
55 */
56
b5cb0608 57static void ps_hex(ib_t *, int, int);
ed19bd98 58static void ps_ascii85(ib_t *, int, int);
516ba4c9 59
60
61/*
62 * 'main()' - Main entry...
63 */
64
ed19bd98 65int /* O - Exit status */
516ba4c9 66main(int argc, /* I - Number of command-line arguments */
67 char *argv[]) /* I - Command-line arguments */
68{
ed19bd98 69 image_t *img; /* Image to print */
70 float xprint, /* Printable area */
71 yprint,
72 xinches, /* Total size in inches */
73 yinches;
74 float xsize, /* Total size in points */
48c4ffef 75 ysize,
76 xsize2,
77 ysize2;
332197a2 78 float aspect; /* Aspect ratio */
ed19bd98 79 int xpages, /* # x pages */
80 ypages, /* # y pages */
81 xpage, /* Current x page */
82 ypage, /* Current y page */
de8a4f54 83 page; /* Current page number */
ed19bd98 84 int x0, y0, /* Corners of the page in image coords */
85 x1, y1;
86 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 */
b5cb0608 92 ppd_choice_t *choice; /* PPD option choice */
ed19bd98 93 int num_options; /* Number of print options */
94 cups_option_t *options; /* Print options */
568d2c2f 95 const char *val; /* Option value */
ed19bd98 96 int slowcollate; /* Collate copies the slow way */
97 float g; /* Gamma correction value */
98 float b; /* Brightness factor */
99 float zoom; /* Zoom facter */
332197a2 100 int xppi, yppi; /* Pixels-per-inch */
ed19bd98 101 int hue, sat; /* Hue and saturation adjustment */
19ec0c2c 102 int realcopies; /* Real copies being printed */
c5da5726 103 float left, top; /* Left and top of image */
7ce9aa3d 104 char filename[1024]; /* Name of file to print */
b5cb0608 105 time_t curtime; /* Current time */
106 struct tm *curtm; /* Current date */
107 char curdate[255]; /* Current date string */
ed19bd98 108
109
7ce9aa3d 110 /*
cc787dc1 111 * Make sure status messages are not buffered...
112 */
113
114 setbuf(stderr, NULL);
115
116 /*
117 * Check command-line...
7ce9aa3d 118 */
119
120 if (argc < 6 || argc > 7)
ed19bd98 121 {
7ce9aa3d 122 fputs("ERROR: imagetops job-id user title copies options [file]\n", stderr);
ed19bd98 123 return (1);
124 }
516ba4c9 125
7ce9aa3d 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)");
128
129 /*
130 * Copy stdin as needed...
131 */
132
133 if (argc == 6)
134 {
1b5bf964 135 int fd; /* File to write to */
7ce9aa3d 136 char buffer[8192]; /* Buffer to read into */
137 int bytes; /* # of bytes to read */
138
139
1b5bf964 140 if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
7ce9aa3d 141 {
142 perror("ERROR: Unable to copy image file");
143 return (1);
144 }
145
1b5bf964 146 fprintf(stderr, "DEBUG: imagetoraster - copying to temp print file \"%s\"\n",
7ce9aa3d 147 filename);
148
149 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
1b5bf964 150 write(fd, buffer, bytes);
151
152 close(fd);
7ce9aa3d 153 }
154 else
def978d5 155 strlcpy(filename, argv[6], sizeof(filename));
7ce9aa3d 156
516ba4c9 157 /*
ed19bd98 158 * Process command-line options and write the prolog...
516ba4c9 159 */
160
ed19bd98 161 zoom = 0.0;
332197a2 162 xppi = 0;
163 yppi = 0;
ed19bd98 164 hue = 0;
165 sat = 100;
f0d2f1a4 166 g = 1.0;
ed19bd98 167 b = 1.0;
516ba4c9 168
ae818f4d 169 Copies = atoi(argv[4]);
170
ed19bd98 171 options = NULL;
172 num_options = cupsParseOptions(argv[5], 0, &options);
516ba4c9 173
de8a4f54 174 ppd = SetCommonOptions(num_options, options, 0);
516ba4c9 175
ed19bd98 176 if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
516ba4c9 177 {
ed19bd98 178 /*
179 * This IPP attribute is unnecessarily complicated...
180 *
181 * single-document, separate-documents-collated-copies, and
182 * single-document-new-sheet all require collated copies.
183 *
3e41e580 184 * separate-documents-uncollated-copies allows for uncollated copies.
ed19bd98 185 */
516ba4c9 186
3e41e580 187 Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
ed19bd98 188 }
516ba4c9 189
ed19bd98 190 if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
a7b3e92e 191 strcasecmp(val, "True") == 0)
ed19bd98 192 Collate = 1;
516ba4c9 193
ed19bd98 194 if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
195 g = atoi(val) * 0.001f;
516ba4c9 196
ed19bd98 197 if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
198 b = atoi(val) * 0.01f;
516ba4c9 199
ed19bd98 200 if ((val = cupsGetOption("scaling", num_options, options)) != NULL)
201 zoom = atoi(val) * 0.01;
516ba4c9 202
ed19bd98 203 if ((val = cupsGetOption("ppi", num_options, options)) != NULL)
332197a2 204 if (sscanf(val, "%dx%d", &xppi, &yppi) < 2)
205 yppi = xppi;
516ba4c9 206
c5da5726 207 if ((val = cupsGetOption("position", num_options, options)) != NULL)
208 {
209 if (strcasecmp(val, "center") == 0)
210 {
211 XPosition = 0;
212 YPosition = 0;
213 }
214 else if (strcasecmp(val, "top") == 0)
215 {
216 XPosition = 0;
217 YPosition = 1;
218 }
219 else if (strcasecmp(val, "left") == 0)
220 {
221 XPosition = -1;
222 YPosition = 0;
223 }
224 else if (strcasecmp(val, "right") == 0)
225 {
226 XPosition = 1;
227 YPosition = 0;
228 }
229 else if (strcasecmp(val, "top-left") == 0)
230 {
231 XPosition = -1;
232 YPosition = 1;
233 }
234 else if (strcasecmp(val, "top-right") == 0)
235 {
236 XPosition = 1;
237 YPosition = 1;
238 }
239 else if (strcasecmp(val, "bottom") == 0)
240 {
241 XPosition = 0;
242 YPosition = -1;
243 }
244 else if (strcasecmp(val, "bottom-left") == 0)
245 {
246 XPosition = -1;
247 YPosition = -1;
248 }
249 else if (strcasecmp(val, "bottom-right") == 0)
250 {
251 XPosition = 1;
252 YPosition = -1;
253 }
254 }
255
ed19bd98 256 if ((val = cupsGetOption("saturation", num_options, options)) != NULL)
257 sat = atoi(val);
258
259 if ((val = cupsGetOption("hue", num_options, options)) != NULL)
260 hue = atoi(val);
516ba4c9 261
a05e4307 262 if ((val = cupsGetOption("mirror", num_options, options)) != NULL &&
263 strcasecmp(val, "True") == 0)
264 Flip = 1;
265
516ba4c9 266 /*
267 * Open the input image to print...
268 */
269
350807be 270 colorspace = ColorDevice ? IMAGE_RGB_CMYK : IMAGE_WHITE;
516ba4c9 271
7ce9aa3d 272 img = ImageOpen(filename, colorspace, IMAGE_WHITE, sat, hue, NULL);
273
274 if (argc == 6)
275 unlink(filename);
276
277 if (img == NULL)
ed19bd98 278 {
279 fputs("ERROR: Unable to open image file for printing!\n", stderr);
280 ppdClose(ppd);
281 return (1);
282 }
516ba4c9 283
ed19bd98 284 colorspace = img->colorspace;
516ba4c9 285
286 /*
287 * Scale as necessary...
288 */
289
332197a2 290 if (zoom == 0.0 && xppi == 0)
291 {
292 xppi = img->xppi;
293 yppi = img->yppi;
294 }
295
296 if (yppi == 0)
297 yppi = xppi;
298
34089ee8 299 fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n",
300 xppi, yppi, zoom);
e6d607f1 301
332197a2 302 if (xppi > 0)
516ba4c9 303 {
304 /*
305 * Scale the image as neccesary to match the desired pixels-per-inch.
306 */
307
95a58aca 308 if (Orientation & 1)
309 {
310 xprint = (PageTop - PageBottom) / 72.0;
311 yprint = (PageRight - PageLeft) / 72.0;
312 }
313 else
314 {
315 xprint = (PageRight - PageLeft) / 72.0;
316 yprint = (PageTop - PageBottom) / 72.0;
317 }
318
319 fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
320 xprint, yprint);
321
332197a2 322 xinches = (float)img->xsize / (float)xppi;
323 yinches = (float)img->ysize / (float)yppi;
48c4ffef 324
e6d607f1 325 fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n",
326 xinches, yinches);
327
753453e4 328 if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
329 {
330 xinches = xinches * atoi(val) / 100;
331 yinches = yinches * atoi(val) / 100;
332 }
333
a28d12c5 334 if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
b16dd9cb 335 cupsGetOption("landscape", num_options, options) == NULL)
48c4ffef 336 {
337 /*
b16dd9cb 338 * Rotate the image if it will fit landscape but not portrait...
48c4ffef 339 */
340
e6d607f1 341 fputs("DEBUG: Auto orientation...\n", stderr);
342
b16dd9cb 343 if ((xinches > xprint || yinches > yprint) &&
344 xinches <= yprint && yinches <= xprint)
345 {
346 /*
347 * Rotate the image as needed...
348 */
349
e6d607f1 350 fputs("DEBUG: Using landscape orientation...\n", stderr);
351
b16dd9cb 352 Orientation = (Orientation + 1) & 3;
353 xsize = yprint;
354 yprint = xprint;
355 xprint = xsize;
b16dd9cb 356 }
48c4ffef 357 }
516ba4c9 358 }
359 else
360 {
361 /*
362 * Scale percentage of page size...
363 */
364
95a58aca 365 xprint = (PageRight - PageLeft) / 72.0;
366 yprint = (PageTop - PageBottom) / 72.0;
332197a2 367 aspect = (float)img->yppi / (float)img->xppi;
368
95a58aca 369 fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
370 xprint, yprint);
371
332197a2 372 fprintf(stderr, "DEBUG: img->xppi = %d, img->yppi = %d, aspect = %f\n",
373 img->xppi, img->yppi, aspect);
374
ed19bd98 375 xsize = xprint * zoom;
332197a2 376 ysize = xsize * img->ysize / img->xsize / aspect;
0169953d 377
ed19bd98 378 if (ysize > (yprint * zoom))
516ba4c9 379 {
ed19bd98 380 ysize = yprint * zoom;
332197a2 381 xsize = ysize * img->xsize * aspect / img->ysize;
516ba4c9 382 }
0169953d 383
48c4ffef 384 xsize2 = yprint * zoom;
332197a2 385 ysize2 = xsize2 * img->ysize / img->xsize / aspect;
48c4ffef 386
387 if (ysize2 > (xprint * zoom))
388 {
389 ysize2 = xprint * zoom;
332197a2 390 xsize2 = ysize2 * img->xsize * aspect / img->ysize;
48c4ffef 391 }
392
e6d607f1 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);
332197a2 395
a28d12c5 396 if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
b16dd9cb 397 cupsGetOption("landscape", num_options, options) == NULL)
48c4ffef 398 {
399 /*
b16dd9cb 400 * Choose the rotation with the largest area, but prefer
401 * portrait if they are equal...
48c4ffef 402 */
403
e6d607f1 404 fputs("DEBUG: Auto orientation...\n", stderr);
405
b16dd9cb 406 if ((xsize * ysize) < (xsize2 * xsize2))
407 {
408 /*
409 * Do landscape orientation...
410 */
411
e6d607f1 412 fputs("DEBUG: Using landscape orientation...\n", stderr);
413
b16dd9cb 414 Orientation = 1;
415 xinches = xsize2;
416 yinches = ysize2;
417 xprint = (PageTop - PageBottom) / 72.0;
418 yprint = (PageRight - PageLeft) / 72.0;
b16dd9cb 419 }
420 else
421 {
422 /*
423 * Do portrait orientation...
424 */
425
e6d607f1 426 fputs("DEBUG: Using portrait orientation...\n", stderr);
427
b16dd9cb 428 Orientation = 0;
429 xinches = xsize;
430 yinches = ysize;
431 }
432 }
433 else if (Orientation & 1)
434 {
e6d607f1 435 fputs("DEBUG: Using landscape orientation...\n", stderr);
436
48c4ffef 437 xinches = xsize2;
438 yinches = ysize2;
439 xprint = (PageTop - PageBottom) / 72.0;
440 yprint = (PageRight - PageLeft) / 72.0;
48c4ffef 441 }
b6ea8f29 442 else
443 {
e6d607f1 444 fputs("DEBUG: Using portrait orientation...\n", stderr);
445
b6ea8f29 446 xinches = xsize;
447 yinches = ysize;
448 xprint = (PageRight - PageLeft) / 72.0;
449 yprint = (PageTop - PageBottom) / 72.0;
450 }
ed19bd98 451 }
516ba4c9 452
b5cb0608 453 /*
454 * Compute the number of pages to print and the size of the image on each
455 * page...
456 */
457
ed19bd98 458 xpages = ceil(xinches / xprint);
459 ypages = ceil(yinches / yprint);
0169953d 460
b5cb0608 461 xprint = xinches / xpages;
462 yprint = yinches / ypages;
463
95a58aca 464 fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n",
465 xpages, xprint, ypages, yprint);
466
b5cb0608 467 /*
468 * Update the page size for custom sizes...
469 */
470
471 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
472 strcasecmp(choice->choice, "Custom") == 0)
473 {
474 float width, /* New width in points */
475 length; /* New length in points */
476 char s[255]; /* New custom page size... */
477
478
df585e0d 479 /*
480 * Use the correct width and length for the current orientation...
481 */
482
483 if (Orientation & 1)
484 {
485 width = yprint * 72.0;
486 length = xprint * 72.0;
487 }
488 else
489 {
490 width = xprint * 72.0;
491 length = yprint * 72.0;
492 }
493
b5cb0608 494 /*
495 * Add margins to page size...
496 */
497
df585e0d 498 width += ppd->custom_margins[0] + ppd->custom_margins[2];
499 length += ppd->custom_margins[1] + ppd->custom_margins[3];
b5cb0608 500
501 /*
502 * Enforce minimums...
503 */
504
505 if (width < ppd->custom_min[0])
506 width = ppd->custom_min[0];
507
508 if (length < ppd->custom_min[1])
509 length = ppd->custom_min[1];
510
95a58aca 511 fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n",
512 width / 72.0, length / 72.0);
513
b5cb0608 514 /*
515 * Set the new custom size...
516 */
517
518 sprintf(s, "Custom.%.0fx%.0f", width, length);
519 ppdMarkOption(ppd, "PageSize", s);
520
521 /*
522 * Update page variables...
523 */
524
525 PageWidth = width;
526 PageLength = length;
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];
b5cb0608 531 }
532
ed19bd98 533 /*
534 * See if we need to collate, and if so how we need to do it...
535 */
516ba4c9 536
ed19bd98 537 if (xpages == 1 && ypages == 1)
538 Collate = 0;
516ba4c9 539
ed19bd98 540 slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL;
516ba4c9 541
b5cb0608 542 if (Copies > 1 && !slowcollate)
543 {
544 realcopies = Copies;
545 Copies = 1;
546 }
547 else
548 realcopies = 1;
549
ed19bd98 550 /*
551 * Write any "exit server" options that have been selected...
552 */
516ba4c9 553
ed19bd98 554 ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
516ba4c9 555
ed19bd98 556 /*
557 * Write any JCL commands that are needed to print PostScript code...
558 */
559
ee6a18b5 560 ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
516ba4c9 561
562 /*
ed19bd98 563 * Start sending the document with any commands needed...
516ba4c9 564 */
565
b5cb0608 566 curtime = time(NULL);
567 curtm = localtime(&curtime);
568
569 puts("%!PS-Adobe-3.0");
570 printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
571 PageRight, PageTop);
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);
03f61bf3 577 strftime(curdate, sizeof(curdate), "%c", curtm);
b5cb0608 578 printf("%%%%CreationDate: %s\n", curdate);
579 printf("%%%%Title: %s\n", argv[3]);
580 printf("%%%%For: %s\n", argv[2]);
581 if (Orientation & 1)
582 puts("%%Orientation: Landscape");
904eef76 583 else
584 puts("%%Orientation: Portrait");
b5cb0608 585 puts("%%EndComments");
586 puts("%%BeginProlog");
ed19bd98 587
37b19c12 588 if (ppd != NULL && ppd->patches != NULL)
589 puts(ppd->patches);
590
ed19bd98 591 ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
592 ppdEmit(ppd, stdout, PPD_ORDER_ANY);
593 ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
516ba4c9 594
ed19bd98 595 if (g != 1.0 || b != 1.0)
37b19c12 596 printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
597 "ifelse %.3f mul } bind settransfer\n", g, b);
ed19bd98 598
de8a4f54 599 WriteCommon();
df585e0d 600 switch (Orientation)
601 {
602 case 0 :
603 WriteLabelProlog(cupsGetOption("page-label", num_options, options),
604 PageBottom, PageTop, PageWidth);
605 break;
606
607 case 1 :
608 WriteLabelProlog(cupsGetOption("page-label", num_options, options),
609 PageLeft, PageRight, PageLength);
610 break;
611
612 case 2 :
613 WriteLabelProlog(cupsGetOption("page-label", num_options, options),
614 PageLength - PageTop, PageLength - PageBottom,
615 PageWidth);
616 break;
617
618 case 3 :
619 WriteLabelProlog(cupsGetOption("page-label", num_options, options),
620 PageWidth - PageRight, PageWidth - PageLeft,
621 PageLength);
622 break;
623 }
d11458ff 624
b5cb0608 625 if (realcopies > 1)
516ba4c9 626 {
83f08393 627 if (ppd == NULL || ppd->language_level == 1)
b5cb0608 628 printf("/#copies %d def\n", realcopies);
83f08393 629 else
b5cb0608 630 printf("<</NumCopies %d>>setpagedevice\n", realcopies);
ed19bd98 631 }
b5cb0608 632
633 puts("%%EndProlog");
516ba4c9 634
635 /*
636 * Output the pages...
637 */
638
b5cb0608 639 row = malloc(img->xsize * abs(colorspace) + 3);
0169953d 640
de8a4f54 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);
648
df585e0d 649 switch (Orientation)
650 {
4a0fc5ef 651 default :
df585e0d 652 switch (XPosition)
653 {
654 case -1 :
655 left = PageLeft;
656 break;
657 default :
658 left = (PageRight + PageLeft - xprint * 72) / 2;
659 break;
660 case 1 :
661 left = PageRight - xprint * 72;
662 break;
663 }
664
665 switch (YPosition)
666 {
667 case -1 :
668 top = PageBottom + yprint * 72;
669 break;
670 default :
671 top = (PageTop + PageBottom + yprint * 72) / 2;
672 break;
673 case 1 :
674 top = PageTop;
675 break;
676 }
677 break;
678
679 case 1 :
680 switch (XPosition)
681 {
682 case -1 :
683 left = PageBottom;
684 break;
685 default :
686 left = (PageTop + PageBottom - xprint * 72) / 2;
687 break;
688 case 1 :
689 left = PageTop - xprint * 72;
690 break;
691 }
692
693 switch (YPosition)
694 {
695 case -1 :
696 top = PageLeft + yprint * 72;
697 break;
698 default :
699 top = (PageRight + PageLeft + yprint * 72) / 2;
700 break;
701 case 1 :
702 top = PageRight;
703 break;
704 }
705 break;
706
707 case 2 :
708 switch (XPosition)
709 {
710 case 1 :
711 left = PageLeft;
712 break;
713 default :
714 left = (PageRight + PageLeft - xprint * 72) / 2;
715 break;
716 case -1 :
717 left = PageRight - xprint * 72;
718 break;
719 }
720
721 switch (YPosition)
722 {
723 case 1 :
724 top = PageBottom + yprint * 72;
725 break;
726 default :
727 top = (PageTop + PageBottom + yprint * 72) / 2;
728 break;
729 case -1 :
730 top = PageTop;
731 break;
732 }
733 break;
734
735 case 3 :
736 switch (XPosition)
737 {
738 case 1 :
739 left = PageBottom;
740 break;
741 default :
742 left = (PageTop + PageBottom - xprint * 72) / 2;
743 break;
744 case -1 :
745 left = PageTop - xprint * 72;
746 break;
747 }
748
749 switch (YPosition)
750 {
751 case 1 :
752 top = PageLeft + yprint * 72;
753 break;
754 default :
755 top = (PageRight + PageLeft + yprint * 72) / 2;
756 break;
757 case -1 :
758 top = PageRight;
759 break;
760 }
761 break;
762 }
763
764 fprintf(stderr, "DEBUG: left=%.2f, top=%.2f\n", left, top);
765
ed19bd98 766 for (page = 1; Copies > 0; Copies --)
767 for (xpage = 0; xpage < xpages; xpage ++)
768 for (ypage = 0; ypage < ypages; ypage ++, page ++)
769 {
b5cb0608 770 if (ppd && ppd->num_filters == 0)
771 fprintf(stderr, "PAGE: %d %d\n", page, realcopies);
772
773 fprintf(stderr, "INFO: Printing page %d...\n", page);
774
775 printf("%%%%Page: %d %d\n", page, page);
516ba4c9 776
ed19bd98 777 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
516ba4c9 778
ed19bd98 779 puts("gsave");
516ba4c9 780
ed19bd98 781 if (Flip)
782 printf("%.0f 0 translate -1 1 scale\n", PageWidth);
783
784 switch (Orientation)
785 {
786 case 1 : /* Landscape */
df585e0d 787 printf("%.0f 0 translate 90 rotate\n", PageWidth);
ed19bd98 788 break;
789 case 2 : /* Reverse Portrait */
790 printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength);
791 break;
792 case 3 : /* Reverse Landscape */
df585e0d 793 printf("0 %.0f translate -90 rotate\n", PageLength);
ed19bd98 794 break;
795 }
516ba4c9 796
df585e0d 797 puts("gsave");
798
5398375f 799 x0 = img->xsize * xpage / xpages;
800 x1 = img->xsize * (xpage + 1) / xpages - 1;
801 y0 = img->ysize * ypage / ypages;
802 y1 = img->ysize * (ypage + 1) / ypages - 1;
516ba4c9 803
c5da5726 804 printf("%.1f %.1f translate\n", left, top);
805
ed19bd98 806 printf("%.3f %.3f scale\n\n",
807 xprint * 72.0 / (x1 - x0 + 1),
808 yprint * 72.0 / (y1 - y0 + 1));
516ba4c9 809
ed19bd98 810 if (LanguageLevel == 1)
af526a52 811 {
ed19bd98 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));
814
815 if (colorspace == IMAGE_WHITE)
816 puts("{currentfile picture readhexstring pop} image");
af526a52 817 else
350807be 818 printf("{currentfile picture readhexstring pop} false %d colorimage\n",
819 abs(colorspace));
ed19bd98 820
821 for (y = y0; y <= y1; y ++)
822 {
823 ImageGetRow(img, x0, y, x1 - x0 + 1, row);
b5cb0608 824 ps_hex(row, (x1 - x0 + 1) * abs(colorspace), y == y1);
ed19bd98 825 }
af526a52 826 }
827 else
828 {
350807be 829 switch (colorspace)
830 {
831 case IMAGE_WHITE :
832 puts("/DeviceGray setcolorspace");
833 break;
834 case IMAGE_RGB :
835 puts("/DeviceRGB setcolorspace");
836 break;
837 case IMAGE_CMYK :
838 puts("/DeviceCMYK setcolorspace");
839 break;
840 }
af526a52 841
ed19bd98 842 printf("<<"
843 "/ImageType 1"
844 "/Width %d"
845 "/Height %d"
846 "/BitsPerComponent 8",
847 x1 - x0 + 1, y1 - y0 + 1);
af526a52 848
350807be 849 switch (colorspace)
850 {
851 case IMAGE_WHITE :
852 fputs("/Decode[0 1]", stdout);
853 break;
854 case IMAGE_RGB :
855 fputs("/Decode[0 1 0 1 0 1]", stdout);
856 break;
857 case IMAGE_CMYK :
858 fputs("/Decode[0 1 0 1 0 1 0 1]", stdout);
859 break;
860 }
af526a52 861
ed19bd98 862 fputs("/DataSource currentfile /ASCII85Decode filter", stdout);
af526a52 863
ed19bd98 864 if (((x1 - x0 + 1) / xprint) < 100.0)
865 fputs("/Interpolate true", stdout);
5398375f 866
ed19bd98 867 puts("/ImageMatrix[1 0 0 -1 0 1]>>image");
af526a52 868
ed19bd98 869 for (y = y0, out_offset = 0; y <= y1; y ++)
870 {
871 ImageGetRow(img, x0, y, x1 - x0 + 1, row + out_offset);
af526a52 872
ed19bd98 873 out_length = (x1 - x0 + 1) * abs(colorspace) + out_offset;
874 out_offset = out_length & 3;
516ba4c9 875
ed19bd98 876 ps_ascii85(row, out_length, y == y1);
516ba4c9 877
ed19bd98 878 if (out_offset > 0)
879 memcpy(row, row + out_length - out_offset, out_offset);
880 }
881 }
516ba4c9 882
ed19bd98 883 puts("grestore");
df585e0d 884 WriteLabels(0);
885 puts("grestore");
ed19bd98 886 puts("showpage");
887 }
516ba4c9 888
b5cb0608 889 puts("%%EOF");
890
ed19bd98 891 /*
892 * End the job with the appropriate JCL command or CTRL-D otherwise.
893 */
516ba4c9 894
625ced05 895 ppdEmitJCLEnd(ppd, stdout);
516ba4c9 896
ed19bd98 897 /*
898 * Close files...
899 */
516ba4c9 900
901 ImageClose(img);
ed19bd98 902 ppdClose(ppd);
516ba4c9 903
ed19bd98 904 return (0);
516ba4c9 905}
906
907
908/*
909 * 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
910 */
911
912static void
b5cb0608 913ps_hex(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? */
516ba4c9 916{
b5cb0608 917 static int col = 0; /* Current column */
516ba4c9 918 static char *hex = "0123456789ABCDEF";
b5cb0608 919 /* Hex digits */
516ba4c9 920
921
922 while (length > 0)
923 {
924 /*
ed19bd98 925 * Put the hex chars out to the file; note that we don't use printf()
516ba4c9 926 * for speed reasons...
927 */
928
ed19bd98 929 putchar(hex[*data >> 4]);
930 putchar(hex[*data & 15]);
516ba4c9 931
932 data ++;
933 length --;
af526a52 934
b5cb0608 935 col += 2;
936 if (col > 78)
937 {
ed19bd98 938 putchar('\n');
b5cb0608 939 col = 0;
940 }
ed19bd98 941 }
516ba4c9 942
b5cb0608 943 if (last_line && col)
944 {
945 putchar('\n');
946 col = 0;
947 }
516ba4c9 948}
949
950
951/*
952 * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
953 */
954
955static void
ed19bd98 956ps_ascii85(ib_t *data, /* I - Data to print */
516ba4c9 957 int length, /* I - Number of bytes to print */
958 int last_line) /* I - Last line of raster data? */
959{
960 unsigned b; /* Binary data word */
961 unsigned char c[5]; /* ASCII85 encoded chars */
b5cb0608 962 static int col = 0; /* Current column */
516ba4c9 963
964
516ba4c9 965 while (length > 3)
966 {
967 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
968
969 if (b == 0)
b5cb0608 970 {
ed19bd98 971 putchar('z');
b5cb0608 972 col ++;
973 }
516ba4c9 974 else
975 {
976 c[4] = (b % 85) + '!';
977 b /= 85;
978 c[3] = (b % 85) + '!';
979 b /= 85;
980 c[2] = (b % 85) + '!';
981 b /= 85;
982 c[1] = (b % 85) + '!';
983 b /= 85;
984 c[0] = b + '!';
985
ed19bd98 986 fwrite(c, 5, 1, stdout);
b5cb0608 987 col += 5;
ed19bd98 988 }
516ba4c9 989
990 data += 4;
991 length -= 4;
b5cb0608 992
993 if (col >= 75)
994 {
995 putchar('\n');
996 col = 0;
997 }
ed19bd98 998 }
516ba4c9 999
1000 if (last_line)
1001 {
1002 if (length > 0)
1003 {
4364903a 1004 memset(data + length, 0, 4 - length);
1005 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
516ba4c9 1006
1007 c[4] = (b % 85) + '!';
1008 b /= 85;
1009 c[3] = (b % 85) + '!';
1010 b /= 85;
1011 c[2] = (b % 85) + '!';
1012 b /= 85;
1013 c[1] = (b % 85) + '!';
1014 b /= 85;
1015 c[0] = b + '!';
1016
ed19bd98 1017 fwrite(c, length + 1, 1, stdout);
1018 }
516ba4c9 1019
ed19bd98 1020 puts("~>");
b5cb0608 1021 col = 0;
516ba4c9 1022 }
516ba4c9 1023}
1024
1025
1026/*
c9d3f842 1027 * End of "$Id$".
516ba4c9 1028 */