]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/imagetops.c
Y2k copyright changes.
[thirdparty/cups.git] / filter / imagetops.c
1 /*
2 * "$Id: imagetops.c,v 1.22 2000/01/04 13:45:46 mike Exp $"
3 *
4 * Image file to PostScript filter for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1993-2000 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-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Main entry...
27 * ps_hex() - Print binary data as a series of hexadecimal numbers.
28 * ps_ascii85() - Print binary data as a series of base-85 numbers.
29 */
30
31 /*
32 * Include necessary headers...
33 */
34
35 #include "common.h"
36 #include "image.h"
37 #include <math.h>
38
39
40 /*
41 * Globals...
42 */
43
44 int Flip = 0, /* Flip/mirror pages */
45 Collate = 0, /* Collate copies? */
46 Copies = 1; /* Number of copies */
47
48
49 /*
50 * Local functions...
51 */
52
53 static void ps_hex(ib_t *, int);
54 static void ps_ascii85(ib_t *, int, int);
55
56
57 /*
58 * 'main()' - Main entry...
59 */
60
61 int /* O - Exit status */
62 main(int argc, /* I - Number of command-line arguments */
63 char *argv[]) /* I - Command-line arguments */
64 {
65 image_t *img; /* Image to print */
66 float xprint, /* Printable area */
67 yprint,
68 xinches, /* Total size in inches */
69 yinches;
70 float xsize, /* Total size in points */
71 ysize,
72 xsize2,
73 ysize2;
74 int xpages, /* # x pages */
75 ypages, /* # y pages */
76 xpage, /* Current x page */
77 ypage, /* Current y page */
78 page; /* Current page number */
79 int x0, y0, /* Corners of the page in image coords */
80 x1, y1;
81 ib_t *row; /* Current row */
82 int y; /* Current Y coordinate in image */
83 int colorspace; /* Output colorspace */
84 int out_offset, /* Offset into output buffer */
85 out_length; /* Length of output buffer */
86 ppd_file_t *ppd; /* PPD file */
87 int num_options; /* Number of print options */
88 cups_option_t *options; /* Print options */
89 const char *val; /* Option value */
90 int slowcollate; /* Collate copies the slow way */
91 float g; /* Gamma correction value */
92 float b; /* Brightness factor */
93 float zoom; /* Zoom facter */
94 int ppi; /* Pixels-per-inch */
95 int hue, sat; /* Hue and saturation adjustment */
96 int realcopies; /* Real copies being printed */
97
98
99 if (argc != 7)
100 {
101 fputs("ERROR: imagetops job-id user title copies options file\n", stderr);
102 return (1);
103 }
104
105 /*
106 * Process command-line options and write the prolog...
107 */
108
109 zoom = 0.0;
110 ppi = 0;
111 hue = 0;
112 sat = 100;
113 g = 1.0;
114 b = 1.0;
115
116 Copies = atoi(argv[4]);
117
118 options = NULL;
119 num_options = cupsParseOptions(argv[5], 0, &options);
120
121 ppd = SetCommonOptions(num_options, options, 1);
122
123 ppdMarkDefaults(ppd);
124 cupsMarkOptions(ppd, num_options, options);
125
126 if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
127 {
128 /*
129 * This IPP attribute is unnecessarily complicated...
130 *
131 * single-document, separate-documents-collated-copies, and
132 * single-document-new-sheet all require collated copies.
133 *
134 * separate-documents-collated-copies allows for uncollated copies.
135 */
136
137 Collate = strcasecmp(val, "separate-documents-collated-copies") != 0;
138 }
139
140 if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
141 strcasecmp(val, "True") == 0)
142 Collate = 1;
143
144 if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
145 g = atoi(val) * 0.001f;
146
147 if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
148 b = atoi(val) * 0.01f;
149
150 if ((val = cupsGetOption("scaling", num_options, options)) != NULL)
151 zoom = atoi(val) * 0.01;
152
153 if ((val = cupsGetOption("ppi", num_options, options)) != NULL)
154 ppi = atoi(val);
155
156 if ((val = cupsGetOption("saturation", num_options, options)) != NULL)
157 sat = atoi(val);
158
159 if ((val = cupsGetOption("hue", num_options, options)) != NULL)
160 hue = atoi(val);
161
162 /*
163 * Open the input image to print...
164 */
165
166 colorspace = ColorDevice ? IMAGE_RGB : IMAGE_WHITE;
167
168 if ((img = ImageOpen(argv[6], colorspace, IMAGE_WHITE, sat, hue, NULL)) == NULL)
169 {
170 fputs("ERROR: Unable to open image file for printing!\n", stderr);
171 ppdClose(ppd);
172 return (1);
173 }
174
175 colorspace = img->colorspace;
176
177 /*
178 * Scale as necessary...
179 */
180
181 if (zoom == 0.0 && ppi == 0)
182 ppi = img->xppi;
183
184 xprint = (PageRight - PageLeft) / 72.0;
185 yprint = (PageTop - PageBottom) / 72.0;
186
187 if (ppi > 0)
188 {
189 /*
190 * Scale the image as neccesary to match the desired pixels-per-inch.
191 */
192
193 xinches = (float)img->xsize / (float)ppi;
194 yinches = (float)img->ysize / (float)ppi;
195
196 /*
197 * Rotate the image if it will fit landscape but not portrait...
198 */
199
200 if ((xinches > xprint || yinches > yprint) &&
201 xinches <= yprint && yinches <= xprint)
202 {
203 /*
204 * Rotate the image as needed...
205 */
206
207 Orientation = (Orientation + 1) & 3;
208 xsize = yprint;
209 yprint = xprint;
210 xprint = xsize;
211
212 xsize = PageLeft;
213 PageLeft = PageBottom;
214 PageBottom = PageWidth - PageRight;
215 PageRight = PageTop;
216 PageTop = PageLength - xsize;
217
218 xsize = PageWidth;
219 PageWidth = PageLength;
220 PageLength = xsize;
221 }
222 }
223 else
224 {
225 /*
226 * Scale percentage of page size...
227 */
228
229 xsize = xprint * zoom;
230 ysize = xsize * img->ysize / img->xsize;
231
232 if (ysize > (yprint * zoom))
233 {
234 ysize = yprint * zoom;
235 xsize = ysize * img->xsize / img->ysize;
236 }
237
238 xsize2 = yprint * zoom;
239 ysize2 = xsize2 * img->ysize / img->xsize;
240
241 if (ysize2 > (xprint * zoom))
242 {
243 ysize2 = xprint * zoom;
244 xsize2 = ysize2 * img->xsize / img->ysize;
245 }
246
247 /*
248 * Choose the rotation with the largest area, but prefer
249 * portrait if they are equal...
250 */
251
252 if ((xsize * ysize) < (xsize2 * xsize2))
253 {
254 /*
255 * Do landscape orientation...
256 */
257
258 Orientation = 1;
259 xinches = xsize2;
260 yinches = ysize2;
261 xprint = (PageTop - PageBottom) / 72.0;
262 yprint = (PageRight - PageLeft) / 72.0;
263
264 xsize = PageLeft;
265 PageLeft = PageBottom;
266 PageBottom = PageWidth - PageRight;
267 PageRight = PageTop;
268 PageTop = PageLength - xsize;
269
270 xsize = PageWidth;
271 PageWidth = PageLength;
272 PageLength = xsize;
273 }
274 else
275 {
276 /*
277 * Do portrait orientation...
278 */
279
280 Orientation = 0;
281 xinches = xsize;
282 yinches = ysize;
283 }
284 }
285
286 xpages = ceil(xinches / xprint);
287 ypages = ceil(yinches / yprint);
288
289 /*
290 * See if we need to collate, and if so how we need to do it...
291 */
292
293 if (xpages == 1 && ypages == 1)
294 Collate = 0;
295
296 slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL;
297
298 /*
299 * Write any "exit server" options that have been selected...
300 */
301
302 ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
303
304 /*
305 * Write any JCL commands that are needed to print PostScript code...
306 */
307
308 if (ppd != NULL && ppd->jcl_begin && ppd->jcl_ps)
309 {
310 fputs(ppd->jcl_begin, stdout);
311 ppdEmit(ppd, stdout, PPD_ORDER_JCL);
312 fputs(ppd->jcl_ps, stdout);
313 }
314
315 /*
316 * Start sending the document with any commands needed...
317 */
318
319 puts("%!");
320
321 if (ppd != NULL && ppd->patches != NULL)
322 puts(ppd->patches);
323
324 ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
325 ppdEmit(ppd, stdout, PPD_ORDER_ANY);
326 ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
327
328 if (g != 1.0 || b != 1.0)
329 printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
330 "ifelse %.3f mul } bind settransfer\n", g, b);
331
332 if (Copies > 1 && !slowcollate)
333 {
334 printf("/#copies %d def\n", Copies);
335 realcopies = Copies;
336 Copies = 1;
337 }
338 else
339 realcopies = 1;
340
341 /*
342 * Output the pages...
343 */
344
345 xprint = xinches / xpages;
346 yprint = yinches / ypages;
347 row = malloc(img->xsize * abs(colorspace) + 3);
348
349 for (page = 1; Copies > 0; Copies --)
350 for (xpage = 0; xpage < xpages; xpage ++)
351 for (ypage = 0; ypage < ypages; ypage ++, page ++)
352 {
353 fprintf(stderr, "PAGE: %d %d\n", page, realcopies);
354 fprintf(stderr, "INFO: Printing page %d...\n", page);
355
356 ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
357
358 puts("gsave");
359
360 if (Flip)
361 printf("%.0f 0 translate -1 1 scale\n", PageWidth);
362
363 switch (Orientation)
364 {
365 case 1 : /* Landscape */
366 printf("%.0f 0 translate 90 rotate\n", PageLength);
367 break;
368 case 2 : /* Reverse Portrait */
369 printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength);
370 break;
371 case 3 : /* Reverse Landscape */
372 printf("0 %.0f translate -90 rotate\n", PageWidth);
373 break;
374 }
375
376 x0 = img->xsize * xpage / xpages;
377 x1 = img->xsize * (xpage + 1) / xpages - 1;
378 y0 = img->ysize * ypage / ypages;
379 y1 = img->ysize * (ypage + 1) / ypages - 1;
380
381 printf("%.1f %.1f translate\n", PageLeft, PageBottom + 72.0 * yprint);
382 printf("%.3f %.3f scale\n\n",
383 xprint * 72.0 / (x1 - x0 + 1),
384 yprint * 72.0 / (y1 - y0 + 1));
385
386 if (LanguageLevel == 1)
387 {
388 printf("/picture %d string def\n", (x1 - x0 + 1) * abs(colorspace));
389 printf("%d %d 8[1 0 0 -1 0 1]", (x1 - x0 + 1), (y1 - y0 + 1));
390
391 if (colorspace == IMAGE_WHITE)
392 puts("{currentfile picture readhexstring pop} image");
393 else
394 puts("{currentfile picture readhexstring pop} false 3 colorimage");
395
396 for (y = y0; y <= y1; y ++)
397 {
398 ImageGetRow(img, x0, y, x1 - x0 + 1, row);
399 ps_hex(row, (x1 - x0 + 1) * abs(colorspace));
400 }
401 }
402 else
403 {
404 if (colorspace == IMAGE_WHITE)
405 puts("/DeviceGray setcolorspace");
406 else
407 puts("/DeviceRGB setcolorspace");
408
409 printf("<<"
410 "/ImageType 1"
411 "/Width %d"
412 "/Height %d"
413 "/BitsPerComponent 8",
414 x1 - x0 + 1, y1 - y0 + 1);
415
416 if (colorspace == IMAGE_WHITE)
417 fputs("/Decode[0 1]", stdout);
418 else
419 fputs("/Decode[0 1 0 1 0 1]", stdout);
420
421 fputs("/DataSource currentfile /ASCII85Decode filter", stdout);
422
423 if (((x1 - x0 + 1) / xprint) < 100.0)
424 fputs("/Interpolate true", stdout);
425
426 puts("/ImageMatrix[1 0 0 -1 0 1]>>image");
427
428 for (y = y0, out_offset = 0; y <= y1; y ++)
429 {
430 ImageGetRow(img, x0, y, x1 - x0 + 1, row + out_offset);
431
432 out_length = (x1 - x0 + 1) * abs(colorspace) + out_offset;
433 out_offset = out_length & 3;
434
435 ps_ascii85(row, out_length, y == y1);
436
437 if (out_offset > 0)
438 memcpy(row, row + out_length - out_offset, out_offset);
439 }
440 }
441
442 puts("grestore");
443 puts("showpage");
444 }
445
446 /*
447 * End the job with the appropriate JCL command or CTRL-D otherwise.
448 */
449
450 if (ppd != NULL && ppd->jcl_end)
451 fputs(ppd->jcl_end, stdout);
452 else
453 putchar(0x04);
454
455 /*
456 * Close files...
457 */
458
459 ImageClose(img);
460 ppdClose(ppd);
461
462 return (0);
463 }
464
465
466 /*
467 * 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
468 */
469
470 static void
471 ps_hex(ib_t *data, /* I - Data to print */
472 int length) /* I - Number of bytes to print */
473 {
474 int col;
475 static char *hex = "0123456789ABCDEF";
476
477
478 col = 0;
479
480 while (length > 0)
481 {
482 /*
483 * Put the hex chars out to the file; note that we don't use printf()
484 * for speed reasons...
485 */
486
487 putchar(hex[*data >> 4]);
488 putchar(hex[*data & 15]);
489
490 data ++;
491 length --;
492
493 col = (col + 1) & 31;
494 if (col == 0 && length > 0)
495 putchar('\n');
496 }
497
498 putchar('\n');
499 }
500
501
502 /*
503 * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
504 */
505
506 static void
507 ps_ascii85(ib_t *data, /* I - Data to print */
508 int length, /* I - Number of bytes to print */
509 int last_line) /* I - Last line of raster data? */
510 {
511 int i; /* Looping var */
512 unsigned b; /* Binary data word */
513 unsigned char c[5]; /* ASCII85 encoded chars */
514
515
516 while (length > 3)
517 {
518 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
519
520 if (b == 0)
521 putchar('z');
522 else
523 {
524 c[4] = (b % 85) + '!';
525 b /= 85;
526 c[3] = (b % 85) + '!';
527 b /= 85;
528 c[2] = (b % 85) + '!';
529 b /= 85;
530 c[1] = (b % 85) + '!';
531 b /= 85;
532 c[0] = b + '!';
533
534 fwrite(c, 5, 1, stdout);
535 }
536
537 data += 4;
538 length -= 4;
539 }
540
541 if (last_line)
542 {
543 if (length > 0)
544 {
545 memset(data + length, 0, 4 - length);
546 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
547
548 c[4] = (b % 85) + '!';
549 b /= 85;
550 c[3] = (b % 85) + '!';
551 b /= 85;
552 c[2] = (b % 85) + '!';
553 b /= 85;
554 c[1] = (b % 85) + '!';
555 b /= 85;
556 c[0] = b + '!';
557
558 fwrite(c, length + 1, 1, stdout);
559 }
560
561 puts("~>");
562 }
563 }
564
565
566 /*
567 * End of "$Id: imagetops.c,v 1.22 2000/01/04 13:45:46 mike Exp $".
568 */