]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
2 | * "$Id: imagetops.c 4741 2005-10-02 04:25:52Z mike $" | |
3 | * | |
4 | * Image file to PostScript filter for the Common UNIX Printing System (CUPS). | |
5 | * | |
6 | * Copyright 1993-2005 by Easy Software Products. | |
7 | * | |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE.txt" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
17 | * 44141 Airport View Drive, Suite 204 | |
18 | * Hollywood, Maryland 20636 USA | |
19 | * | |
20 | * Voice: (301) 373-9600 | |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
23 | * | |
24 | * This file is subject to the Apple OS-Developed Software exception. | |
25 | * | |
26 | * Contents: | |
27 | * | |
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. | |
31 | */ | |
32 | ||
33 | /* | |
34 | * Include necessary headers... | |
35 | */ | |
36 | ||
37 | #include "common.h" | |
38 | #include "image.h" | |
39 | #include <math.h> | |
40 | ||
41 | ||
42 | /* | |
43 | * Globals... | |
44 | */ | |
45 | ||
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 */ | |
51 | ||
52 | ||
53 | /* | |
54 | * Local functions... | |
55 | */ | |
56 | ||
57 | static void ps_hex(cups_ib_t *, int, int); | |
58 | static void ps_ascii85(cups_ib_t *, int, int); | |
59 | ||
60 | ||
61 | /* | |
62 | * 'main()' - Main entry... | |
63 | */ | |
64 | ||
65 | int /* O - Exit status */ | |
66 | main(int argc, /* I - Number of command-line arguments */ | |
67 | char *argv[]) /* I - Command-line arguments */ | |
68 | { | |
69 | cups_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 */ | |
75 | ysize, | |
76 | xsize2, | |
77 | ysize2; | |
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 */ | |
85 | x1, y1; | |
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 */ | |
108 | ||
109 | ||
110 | /* | |
111 | * Make sure status messages are not buffered... | |
112 | */ | |
113 | ||
114 | setbuf(stderr, NULL); | |
115 | ||
116 | /* | |
117 | * Check command-line... | |
118 | */ | |
119 | ||
120 | if (argc < 6 || argc > 7) | |
121 | { | |
122 | fputs("ERROR: imagetops job-id user title copies options [file]\n", stderr); | |
123 | return (1); | |
124 | } | |
125 | ||
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 | { | |
135 | int fd; /* File to write to */ | |
136 | char buffer[8192]; /* Buffer to read into */ | |
137 | int bytes; /* # of bytes to read */ | |
138 | ||
139 | ||
140 | if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) | |
141 | { | |
142 | perror("ERROR: Unable to copy image file"); | |
143 | return (1); | |
144 | } | |
145 | ||
146 | fprintf(stderr, "DEBUG: imagetoraster - copying to temp print file \"%s\"\n", | |
147 | filename); | |
148 | ||
149 | while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) | |
150 | write(fd, buffer, bytes); | |
151 | ||
152 | close(fd); | |
153 | } | |
154 | else | |
155 | strlcpy(filename, argv[6], sizeof(filename)); | |
156 | ||
157 | /* | |
158 | * Process command-line options and write the prolog... | |
159 | */ | |
160 | ||
161 | zoom = 0.0; | |
162 | xppi = 0; | |
163 | yppi = 0; | |
164 | hue = 0; | |
165 | sat = 100; | |
166 | g = 1.0; | |
167 | b = 1.0; | |
168 | ||
169 | Copies = atoi(argv[4]); | |
170 | ||
171 | options = NULL; | |
172 | num_options = cupsParseOptions(argv[5], 0, &options); | |
173 | ||
174 | ppd = SetCommonOptions(num_options, options, 0); | |
175 | ||
176 | if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL) | |
177 | { | |
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 | * | |
184 | * separate-documents-uncollated-copies allows for uncollated copies. | |
185 | */ | |
186 | ||
187 | Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0; | |
188 | } | |
189 | ||
190 | if ((val = cupsGetOption("Collate", num_options, options)) != NULL && | |
191 | strcasecmp(val, "True") == 0) | |
192 | Collate = 1; | |
193 | ||
194 | if ((val = cupsGetOption("gamma", num_options, options)) != NULL) | |
195 | g = atoi(val) * 0.001f; | |
196 | ||
197 | if ((val = cupsGetOption("brightness", num_options, options)) != NULL) | |
198 | b = atoi(val) * 0.01f; | |
199 | ||
200 | if ((val = cupsGetOption("scaling", num_options, options)) != NULL) | |
201 | zoom = atoi(val) * 0.01; | |
202 | ||
203 | if ((val = cupsGetOption("ppi", num_options, options)) != NULL) | |
204 | if (sscanf(val, "%dx%d", &xppi, &yppi) < 2) | |
205 | yppi = xppi; | |
206 | ||
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 | ||
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); | |
261 | ||
262 | if ((val = cupsGetOption("mirror", num_options, options)) != NULL && | |
263 | strcasecmp(val, "True") == 0) | |
264 | Flip = 1; | |
265 | ||
266 | /* | |
267 | * Open the input image to print... | |
268 | */ | |
269 | ||
270 | colorspace = ColorDevice ? CUPS_IMAGE_RGB_CMYK : CUPS_IMAGE_WHITE; | |
271 | ||
272 | img = cupsImageOpen(filename, colorspace, CUPS_IMAGE_WHITE, sat, hue, NULL); | |
273 | ||
274 | if (argc == 6) | |
275 | unlink(filename); | |
276 | ||
277 | if (img == NULL) | |
278 | { | |
279 | fputs("ERROR: Unable to open image file for printing!\n", stderr); | |
280 | ppdClose(ppd); | |
281 | return (1); | |
282 | } | |
283 | ||
284 | colorspace = cupsImageGetColorSpace(img); | |
285 | ||
286 | /* | |
287 | * Scale as necessary... | |
288 | */ | |
289 | ||
290 | if (zoom == 0.0 && xppi == 0) | |
291 | { | |
292 | xppi = cupsImageGetXPPI(img); | |
293 | yppi = cupsImageGetYPPI(img); | |
294 | } | |
295 | ||
296 | if (yppi == 0) | |
297 | yppi = xppi; | |
298 | ||
299 | fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n", | |
300 | xppi, yppi, zoom); | |
301 | ||
302 | if (xppi > 0) | |
303 | { | |
304 | /* | |
305 | * Scale the image as neccesary to match the desired pixels-per-inch. | |
306 | */ | |
307 | ||
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 | ||
322 | xinches = (float)cupsImageGetWidth(img) / (float)xppi; | |
323 | yinches = (float)cupsImageGetHeight(img) / (float)yppi; | |
324 | ||
325 | fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n", | |
326 | xinches, yinches); | |
327 | ||
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 | ||
334 | if (cupsGetOption("orientation-requested", num_options, options) == NULL && | |
335 | cupsGetOption("landscape", num_options, options) == NULL) | |
336 | { | |
337 | /* | |
338 | * Rotate the image if it will fit landscape but not portrait... | |
339 | */ | |
340 | ||
341 | fputs("DEBUG: Auto orientation...\n", stderr); | |
342 | ||
343 | if ((xinches > xprint || yinches > yprint) && | |
344 | xinches <= yprint && yinches <= xprint) | |
345 | { | |
346 | /* | |
347 | * Rotate the image as needed... | |
348 | */ | |
349 | ||
350 | fputs("DEBUG: Using landscape orientation...\n", stderr); | |
351 | ||
352 | Orientation = (Orientation + 1) & 3; | |
353 | xsize = yprint; | |
354 | yprint = xprint; | |
355 | xprint = xsize; | |
356 | } | |
357 | } | |
358 | } | |
359 | else | |
360 | { | |
361 | /* | |
362 | * Scale percentage of page size... | |
363 | */ | |
364 | ||
365 | xprint = (PageRight - PageLeft) / 72.0; | |
366 | yprint = (PageTop - PageBottom) / 72.0; | |
367 | aspect = (float)cupsImageGetYPPI(img) / (float)cupsImageGetXPPI(img); | |
368 | ||
369 | fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n", | |
370 | xprint, yprint); | |
371 | ||
372 | fprintf(stderr, "DEBUG: cupsImageGetXPPI(img) = %d, cupsImageGetYPPI(img) = %d, aspect = %f\n", | |
373 | cupsImageGetXPPI(img), cupsImageGetYPPI(img), aspect); | |
374 | ||
375 | xsize = xprint * zoom; | |
376 | ysize = xsize * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect; | |
377 | ||
378 | if (ysize > (yprint * zoom)) | |
379 | { | |
380 | ysize = yprint * zoom; | |
381 | xsize = ysize * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img); | |
382 | } | |
383 | ||
384 | xsize2 = yprint * zoom; | |
385 | ysize2 = xsize2 * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect; | |
386 | ||
387 | if (ysize2 > (xprint * zoom)) | |
388 | { | |
389 | ysize2 = xprint * zoom; | |
390 | xsize2 = ysize2 * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img); | |
391 | } | |
392 | ||
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); | |
395 | ||
396 | if (cupsGetOption("orientation-requested", num_options, options) == NULL && | |
397 | cupsGetOption("landscape", num_options, options) == NULL) | |
398 | { | |
399 | /* | |
400 | * Choose the rotation with the largest area, but prefer | |
401 | * portrait if they are equal... | |
402 | */ | |
403 | ||
404 | fputs("DEBUG: Auto orientation...\n", stderr); | |
405 | ||
406 | if ((xsize * ysize) < (xsize2 * xsize2)) | |
407 | { | |
408 | /* | |
409 | * Do landscape orientation... | |
410 | */ | |
411 | ||
412 | fputs("DEBUG: Using landscape orientation...\n", stderr); | |
413 | ||
414 | Orientation = 1; | |
415 | xinches = xsize2; | |
416 | yinches = ysize2; | |
417 | xprint = (PageTop - PageBottom) / 72.0; | |
418 | yprint = (PageRight - PageLeft) / 72.0; | |
419 | } | |
420 | else | |
421 | { | |
422 | /* | |
423 | * Do portrait orientation... | |
424 | */ | |
425 | ||
426 | fputs("DEBUG: Using portrait orientation...\n", stderr); | |
427 | ||
428 | Orientation = 0; | |
429 | xinches = xsize; | |
430 | yinches = ysize; | |
431 | } | |
432 | } | |
433 | else if (Orientation & 1) | |
434 | { | |
435 | fputs("DEBUG: Using landscape orientation...\n", stderr); | |
436 | ||
437 | xinches = xsize2; | |
438 | yinches = ysize2; | |
439 | xprint = (PageTop - PageBottom) / 72.0; | |
440 | yprint = (PageRight - PageLeft) / 72.0; | |
441 | } | |
442 | else | |
443 | { | |
444 | fputs("DEBUG: Using portrait orientation...\n", stderr); | |
445 | ||
446 | xinches = xsize; | |
447 | yinches = ysize; | |
448 | xprint = (PageRight - PageLeft) / 72.0; | |
449 | yprint = (PageTop - PageBottom) / 72.0; | |
450 | } | |
451 | } | |
452 | ||
453 | /* | |
454 | * Compute the number of pages to print and the size of the image on each | |
455 | * page... | |
456 | */ | |
457 | ||
458 | xpages = ceil(xinches / xprint); | |
459 | ypages = ceil(yinches / yprint); | |
460 | ||
461 | xprint = xinches / xpages; | |
462 | yprint = yinches / ypages; | |
463 | ||
464 | fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n", | |
465 | xpages, xprint, ypages, yprint); | |
466 | ||
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 | ||
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 | ||
494 | /* | |
495 | * Add margins to page size... | |
496 | */ | |
497 | ||
498 | width += ppd->custom_margins[0] + ppd->custom_margins[2]; | |
499 | length += ppd->custom_margins[1] + ppd->custom_margins[3]; | |
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 | ||
511 | fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n", | |
512 | width / 72.0, length / 72.0); | |
513 | ||
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]; | |
531 | } | |
532 | ||
533 | /* | |
534 | * See if we need to collate, and if so how we need to do it... | |
535 | */ | |
536 | ||
537 | if (xpages == 1 && ypages == 1) | |
538 | Collate = 0; | |
539 | ||
540 | slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL; | |
541 | ||
542 | if (Copies > 1 && !slowcollate) | |
543 | { | |
544 | realcopies = Copies; | |
545 | Copies = 1; | |
546 | } | |
547 | else | |
548 | realcopies = 1; | |
549 | ||
550 | /* | |
551 | * Write any "exit server" options that have been selected... | |
552 | */ | |
553 | ||
554 | ppdEmit(ppd, stdout, PPD_ORDER_EXIT); | |
555 | ||
556 | /* | |
557 | * Write any JCL commands that are needed to print PostScript code... | |
558 | */ | |
559 | ||
560 | ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]); | |
561 | ||
562 | /* | |
563 | * Start sending the document with any commands needed... | |
564 | */ | |
565 | ||
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); | |
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]); | |
581 | if (Orientation & 1) | |
582 | puts("%%Orientation: Landscape"); | |
583 | else | |
584 | puts("%%Orientation: Portrait"); | |
585 | puts("%%EndComments"); | |
586 | puts("%%BeginProlog"); | |
587 | ||
588 | if (ppd != NULL && ppd->patches != NULL) | |
589 | puts(ppd->patches); | |
590 | ||
591 | ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT); | |
592 | ppdEmit(ppd, stdout, PPD_ORDER_ANY); | |
593 | ppdEmit(ppd, stdout, PPD_ORDER_PROLOG); | |
594 | ||
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); | |
598 | ||
599 | WriteCommon(); | |
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 | } | |
624 | ||
625 | if (realcopies > 1) | |
626 | { | |
627 | if (ppd == NULL || ppd->language_level == 1) | |
628 | printf("/#copies %d def\n", realcopies); | |
629 | else | |
630 | printf("<</NumCopies %d>>setpagedevice\n", realcopies); | |
631 | } | |
632 | ||
633 | puts("%%EndProlog"); | |
634 | ||
635 | /* | |
636 | * Output the pages... | |
637 | */ | |
638 | ||
639 | row = malloc(cupsImageGetWidth(img) * abs(colorspace) + 3); | |
640 | ||
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 | ||
649 | switch (Orientation) | |
650 | { | |
651 | default : | |
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 | ||
766 | for (page = 1; Copies > 0; Copies --) | |
767 | for (xpage = 0; xpage < xpages; xpage ++) | |
768 | for (ypage = 0; ypage < ypages; ypage ++, page ++) | |
769 | { | |
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); | |
776 | ||
777 | ppdEmit(ppd, stdout, PPD_ORDER_PAGE); | |
778 | ||
779 | puts("gsave"); | |
780 | ||
781 | if (Flip) | |
782 | printf("%.0f 0 translate -1 1 scale\n", PageWidth); | |
783 | ||
784 | switch (Orientation) | |
785 | { | |
786 | case 1 : /* Landscape */ | |
787 | printf("%.0f 0 translate 90 rotate\n", PageWidth); | |
788 | break; | |
789 | case 2 : /* Reverse Portrait */ | |
790 | printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength); | |
791 | break; | |
792 | case 3 : /* Reverse Landscape */ | |
793 | printf("0 %.0f translate -90 rotate\n", PageLength); | |
794 | break; | |
795 | } | |
796 | ||
797 | puts("gsave"); | |
798 | ||
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; | |
803 | ||
804 | printf("%.1f %.1f translate\n", left, top); | |
805 | ||
806 | printf("%.3f %.3f scale\n\n", | |
807 | xprint * 72.0 / (x1 - x0 + 1), | |
808 | yprint * 72.0 / (y1 - y0 + 1)); | |
809 | ||
810 | if (LanguageLevel == 1) | |
811 | { | |
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 == CUPS_IMAGE_WHITE) | |
816 | puts("{currentfile picture readhexstring pop} image"); | |
817 | else | |
818 | printf("{currentfile picture readhexstring pop} false %d colorimage\n", | |
819 | abs(colorspace)); | |
820 | ||
821 | for (y = y0; y <= y1; y ++) | |
822 | { | |
823 | cupsImageGetRow(img, x0, y, x1 - x0 + 1, row); | |
824 | ps_hex(row, (x1 - x0 + 1) * abs(colorspace), y == y1); | |
825 | } | |
826 | } | |
827 | else | |
828 | { | |
829 | switch (colorspace) | |
830 | { | |
831 | case CUPS_IMAGE_WHITE : | |
832 | puts("/DeviceGray setcolorspace"); | |
833 | break; | |
834 | case CUPS_IMAGE_RGB : | |
835 | puts("/DeviceRGB setcolorspace"); | |
836 | break; | |
837 | case CUPS_IMAGE_CMYK : | |
838 | puts("/DeviceCMYK setcolorspace"); | |
839 | break; | |
840 | } | |
841 | ||
842 | printf("<<" | |
843 | "/cupsImageType 1" | |
844 | "/Width %d" | |
845 | "/Height %d" | |
846 | "/BitsPerComponent 8", | |
847 | x1 - x0 + 1, y1 - y0 + 1); | |
848 | ||
849 | switch (colorspace) | |
850 | { | |
851 | case CUPS_IMAGE_WHITE : | |
852 | fputs("/Decode[0 1]", stdout); | |
853 | break; | |
854 | case CUPS_IMAGE_RGB : | |
855 | fputs("/Decode[0 1 0 1 0 1]", stdout); | |
856 | break; | |
857 | case CUPS_IMAGE_CMYK : | |
858 | fputs("/Decode[0 1 0 1 0 1 0 1]", stdout); | |
859 | break; | |
860 | } | |
861 | ||
862 | fputs("/DataSource currentfile /ASCII85Decode filter", stdout); | |
863 | ||
864 | if (((x1 - x0 + 1) / xprint) < 100.0) | |
865 | fputs("/Interpolate true", stdout); | |
866 | ||
867 | puts("/cupsImageMatrix[1 0 0 -1 0 1]>>image"); | |
868 | ||
869 | for (y = y0, out_offset = 0; y <= y1; y ++) | |
870 | { | |
871 | cupsImageGetRow(img, x0, y, x1 - x0 + 1, row + out_offset); | |
872 | ||
873 | out_length = (x1 - x0 + 1) * abs(colorspace) + out_offset; | |
874 | out_offset = out_length & 3; | |
875 | ||
876 | ps_ascii85(row, out_length, y == y1); | |
877 | ||
878 | if (out_offset > 0) | |
879 | memcpy(row, row + out_length - out_offset, out_offset); | |
880 | } | |
881 | } | |
882 | ||
883 | puts("grestore"); | |
884 | WriteLabels(0); | |
885 | puts("grestore"); | |
886 | puts("showpage"); | |
887 | } | |
888 | ||
889 | puts("%%EOF"); | |
890 | ||
891 | /* | |
892 | * End the job with the appropriate JCL command or CTRL-D otherwise. | |
893 | */ | |
894 | ||
895 | ppdEmitJCLEnd(ppd, stdout); | |
896 | ||
897 | /* | |
898 | * Close files... | |
899 | */ | |
900 | ||
901 | cupsImageClose(img); | |
902 | ppdClose(ppd); | |
903 | ||
904 | return (0); | |
905 | } | |
906 | ||
907 | ||
908 | /* | |
909 | * 'ps_hex()' - Print binary data as a series of hexadecimal numbers. | |
910 | */ | |
911 | ||
912 | static void | |
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? */ | |
916 | { | |
917 | static int col = 0; /* Current column */ | |
918 | static char *hex = "0123456789ABCDEF"; | |
919 | /* Hex digits */ | |
920 | ||
921 | ||
922 | while (length > 0) | |
923 | { | |
924 | /* | |
925 | * Put the hex chars out to the file; note that we don't use printf() | |
926 | * for speed reasons... | |
927 | */ | |
928 | ||
929 | putchar(hex[*data >> 4]); | |
930 | putchar(hex[*data & 15]); | |
931 | ||
932 | data ++; | |
933 | length --; | |
934 | ||
935 | col += 2; | |
936 | if (col > 78) | |
937 | { | |
938 | putchar('\n'); | |
939 | col = 0; | |
940 | } | |
941 | } | |
942 | ||
943 | if (last_line && col) | |
944 | { | |
945 | putchar('\n'); | |
946 | col = 0; | |
947 | } | |
948 | } | |
949 | ||
950 | ||
951 | /* | |
952 | * 'ps_ascii85()' - Print binary data as a series of base-85 numbers. | |
953 | */ | |
954 | ||
955 | static void | |
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? */ | |
959 | { | |
960 | unsigned b; /* Binary data word */ | |
961 | unsigned char c[5]; /* ASCII85 encoded chars */ | |
962 | static int col = 0; /* Current column */ | |
963 | ||
964 | ||
965 | while (length > 3) | |
966 | { | |
967 | b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]; | |
968 | ||
969 | if (b == 0) | |
970 | { | |
971 | putchar('z'); | |
972 | col ++; | |
973 | } | |
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 | ||
986 | fwrite(c, 5, 1, stdout); | |
987 | col += 5; | |
988 | } | |
989 | ||
990 | data += 4; | |
991 | length -= 4; | |
992 | ||
993 | if (col >= 75) | |
994 | { | |
995 | putchar('\n'); | |
996 | col = 0; | |
997 | } | |
998 | } | |
999 | ||
1000 | if (last_line) | |
1001 | { | |
1002 | if (length > 0) | |
1003 | { | |
1004 | memset(data + length, 0, 4 - length); | |
1005 | b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]; | |
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 | ||
1017 | fwrite(c, length + 1, 1, stdout); | |
1018 | } | |
1019 | ||
1020 | puts("~>"); | |
1021 | col = 0; | |
1022 | } | |
1023 | } | |
1024 | ||
1025 | ||
1026 | /* | |
1027 | * End of "$Id: imagetops.c 4741 2005-10-02 04:25:52Z mike $". | |
1028 | */ |