1 /*
2 * Image file to PDF filter for the Common UNIX Printing System (CUPS).
3 * developped by BBR Inc. 2006-2007
4 *
5 * This is based on imagetops.c of CUPS
6 *
7 * imagetops.c copyright notice is follows
8 *
9 * Copyright 1993-2006 by Easy Software Products.
10 *
11 * These coded instructions, statements, and computer programs are the
12 * property of Easy Software Products and are protected by Federal
13 * copyright law. Distribution and use rights are outlined in the file
14 * "COPYING" which should have been included with this file.
15 */
16
17 /*
18 * Include necessary headers...
19 */
20
21 #include "config.h"
22 #include "common.h"
23 #include <cupsfilters/image.h>
24 #include <cupsfilters/raster.h>
25 #include <cupsfilters/image-private.h>
26 #include <math.h>
27 #include <ctype.h>
28
29 #if CUPS_VERSION_MAJOR < 1 \
30 || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 2)
31 #ifndef CUPS_1_1
32 #error Installed libs and specified source Version mismatch \
33 Libs >= 1.2 && Source < 1.2
34 #define CUPS_1_1
35 #endif
36 #else
37 #ifdef CUPS_1_1
38 #error Installed libs and specified source Version mismatch \
39 Libs < 1.2 && Source >= 1.2
40 #undef CUPS_1_1
41 #endif
42 #endif
43
44 #define USE_CONVERT_CMD
45 //#define OUT_AS_HEX
46 //#define OUT_AS_ASCII85
47
48 /*
49 * Globals...
50 */
51
52 int Flip = 0, /* Flip/mirror pages */
53 XPosition = 0, /* Horizontal position on page */
54 YPosition = 0, /* Vertical position on page */
55 Collate = 0, /* Collate copies? */
56 Copies = 1, /* Number of copies */
57 Reverse = 0, /* Output order */
58 EvenDuplex = 0; /* cupsEvenDuplex */
59
60 #ifdef CUPS_1_1
61 #define cups_ib_t ib_t
62 #define cups_image_t image_t
63 #define CUPS_IMAGE_CMYK IMAGE_CMYK
64 #define CUPS_IMAGE_WHITE IMAGE_WHITE
65 #define CUPS_IMAGE_RGB IMAGE_RGB
66 #define CUPS_IMAGE_RGB_CMYK IMAGE_RGB_CMYK
67 #define cupsImageOpen ImageOpen
68 #define cupsImageClose ImageClose
69 #define cupsImageGetColorSpace(img) (img->colorspace)
70 #define cupsImageGetXPPI(img) (img->xppi)
71 #define cupsImageGetYPPI(img) (img->yppi)
72 #define cupsImageGetWidth(img) (img->xsize)
73 #define cupsImageGetHeight(img) (img->ysize)
74 #define cupsImageGetRow ImageGetRow
75 #endif
76
77 /*
78 * Local functions...
79 */
80
81 #ifdef OUT_AS_HEX
82 static void out_hex(cups_ib_t *, int, int);
83 #else
84 #ifdef OUT_AS_ASCII85
85 static void out_ascii85(cups_ib_t *, int, int);
86 #else
87 static void out_bin(cups_ib_t *, int, int);
88 #endif
89 #endif
90 static void outPdf(const char *str);
91 static void putcPdf(char c);
92 static int newObj(void);
93 static void freeAllObj(void);
94 static void outXref(void);
95 static void outTrailer(void);
96 static void outString(const char *s);
97 static void outPrologue(int nPages);
98 static void allocPageObjects(int noPages);
99 static void setOffset(int obj);
100 static void outPageObject(int pageObj, int contentsObj, int imgObj);
101 static void outPageContents(int contentsObj);
102 static void outImage(int imgObj);
103
104 struct pdfObject {
105 int offset;
106 };
107
108 static struct pdfObject *objects = NULL;
109 static int currentObjectNo = 0;
110 static int allocatedObjectNum = 0;
111 static int currentOffset = 0;
112 static int xrefOffset;
113 static int *pageObjects = NULL;
114 static int catalogObj;
115 static int pagesObj;
116 static const char *title;
117 static int xpages, /* # x pages */
118 ypages, /* # y pages */
119 xpage, /* Current x page */
120 ypage, /* Current y page */
121 page; /* Current page number */
122 static int xc0, yc0, /* Corners of the page in image coords */
123 xc1, yc1;
124 static float left, top; /* Left and top of image */
125 static float xprint, /* Printable area */
126 yprint,
127 xinches, /* Total size in inches */
128 yinches;
129 static float xsize, /* Total size in points */
130 ysize,
131 xsize2,
132 ysize2;
133 static float aspect; /* Aspect ratio */
134 static cups_image_t *img; /* Image to print */
135 static int colorspace; /* Output colorspace */
136 static cups_ib_t *row; /* Current row */
137 static float gammaval = 1.0; /* Gamma correction value */
138 static float brightness = 1.0; /* Gamma correction value */
139 static ppd_file_t *ppd; /* PPD file */
140
141 #define N_OBJECT_ALLOC 100
142 #define LINEBUFSIZE 1024
143
144 static char linebuf[LINEBUFSIZE];
145
emitJCLOptions(FILE * fp,int copies)146 void emitJCLOptions(FILE *fp, int copies)
147 {
148 int section;
149 ppd_choice_t **choices;
150 int i;
151 char buf[1024];
152 ppd_attr_t *attr;
153 int pdftopdfjcl = 0;
154 int datawritten = 0;
155
156 if (ppd == 0) return;
157 if ((attr = ppdFindAttr(ppd,"pdftopdfJCLBegin",NULL)) != NULL) {
158 int n = strlen(attr->value);
159 pdftopdfjcl = 1;
160 for (i = 0;i < n;i++) {
161 if (attr->value[i] == '\r' || attr->value[i] == '\n') {
162 /* skip new line */
163 continue;
164 }
165 fputc(attr->value[i],fp);
166 datawritten = 1;
167 }
168 }
169
170 snprintf(buf,sizeof(buf),"%d",copies);
171 if (ppdFindOption(ppd,"Copies") != NULL) {
172 ppdMarkOption(ppd,"Copies",buf);
173 } else {
174 if ((attr = ppdFindAttr(ppd,"pdftopdfJCLCopies",buf)) != NULL) {
175 fputs(attr->value,fp);
176 datawritten = 1;
177 } else if (pdftopdfjcl) {
178 fprintf(fp,"Copies=%d;",copies);
179 datawritten = 1;
180 }
181 }
182 for (section = (int)PPD_ORDER_ANY;
183 section <= (int)PPD_ORDER_PROLOG;section++) {
184 int n;
185
186 n = ppdCollect(ppd,(ppd_section_t)section,&choices);
187 for (i = 0;i < n;i++) {
188 snprintf(buf,sizeof(buf),"pdftopdfJCL%s",
189 ((ppd_option_t *)(choices[i]->option))->keyword);
190 if ((attr = ppdFindAttr(ppd,buf,choices[i]->choice)) != NULL) {
191 fputs(attr->value,fp);
192 datawritten = 1;
193 } else if (pdftopdfjcl) {
194 fprintf(fp,"%s=%s;",
195 ((ppd_option_t *)(choices[i]->option))->keyword,
196 choices[i]->choice);
197 datawritten = 1;
198 }
199 }
200 }
201 if (datawritten) fputc('\n',fp);
202 }
203
204
setOffset(int obj)205 static void setOffset(int obj)
206 {
207 objects[obj].offset = currentOffset;
208 }
209
allocPageObjects(int nPages)210 static void allocPageObjects(int nPages)
211 {
212 int i;
213
214 if ((pageObjects = malloc(sizeof(int)*nPages)) == NULL)
215 {
216 fprintf(stderr,"ERROR: Can't allocate pageObjects\n");
217 exit(2);
218 }
219 for (i = 0;i < nPages;i++)
220 {
221 pageObjects[i] = newObj();
222 }
223 }
224
newObj(void)225 static int newObj(void)
226 {
227 if (objects == NULL)
228 {
229 if ((objects = malloc(sizeof(struct pdfObject)*N_OBJECT_ALLOC))
230 == NULL)
231 {
232 fprintf(stderr,"ERROR: Can't allocate objects\n");
233 exit(2);
234 }
235 allocatedObjectNum = N_OBJECT_ALLOC;
236 }
237 if (currentObjectNo >= allocatedObjectNum)
238 {
239 if ((objects = realloc(objects,
240 sizeof(struct pdfObject)*(allocatedObjectNum+N_OBJECT_ALLOC)))
241 == NULL)
242 {
243 fprintf(stderr,"ERROR: Can't allocate objects\n");
244 exit(2);
245 }
246 allocatedObjectNum += N_OBJECT_ALLOC;
247 }
248 objects[currentObjectNo].offset = currentOffset;
249 return currentObjectNo++;
250 }
251
freeAllObj(void)252 static void freeAllObj(void)
253 {
254 if (objects != NULL)
255 {
256 free(objects);
257 objects = NULL;
258 }
259 }
260
putcPdf(char c)261 static void putcPdf(char c)
262 {
263 fputc(c,stdout);
264 currentOffset++;
265 }
266
outPdf(const char * str)267 static void outPdf(const char *str)
268 {
269 unsigned long len = strlen(str);
270
271 fputs(str,stdout);
272 currentOffset += len;
273 }
274
outXref(void)275 static void outXref(void)
276 {
277 char buf[21];
278 int i;
279
280 xrefOffset = currentOffset;
281 outPdf("xref\n");
282 snprintf(buf,21,"0 %d\n",currentObjectNo);
283 outPdf(buf);
284 outPdf("0000000000 65535 f \n");
285 for (i = 1;i < currentObjectNo;i++)
286 {
287 snprintf(buf,21,"%010d 00000 n \n",objects[i].offset);
288 outPdf(buf);
289 }
290 }
291
outString(const char * s)292 static void outString(const char *s)
293 {
294 char c;
295
296 putcPdf('(');
297 for (;(c = *s) != '\0';s++) {
298 if (c == '\\' || c == '(' || c == ')') {
299 putcPdf('\\');
300 }
301 putcPdf(c);
302 }
303 putcPdf(')');
304 }
305
outTrailer(void)306 static void outTrailer(void)
307 {
308 time_t curtime;
309 struct tm *curtm;
310 char curdate[255];
311
312 curtime = time(NULL);
313 curtm = localtime(&curtime);
314 strftime(curdate, sizeof(curdate),"D:%Y%m%d%H%M%S%z", curtm);
315
316 outPdf("trailer\n");
317 snprintf(linebuf, LINEBUFSIZE,"<</Size %d ",currentObjectNo);
318 outPdf(linebuf);
319 outPdf("/Root 1 0 R\n");
320 outPdf("/Info << /Title ");
321 outString(title);
322 putcPdf(' ');
323 snprintf(linebuf,LINEBUFSIZE,"/CreationDate (%s) ",curdate);
324 outPdf(linebuf);
325 snprintf(linebuf,LINEBUFSIZE,"/ModDate (%s) ",curdate);
326 outPdf(linebuf);
327 outPdf("/Producer (imagetopdf) ");
328 outPdf("/Trapped /False >>\n");
329 outPdf(">>\n");
330 outPdf("startxref\n");
331 snprintf(linebuf,LINEBUFSIZE,"%d\n",xrefOffset);
332 outPdf(linebuf);
333 outPdf("%%EOF\n");
334 }
335
outPrologue(int nPages)336 static void outPrologue(int nPages)
337 {
338 int i;
339
340 /* out header */
341 newObj(); /* dummy for no 0 object */
342 outPdf("%PDF-1.3\n");
343 /* out binary for transfer program */
344 linebuf[0] = '%';
345 linebuf[1] = (char)129;
346 linebuf[2] = (char)130;
347 linebuf[3] = (char)131;
348 linebuf[4] = (char)132;
349 linebuf[5] = '\n';
350 linebuf[6] = (char)0;
351 outPdf(linebuf);
352 outPdf("% This file was generated by imagetopdf\n");
353
354 catalogObj = newObj();
355 pagesObj = newObj();
356 allocPageObjects(nPages);
357
358 /* out catalog */
359 snprintf(linebuf,LINEBUFSIZE,
360 "%d 0 obj <</Type/Catalog /Pages %d 0 R ",catalogObj,pagesObj);
361 outPdf(linebuf);
362 outPdf(">> endobj\n");
363
364 /* out Pages */
365 setOffset(pagesObj);
366 snprintf(linebuf,LINEBUFSIZE,
367 "%d 0 obj <</Type/Pages /Kids [ ",pagesObj);
368 outPdf(linebuf);
369 if (Reverse) {
370 for (i = nPages-1;i >= 0;i--)
371 {
372 snprintf(linebuf,LINEBUFSIZE,"%d 0 R ",pageObjects[i]);
373 outPdf(linebuf);
374 }
375 } else {
376 for (i = 0;i < nPages;i++)
377 {
378 snprintf(linebuf,LINEBUFSIZE,"%d 0 R ",pageObjects[i]);
379 outPdf(linebuf);
380 }
381 }
382 outPdf("] ");
383 snprintf(linebuf,LINEBUFSIZE,"/Count %d >> endobj\n",nPages);
384 outPdf(linebuf);
385 }
386
outPageObject(int pageObj,int contentsObj,int imgObj)387 static void outPageObject(int pageObj, int contentsObj, int imgObj)
388 {
389 int trfuncObj;
390 int lengthObj;
391 int startOffset;
392 int length;
393 int outTrfunc = (gammaval != 1.0 || brightness != 1.0);
394
395 /* out Page Object */
396 setOffset(pageObj);
397 snprintf(linebuf,LINEBUFSIZE,
398 "%d 0 obj <</Type/Page /Parent %d 0 R ",
399 pageObj,pagesObj);
400 outPdf(linebuf);
401 snprintf(linebuf,LINEBUFSIZE,
402 "/MediaBox [ 0 0 %f %f ] ",PageWidth,PageLength);
403 outPdf(linebuf);
404 snprintf(linebuf,LINEBUFSIZE,
405 "/TrimBox [ 0 0 %f %f ] ",PageWidth,PageLength);
406 outPdf(linebuf);
407 snprintf(linebuf,LINEBUFSIZE,
408 "/CropBox [ 0 0 %f %f ] ",PageWidth,PageLength);
409 outPdf(linebuf);
410 if (contentsObj >= 0) {
411 snprintf(linebuf,LINEBUFSIZE,
412 "/Contents %d 0 R ",contentsObj);
413 outPdf(linebuf);
414 snprintf(linebuf,LINEBUFSIZE,
415 "/Resources <</ProcSet [/PDF] "
416 "/XObject << /Im %d 0 R >>\n",imgObj);
417 outPdf(linebuf);
418 } else {
419 /* empty page */
420 snprintf(linebuf,LINEBUFSIZE,
421 "/Resources <</ProcSet [/PDF] \n");
422 outPdf(linebuf);
423 }
424 if (outTrfunc) {
425 trfuncObj = newObj();
426 lengthObj = newObj();
427 snprintf(linebuf,LINEBUFSIZE,
428 "/ExtGState << /GS1 << /TR %d 0 R >> >>\n",trfuncObj);
429 outPdf(linebuf);
430 }
431 outPdf(" >>\n>>\nendobj\n");
432
433 if (outTrfunc) {
434 /* out translate function */
435 setOffset(trfuncObj);
436 snprintf(linebuf,LINEBUFSIZE,
437 "%d 0 obj <</FunctionType 4 /Domain [0 1.0]"
438 " /Range [0 1.0] /Length %d 0 R >>\n",
439 trfuncObj,lengthObj);
440 outPdf(linebuf);
441 outPdf("stream\n");
442 startOffset = currentOffset;
443 snprintf(linebuf,LINEBUFSIZE,
444 "{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
445 "ifelse %.3f mul }\n", gammaval, brightness);
446 outPdf(linebuf);
447 length = currentOffset - startOffset;
448 snprintf(linebuf,LINEBUFSIZE,
449 "endstream\nendobj\n");
450 outPdf(linebuf);
451
452 /* out length object */
453 setOffset(lengthObj);
454 snprintf(linebuf,LINEBUFSIZE,
455 "%d 0 obj %d endobj\n",lengthObj,length);
456 outPdf(linebuf);
457 }
458 }
459
outPageContents(int contentsObj)460 static void outPageContents(int contentsObj)
461 {
462 int startOffset;
463 int lengthObj;
464 int length;
465
466 setOffset(contentsObj);
467 lengthObj = newObj();
468 snprintf(linebuf,LINEBUFSIZE,
469 "%d 0 obj <</Length %d 0 R >> stream\n",contentsObj,lengthObj);
470 outPdf(linebuf);
471 startOffset = currentOffset;
472
473 if (gammaval != 1.0 || brightness != 1.0)
474 outPdf("/GS1 gs\n");
475 if (Flip)
476 {
477 snprintf(linebuf,LINEBUFSIZE,
478 "-1 0 0 1 %.0f 0 cm\n",PageWidth);
479 outPdf(linebuf);
480 }
481
482 switch (Orientation)
483 {
484 case 1:
485 snprintf(linebuf,LINEBUFSIZE,
486 "0 1 -1 0 %.0f 0 cm\n",PageWidth);
487 outPdf(linebuf);
488 break;
489 case 2:
490 snprintf(linebuf,LINEBUFSIZE,
491 "-1 0 0 -1 %.0f %.0f cm\n",PageWidth, PageLength);
492 outPdf(linebuf);
493 break;
494 case 3:
495 snprintf(linebuf,LINEBUFSIZE,
496 "0 -1 1 0 0 %.0f cm\n",PageLength);
497 outPdf(linebuf);
498 break;
499 }
500
501 xc0 = cupsImageGetWidth(img) * xpage / xpages;
502 xc1 = cupsImageGetWidth(img) * (xpage + 1) / xpages - 1;
503 yc0 = cupsImageGetHeight(img) * ypage / ypages;
504 yc1 = cupsImageGetHeight(img) * (ypage + 1) / ypages - 1;
505
506 snprintf(linebuf,LINEBUFSIZE,
507 "1 0 0 1 %.1f %.1f cm\n",left,top);
508 outPdf(linebuf);
509
510 snprintf(linebuf,LINEBUFSIZE,
511 "%.3f 0 0 %.3f 0 0 cm\n",
512 xprint * 72.0, yprint * 72.0);
513 outPdf(linebuf);
514 outPdf("/Im Do\n");
515 length = currentOffset - startOffset - 1;
516 outPdf("endstream\nendobj\n");
517
518 /* out length object */
519 setOffset(lengthObj);
520 snprintf(linebuf,LINEBUFSIZE,
521 "%d 0 obj %d endobj\n",lengthObj,length);
522 outPdf(linebuf);
523 }
524
outImage(int imgObj)525 static void outImage(int imgObj)
526 {
527 int y; /* Current Y coordinate in image */
528 #ifdef OUT_AS_ASCII85
529 int out_offset; /* Offset into output buffer */
530 #endif
531 int out_length; /* Length of output buffer */
532 int startOffset;
533 int lengthObj;
534 int length;
535
536 setOffset(imgObj);
537 lengthObj = newObj();
538 snprintf(linebuf,LINEBUFSIZE,
539 "%d 0 obj << /Length %d 0 R /Type /XObject "
540 "/Subtype /Image /Name /Im"
541 #ifdef OUT_AS_HEX
542 "/Filter /ASCIIHexDecode "
543 #else
544 #ifdef OUT_AS_ASCII85
545 "/Filter /ASCII85Decode "
546 #endif
547 #endif
548 ,imgObj,lengthObj);
549 outPdf(linebuf);
550 snprintf(linebuf,LINEBUFSIZE,
551 "/Width %d /Height %d /BitsPerComponent 8 ",
552 xc1 - xc0 + 1, yc1 - yc0 + 1);
553 outPdf(linebuf);
554
555 switch (colorspace)
556 {
557 case CUPS_IMAGE_WHITE :
558 outPdf("/ColorSpace /DeviceGray ");
559 outPdf("/Decode[0 1] ");
560 break;
561 case CUPS_IMAGE_RGB :
562 outPdf("/ColorSpace /DeviceRGB ");
563 outPdf("/Decode[0 1 0 1 0 1] ");
564 break;
565 case CUPS_IMAGE_CMYK :
566 outPdf("/ColorSpace /DeviceCMYK ");
567 outPdf("/Decode[0 1 0 1 0 1 0 1] ");
568 break;
569 }
570 if (((xc1 - xc0 + 1) / xprint) < 100.0)
571 outPdf("/Interpolate true ");
572
573 outPdf(">>\n");
574 outPdf("stream\n");
575 startOffset = currentOffset;
576
577 #ifdef OUT_AS_ASCII85
578 /* out ascii85 needs multiple of 4bytes */
579 for (y = yc0, out_offset = 0; y <= yc1; y ++)
580 {
581 cupsImageGetRow(img, xc0, y, xc1 - xc0 + 1, row + out_offset);
582
583 out_length = (xc1 - xc0 + 1) * abs(colorspace) + out_offset;
584 out_offset = out_length & 3;
585
586 out_ascii85(row, out_length, y == yc1);
587
588 if (out_offset > 0)
589 memcpy(row, row + out_length - out_offset, out_offset);
590 }
591 #else
592 for (y = yc0; y <= yc1; y ++)
593 {
594 cupsImageGetRow(img, xc0, y, xc1 - xc0 + 1, row);
595
596 out_length = (xc1 - xc0 + 1) * abs(colorspace);
597
598 #ifdef OUT_AS_HEX
599 out_hex(row, out_length, y == yc1);
600 #else
601 out_bin(row, out_length, y == yc1);
602 #endif
603 }
604 #endif
605 length = currentOffset - startOffset;
606 outPdf("\nendstream\nendobj\n");
607
608 /* out length object */
609 setOffset(lengthObj);
610 snprintf(linebuf,LINEBUFSIZE,
611 "%d 0 obj %d endobj\n",lengthObj,length);
612 outPdf(linebuf);
613 }
614
615 /*
616 * Copied ppd_decode() from CUPS which is not exported to the API
617 */
618
619 static int /* O - Length of decoded string */
ppd_decode(char * string)620 ppd_decode(char *string) /* I - String to decode */
621 {
622 char *inptr, /* Input pointer */
623 *outptr; /* Output pointer */
624
625
626 inptr = string;
627 outptr = string;
628
629 while (*inptr != '\0')
630 if (*inptr == '<' && isxdigit(inptr[1] & 255))
631 {
632 /*
633 * Convert hex to 8-bit values...
634 */
635
636 inptr ++;
637 while (isxdigit(*inptr & 255))
638 {
639 if (isalpha(*inptr))
640 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
641 else
642 *outptr = (*inptr - '0') << 4;
643
644 inptr ++;
645
646 if (!isxdigit(*inptr & 255))
647 break;
648
649 if (isalpha(*inptr))
650 *outptr |= tolower(*inptr) - 'a' + 10;
651 else
652 *outptr |= *inptr - '0';
653
654 inptr ++;
655 outptr ++;
656 }
657
658 while (*inptr != '>' && *inptr != '\0')
659 inptr ++;
660 while (*inptr == '>')
661 inptr ++;
662 }
663 else
664 *outptr++ = *inptr++;
665
666 *outptr = '\0';
667
668 return ((int)(outptr - string));
669 }
670
671 /*
672 * 'main()' - Main entry...
673 */
674
675 int /* O - Exit status */
main(int argc,char * argv[])676 main(int argc, /* I - Number of command-line arguments */
677 char *argv[]) /* I - Command-line arguments */
678 {
679 cups_page_header2_t h; /* CUPS Raster page header, to */
680 /* accommodate results of command */
681 /* line parsing for PPD-less queue */
682 ppd_choice_t *choice; /* PPD option choice */
683 int num_options; /* Number of print options */
684 cups_option_t *options; /* Print options */
685 const char *val; /* Option value */
686 float zoom; /* Zoom facter */
687 int xppi, yppi; /* Pixels-per-inch */
688 int hue, sat; /* Hue and saturation adjustment */
689 int emit_jcl;
690 int pdf_printer = 0;
691 char filename[1024]; /* Name of file to print */
692 int deviceCopies = 1;
693 int deviceCollate = 0;
694 int deviceReverse = 0;
695 ppd_attr_t *attr;
696 int pl,pr;
697 int fillprint = 0; /* print-scaling = fill */
698 int cropfit = 0; /* -o crop-to-fit = true */
699 /*
700 * Make sure status messages are not buffered...
701 */
702
703 setbuf(stderr, NULL);
704
705 /*
706 * Check command-line...
707 */
708
709 if (argc < 6 || argc > 7)
710 {
711 fputs("ERROR: imagetopdf job-id user title copies options [file]\n", stderr);
712 return (1);
713 }
714
715 title = argv[3];
716 fprintf(stderr, "INFO: %s %s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
717 argv[3], argv[4], argv[5], argv[6] ? argv[6] : "(null)");
718
719 /*
720 * Copy stdin as needed...
721 */
722
723 if (argc == 6)
724 {
725 int fd; /* File to write to */
726 char buffer[8192]; /* Buffer to read into */
727 int bytes; /* # of bytes to read */
728
729
730 if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
731 {
732 perror("ERROR: Unable to copy image file");
733 return (1);
734 }
735
736 fprintf(stderr, "DEBUG: imagetopdf - copying to temp print file \"%s\"\n",
737 filename);
738
739 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
740 if (write(fd, buffer, bytes) == -1)
741 fprintf(stderr,
742 "DEBUG: imagetopdf - write error on temp print file \"%s\"\n",
743 filename);
744
745 close(fd);
746 }
747 else
748 {
749 strncpy(filename, argv[6], sizeof(filename) - 1);
750 }
751
752 /*
753 * Process command-line options and write the prolog...
754 */
755
756 zoom = 1.0;
757 xppi = 0;
758 yppi = 0;
759 hue = 0;
760 sat = 100;
761
762 Copies = atoi(argv[4]);
763
764 options = NULL;
765 num_options = cupsParseOptions(argv[5], 0, &options);
766
767 ppd = SetCommonOptions(num_options, options, 0);
768 if (!ppd) {
769 cupsRasterParseIPPOptions(&h, num_options, options, 0, 1);
770 Orientation = h.Orientation;
771 Duplex = h.Duplex;
772 ColorDevice = h.cupsNumColors <= 1 ? 0 : 1;
773 PageWidth = h.cupsPageSize[0] != 0.0 ? h.cupsPageSize[0] :
774 (float)h.PageSize[0];
775 PageLength = h.cupsPageSize[1] != 0.0 ? h.cupsPageSize[1] :
776 (float)h.PageSize[1];
777 PageLeft = h.cupsImagingBBox[0] != 0.0 ? h.cupsImagingBBox[0] :
778 (float)h.ImagingBoundingBox[0];
779 PageBottom = h.cupsImagingBBox[1] != 0.0 ? h.cupsImagingBBox[1] :
780 (float)h.ImagingBoundingBox[1];
781 PageRight = h.cupsImagingBBox[2] != 0.0 ? h.cupsImagingBBox[2] :
782 (float)h.ImagingBoundingBox[2];
783 PageTop = h.cupsImagingBBox[3] != 0.0 ? h.cupsImagingBBox[3] :
784 (float)h.ImagingBoundingBox[3];
785 Flip = h.MirrorPrint ? 1 : 0;
786 Collate = h.Collate ? 1 : 0;
787 Copies = h.NumCopies;
788 }
789
790 if (Copies == 1
791 && (choice = ppdFindMarkedChoice(ppd,"Copies")) != NULL) {
792 Copies = atoi(choice->choice);
793 }
794 if (Copies == 0) Copies = 1;
795 if ((val = cupsGetOption("Duplex",num_options,options)) != 0 &&
796 (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
797 !strcasecmp(val, "yes"))) {
798 /* for compatiblity */
799 if (ppdFindOption(ppd,"Duplex") != NULL) {
800 ppdMarkOption(ppd,"Duplex","True");
801 ppdMarkOption(ppd,"Duplex","On");
802 Duplex = 1;
803 }
804 } else if ((val = cupsGetOption("sides",num_options,options)) != 0 &&
805 (!strcasecmp(val, "two-sided-long-edge") ||
806 !strcasecmp(val, "two-sided-short-edge"))) {
807 /* for compatiblity */
808 if (ppdFindOption(ppd,"Duplex") != NULL) {
809 ppdMarkOption(ppd,"Duplex","True");
810 ppdMarkOption(ppd,"Duplex","On");
811 Duplex = 1;
812 }
813 }
814
815 if ((val = cupsGetOption("OutputOrder",num_options,options)) != 0) {
816 if (!strcasecmp(val, "Reverse")) {
817 Reverse = 1;
818 }
819 } else if (ppd) {
820 /*
821 * Figure out the right default output order from the PPD file...
822 */
823
824 if ((choice = ppdFindMarkedChoice(ppd,"OutputOrder")) != 0) {
825 Reverse = !strcasecmp(choice->choice,"Reverse");
826 } else if ((choice = ppdFindMarkedChoice(ppd,"OutputBin")) != 0 &&
827 (attr = ppdFindAttr(ppd,"PageStackOrder",choice->choice)) != 0 &&
828 attr->value) {
829 Reverse = !strcasecmp(attr->value,"Reverse");
830 } else if ((attr = ppdFindAttr(ppd,"DefaultOutputOrder",0)) != 0 &&
831 attr->value) {
832 Reverse = !strcasecmp(attr->value,"Reverse");
833 }
834 }
835
836 /* adjust to even page when duplex */
837 if (((val = cupsGetOption("cupsEvenDuplex",num_options,options)) != 0 &&
838 (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
839 !strcasecmp(val, "yes"))) ||
840 ((attr = ppdFindAttr(ppd,"cupsEvenDuplex",0)) != 0 &&
841 (!strcasecmp(attr->value, "true")
842 || !strcasecmp(attr->value, "on") ||
843 !strcasecmp(attr->value, "yes")))) {
844 EvenDuplex = 1;
845 }
846
847 if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
848 {
849 /*
850 * This IPP attribute is unnecessarily complicated...
851 *
852 * single-document, separate-documents-collated-copies, and
853 * single-document-new-sheet all require collated copies.
854 *
855 * separate-documents-uncollated-copies allows for uncollated copies.
856 */
857
858 Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
859 }
860
861 if ((val = cupsGetOption("Collate", num_options, options)) != NULL) {
862 if (strcasecmp(val, "True") == 0) {
863 Collate = 1;
864 }
865 } else {
866 if ((choice = ppdFindMarkedChoice(ppd,"Collate")) != NULL
867 && (!strcasecmp(choice->choice,"true")
868 || !strcasecmp(choice->choice, "on")
869 || !strcasecmp(choice->choice, "yes"))) {
870 Collate = 1;
871 }
872 }
873
874 if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
875 gammaval = atoi(val) * 0.001f;
876
877 if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
878 brightness = atoi(val) * 0.01f;
879
880 if ((val = cupsGetOption("ppi", num_options, options)) != NULL)
881 {
882 if (sscanf(val, "%dx%d", &xppi, &yppi) < 2)
883 yppi = xppi;
884 zoom = 0.0;
885 }
886
887 if ((val = cupsGetOption("position", num_options, options)) != NULL)
888 {
889 if (strcasecmp(val, "center") == 0)
890 {
891 XPosition = 0;
892 YPosition = 0;
893 }
894 else if (strcasecmp(val, "top") == 0)
895 {
896 XPosition = 0;
897 YPosition = 1;
898 }
899 else if (strcasecmp(val, "left") == 0)
900 {
901 XPosition = -1;
902 YPosition = 0;
903 }
904 else if (strcasecmp(val, "right") == 0)
905 {
906 XPosition = 1;
907 YPosition = 0;
908 }
909 else if (strcasecmp(val, "top-left") == 0)
910 {
911 XPosition = -1;
912 YPosition = 1;
913 }
914 else if (strcasecmp(val, "top-right") == 0)
915 {
916 XPosition = 1;
917 YPosition = 1;
918 }
919 else if (strcasecmp(val, "bottom") == 0)
920 {
921 XPosition = 0;
922 YPosition = -1;
923 }
924 else if (strcasecmp(val, "bottom-left") == 0)
925 {
926 XPosition = -1;
927 YPosition = -1;
928 }
929 else if (strcasecmp(val, "bottom-right") == 0)
930 {
931 XPosition = 1;
932 YPosition = -1;
933 }
934 }
935
936 if ((val = cupsGetOption("saturation", num_options, options)) != NULL)
937 sat = atoi(val);
938
939 if ((val = cupsGetOption("hue", num_options, options)) != NULL)
940 hue = atoi(val);
941
942 if ((val = cupsGetOption("mirror", num_options, options)) != NULL &&
943 strcasecmp(val, "True") == 0)
944 Flip = 1;
945
946 if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
947 (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
948 !strcasecmp(val, "no") || !strcmp(val, "0")))
949 emit_jcl = 0;
950 else
951 emit_jcl = 1;
952
953
954
955 /*
956 * Open the input image to print...
957 */
958
959 colorspace = ColorDevice ? CUPS_IMAGE_RGB_CMYK : CUPS_IMAGE_WHITE;
960
961 img = cupsImageOpen(filename, colorspace, CUPS_IMAGE_WHITE, sat, hue, NULL);
962 if(img!=NULL){
963
964 int margin_defined = 0;
965 int fidelity = 0;
966 int document_large = 0;
967
968 if(ppd && (ppd->custom_margins[0]||ppd->custom_margins[1]||
969 ppd->custom_margins[2]||ppd->custom_margins[3])) // In case of custom margins
970 margin_defined = 1;
971 if(PageLength!=PageTop-PageBottom||PageWidth!=PageRight-PageLeft)
972 margin_defined = 1;
973
974 if((val = cupsGetOption("ipp-attribute-fidelity",num_options,options)) != NULL) {
975 if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")||
976 !strcasecmp(val,"on")) {
977 fidelity = 1;
978 }
979 }
980
981 float w = (float)cupsImageGetWidth(img);
982 float h = (float)cupsImageGetHeight(img);
983 float pw = PageRight-PageLeft;
984 float ph = PageTop-PageBottom;
985 int tempOrientation = Orientation;
986 if((val = cupsGetOption("orientation-requested",num_options,options))!=NULL) {
987 tempOrientation = atoi(val);
988 }
989 else if((val = cupsGetOption("landscape",num_options,options))!=NULL) {
990 if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) {
991 tempOrientation = 4;
992 }
993 }
994 if(tempOrientation==0) {
995 if(((pw > ph) && (w < h)) || ((pw < ph) && (w > h)))
996 tempOrientation = 4;
997 }
998 if(tempOrientation==4||tempOrientation==5) {
999 int tmp = pw;
1000 pw = ph;
1001 ph = tmp;
1002 }
1003 if (w * 72.0 / img->xppi > pw || h * 72.0 / img->yppi > ph)
1004 document_large = 1;
1005
1006 if((val = cupsGetOption("print-scaling",num_options,options)) != NULL) {
1007 if(!strcasecmp(val,"auto")) {
1008 if(fidelity||document_large) {
1009 if(margin_defined)
1010 zoom = 1.0; // fit method
1011 else
1012 fillprint = 1; // fill method
1013 }
1014 else
1015 cropfit = 1; // none method
1016 }
1017 else if(!strcasecmp(val,"auto-fit")) {
1018 if(fidelity||document_large)
1019 zoom = 1.0; // fit method
1020 else
1021 cropfit = 1; // none method
1022 }
1023 else if(!strcasecmp(val,"fill"))
1024 fillprint = 1; // fill method
1025 else if(!strcasecmp(val,"fit"))
1026 zoom = 1.0; // fitplot = 1 or fit method
1027 else
1028 cropfit=1; // none or crop-to-fit
1029 }
1030 else{ // print-scaling is not defined, look for alternate options.
1031
1032 if ((val = cupsGetOption("scaling", num_options, options)) != NULL)
1033 zoom = atoi(val) * 0.01;
1034 else if (((val =
1035 cupsGetOption("fit-to-page", num_options, options)) != NULL) ||
1036 ((val = cupsGetOption("fitplot", num_options, options)) != NULL))
1037 {
1038 if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") ||
1039 !strcasecmp(val, "true"))
1040 zoom = 1.0;
1041 else
1042 zoom = 0.0;
1043 }
1044 else if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
1045 zoom = 0.0;
1046
1047 if((val = cupsGetOption("fill",num_options,options))!=0) {
1048 if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) {
1049 fillprint = 1;
1050 }
1051 }
1052
1053 if((val = cupsGetOption("crop-to-fit",num_options,options))!= NULL){
1054 if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) {
1055 cropfit=1;
1056 }
1057 } }
1058 }
1059 if(fillprint||cropfit)
1060 {
1061 /* For cropfit do the math without the unprintable margins to get correct
1062 centering */
1063 if (cropfit)
1064 {
1065 PageBottom = 0.0;
1066 PageTop = PageLength;
1067 PageLeft = 0.0;
1068 PageRight = PageWidth;
1069 }
1070 float w = (float)cupsImageGetWidth(img);
1071 float h = (float)cupsImageGetHeight(img);
1072 float pw = PageRight-PageLeft;
1073 float ph = PageTop-PageBottom;
1074 int tempOrientation = Orientation;
1075 const char *val;
1076 int flag = 3;
1077 if((val = cupsGetOption("orientation-requested",num_options,options))!=NULL)
1078 {
1079 tempOrientation = atoi(val);
1080 }
1081 else if((val = cupsGetOption("landscape",num_options,options))!=NULL)
1082 {
1083 if(!strcasecmp(val,"true")||!strcasecmp(val,"yes"))
1084 {
1085 tempOrientation = 4;
1086 }
1087 }
1088 if(tempOrientation>0)
1089 {
1090 if(tempOrientation==4||tempOrientation==5)
1091 {
1092 float temp = pw;
1093 pw = ph;
1094 ph = temp;
1095 flag = 4;
1096 }
1097 }
1098 if(tempOrientation==0)
1099 {
1100 if(((pw > ph) && (w < h)) || ((pw < ph) && (w > h)))
1101 {
1102 int temp = pw;
1103 pw = ph;
1104 ph = temp;
1105 flag = 4;
1106 }
1107 }
1108 if(fillprint){
1109 float final_w,final_h;
1110 if(w*ph/pw <=h){
1111 final_w =w;
1112 final_h =w*ph/pw;
1113 }
1114 else{
1115 final_w = h*pw/ph;
1116 final_h = h;
1117 }
1118 float posw=(w-final_w)/2,posh=(h-final_h)/2;
1119 posw = (1+XPosition)*posw;
1120 posh = (1-YPosition)*posh;
1121 cups_image_t *img2 = cupsImageCrop(img,posw,posh,final_w,final_h);
1122 cupsImageClose(img);
1123 img = img2;
1124 }
1125 else
1126 {
1127 float final_w=w,final_h=h;
1128 if (w > pw * img->xppi / 72.0)
1129 final_w = pw * img->xppi / 72.0;
1130 if (h > ph * img->yppi / 72.0)
1131 final_h = ph * img->yppi / 72.0;
1132 float posw=(w-final_w)/2,posh=(h-final_h)/2;
1133 posw = (1+XPosition)*posw;
1134 posh = (1-YPosition)*posh;
1135 cups_image_t *img2 = cupsImageCrop(img,posw,posh,final_w,final_h);
1136 cupsImageClose(img);
1137 img = img2;
1138 if(flag==4)
1139 {
1140 PageBottom += (PageLength - final_w * 72.0 / img->xppi) / 2;
1141 PageTop = PageBottom + final_w * 72.0 / img->xppi;
1142 PageLeft += (PageWidth - final_h * 72.0 / img->yppi) / 2;
1143 PageRight = PageLeft + final_h * 72.0 / img->yppi;
1144 }
1145 else
1146 {
1147 PageBottom += (PageLength - final_h * 72.0 / img->yppi) / 2;
1148 PageTop = PageBottom + final_h * 72.0 / img->yppi;
1149 PageLeft += (PageWidth - final_w * 72.0 / img->xppi) / 2;
1150 PageRight = PageLeft + final_w * 72.0 / img->xppi;
1151 }
1152 if(PageBottom<0) PageBottom = 0;
1153 if(PageLeft<0) PageLeft = 0;
1154 }
1155 }
1156
1157 #if defined(USE_CONVERT_CMD) && defined(CONVERT_CMD)
1158 if (img == NULL) {
1159 char filename2[1024];
1160 int fd2;
1161
1162 if ((fd2 = cupsTempFd(filename2, sizeof(filename2))) < 0)
1163 {
1164 perror("ERROR: Unable to copy image file");
1165 return (1);
1166 }
1167 close(fd2);
1168 snprintf(linebuf,LINEBUFSIZE,
1169 CONVERT_CMD
1170 " %s png:%s",filename, filename2);
1171 if (system(linebuf) != 0) {
1172 unlink(filename2);
1173 perror("ERROR: Unable to copy image file");
1174 return (1);
1175 }
1176 img = cupsImageOpen(filename2, colorspace,
1177 CUPS_IMAGE_WHITE, sat, hue, NULL);
1178 unlink(filename2);
1179 }
1180 #endif
1181 if (argc == 6)
1182 unlink(filename);
1183
1184 if (img == NULL)
1185 {
1186 fputs("ERROR: Unable to open image file for printing!\n", stderr);
1187 ppdClose(ppd);
1188 return (1);
1189 }
1190
1191 colorspace = cupsImageGetColorSpace(img);
1192
1193 /*
1194 * Scale as necessary...
1195 */
1196
1197 if (zoom == 0.0 && xppi == 0)
1198 {
1199 xppi = cupsImageGetXPPI(img);
1200 yppi = cupsImageGetYPPI(img);
1201 }
1202
1203 if (yppi == 0)
1204 yppi = xppi;
1205
1206 fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n",
1207 xppi, yppi, zoom);
1208
1209 if (xppi > 0)
1210 {
1211 /*
1212 * Scale the image as neccesary to match the desired pixels-per-inch.
1213 */
1214
1215 if (Orientation & 1)
1216 {
1217 xprint = (PageTop - PageBottom) / 72.0;
1218 yprint = (PageRight - PageLeft) / 72.0;
1219 }
1220 else
1221 {
1222 xprint = (PageRight - PageLeft) / 72.0;
1223 yprint = (PageTop - PageBottom) / 72.0;
1224 }
1225
1226 fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
1227 xprint, yprint);
1228
1229 xinches = (float)cupsImageGetWidth(img) / (float)xppi;
1230 yinches = (float)cupsImageGetHeight(img) / (float)yppi;
1231
1232 fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n",
1233 xinches, yinches);
1234
1235 if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
1236 {
1237 xinches = xinches * atoi(val) / 100;
1238 yinches = yinches * atoi(val) / 100;
1239 }
1240
1241 if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
1242 cupsGetOption("landscape", num_options, options) == NULL)
1243 {
1244 /*
1245 * Rotate the image if it will fit landscape but not portrait...
1246 */
1247
1248 fputs("DEBUG: Auto orientation...\n", stderr);
1249
1250 if ((xinches > xprint || yinches > yprint) &&
1251 xinches <= yprint && yinches <= xprint)
1252 {
1253 /*
1254 * Rotate the image as needed...
1255 */
1256
1257 fputs("DEBUG: Using landscape orientation...\n", stderr);
1258
1259 Orientation = (Orientation + 1) & 3;
1260 xsize = yprint;
1261 yprint = xprint;
1262 xprint = xsize;
1263 }
1264 }
1265 }
1266 else
1267 {
1268 /*
1269 * Scale percentage of page size...
1270 */
1271
1272 xprint = (PageRight - PageLeft) / 72.0;
1273 yprint = (PageTop - PageBottom) / 72.0;
1274 aspect = (float)cupsImageGetYPPI(img) / (float)cupsImageGetXPPI(img);
1275
1276 fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n",
1277 xprint, yprint);
1278
1279 fprintf(stderr, "DEBUG: cupsImageGetXPPI(img) = %d, cupsImageGetYPPI(img) = %d, aspect = %f\n",
1280 cupsImageGetXPPI(img), cupsImageGetYPPI(img), aspect);
1281
1282 xsize = xprint * zoom;
1283 ysize = xsize * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect;
1284
1285 if (ysize > (yprint * zoom))
1286 {
1287 ysize = yprint * zoom;
1288 xsize = ysize * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img);
1289 }
1290
1291 xsize2 = yprint * zoom;
1292 ysize2 = xsize2 * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect;
1293
1294 if (ysize2 > (xprint * zoom))
1295 {
1296 ysize2 = xprint * zoom;
1297 xsize2 = ysize2 * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img);
1298 }
1299
1300 fprintf(stderr, "DEBUG: Portrait size is %.2f x %.2f inches\n", xsize, ysize);
1301 fprintf(stderr, "DEBUG: Landscape size is %.2f x %.2f inches\n", xsize2, ysize2);
1302
1303 if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
1304 cupsGetOption("landscape", num_options, options) == NULL)
1305 {
1306 /*
1307 * Choose the rotation with the largest area, but prefer
1308 * portrait if they are equal...
1309 */
1310
1311 fputs("DEBUG: Auto orientation...\n", stderr);
1312
1313 if ((xsize * ysize) < (xsize2 * xsize2))
1314 {
1315 /*
1316 * Do landscape orientation...
1317 */
1318
1319 fputs("DEBUG: Using landscape orientation...\n", stderr);
1320
1321 Orientation = 1;
1322 xinches = xsize2;
1323 yinches = ysize2;
1324 xprint = (PageTop - PageBottom) / 72.0;
1325 yprint = (PageRight - PageLeft) / 72.0;
1326 }
1327 else
1328 {
1329 /*
1330 * Do portrait orientation...
1331 */
1332
1333 fputs("DEBUG: Using portrait orientation...\n", stderr);
1334
1335 Orientation = 0;
1336 xinches = xsize;
1337 yinches = ysize;
1338 }
1339 }
1340 else if (Orientation & 1)
1341 {
1342 fputs("DEBUG: Using landscape orientation...\n", stderr);
1343
1344 xinches = xsize2;
1345 yinches = ysize2;
1346 xprint = (PageTop - PageBottom) / 72.0;
1347 yprint = (PageRight - PageLeft) / 72.0;
1348 }
1349 else
1350 {
1351 fputs("DEBUG: Using portrait orientation...\n", stderr);
1352
1353 xinches = xsize;
1354 yinches = ysize;
1355 xprint = (PageRight - PageLeft) / 72.0;
1356 yprint = (PageTop - PageBottom) / 72.0;
1357 }
1358 }
1359
1360 /*
1361 * Compute the number of pages to print and the size of the image on each
1362 * page...
1363 */
1364
1365 if (zoom == 1.0) {
1366 /* If fitplot is specified, make xpages, ypages 1 forcedly.
1367 Because calculation error may be caused and
1368 result of ceil function may be larger than 1.
1369 */
1370 xpages = ypages = 1;
1371 } else {
1372 xpages = ceil(xinches / xprint);
1373 ypages = ceil(yinches / yprint);
1374 }
1375
1376 xprint = xinches / xpages;
1377 yprint = yinches / ypages;
1378
1379 fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n",
1380 xpages, xprint, ypages, yprint);
1381
1382 /*
1383 * Update the page size for custom sizes...
1384 */
1385
1386 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
1387 strcasecmp(choice->choice, "Custom") == 0)
1388 {
1389 float width, /* New width in points */
1390 length; /* New length in points */
1391 char s[255]; /* New custom page size... */
1392
1393
1394 /*
1395 * Use the correct width and length for the current orientation...
1396 */
1397
1398 if (Orientation & 1)
1399 {
1400 width = yprint * 72.0;
1401 length = xprint * 72.0;
1402 }
1403 else
1404 {
1405 width = xprint * 72.0;
1406 length = yprint * 72.0;
1407 }
1408
1409 /*
1410 * Add margins to page size...
1411 */
1412
1413 width += ppd->custom_margins[0] + ppd->custom_margins[2];
1414 length += ppd->custom_margins[1] + ppd->custom_margins[3];
1415
1416 /*
1417 * Enforce minimums...
1418 */
1419
1420 if (width < ppd->custom_min[0])
1421 width = ppd->custom_min[0];
1422
1423 if (length < ppd->custom_min[1])
1424 length = ppd->custom_min[1];
1425
1426 fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n",
1427 width / 72.0, length / 72.0);
1428
1429 /*
1430 * Set the new custom size...
1431 */
1432
1433 sprintf(s, "Custom.%.0fx%.0f", width, length);
1434 ppdMarkOption(ppd, "PageSize", s);
1435
1436 /*
1437 * Update page variables...
1438 */
1439
1440 PageWidth = width;
1441 PageLength = length;
1442 PageLeft = ppd->custom_margins[0];
1443 PageRight = width - ppd->custom_margins[2];
1444 PageBottom = ppd->custom_margins[1];
1445 PageTop = length - ppd->custom_margins[3];
1446 }
1447
1448 if (Copies == 1) {
1449 /* collate is not needed */
1450 Collate = 0;
1451 ppdMarkOption(ppd,"Collate","False");
1452 }
1453 if (!Duplex) {
1454 /* evenDuplex is not needed */
1455 EvenDuplex = 0;
1456 }
1457
1458 /* check collate device */
1459 if (Collate) {
1460 if ((choice = ppdFindMarkedChoice(ppd,"Collate")) != NULL &&
1461 !strcasecmp(choice->choice,"true")) {
1462 ppd_option_t *opt;
1463
1464 if ((opt = ppdFindOption(ppd,"Collate")) != NULL &&
1465 !opt->conflicted) {
1466 deviceCollate = 1;
1467 } else {
1468 ppdMarkOption(ppd,"Collate","False");
1469 }
1470 }
1471 }
1472 /* check OutputOrder device */
1473 if (Reverse) {
1474 if (ppdFindOption(ppd,"OutputOrder") != NULL) {
1475 deviceReverse = 1;
1476 }
1477 }
1478 if (ppd != NULL &&
1479 !ppd->manual_copies && Collate && !deviceCollate) {
1480 /* Copying by device , software collate is impossible */
1481 /* Enable software copying */
1482 ppd->manual_copies = 1;
1483 }
1484 if (Copies > 1 && (ppd == NULL || ppd->manual_copies)
1485 && Duplex) {
1486 /* Enable software collate , or same pages are printed in both sides */
1487 Collate = 1;
1488 if (deviceCollate) {
1489 deviceCollate = 0;
1490 ppdMarkOption(ppd,"Collate","False");
1491 }
1492 }
1493 if (Duplex && Collate && !deviceCollate) {
1494 /* Enable evenDuplex or the first page may be printed other side of the
1495 end of precedings */
1496 EvenDuplex = 1;
1497 }
1498 if (Duplex && Reverse && !deviceReverse) {
1499 /* Enable evenDuplex or the first page may be empty. */
1500 EvenDuplex = 1;
1501 }
1502 /* change feature for software */
1503 if (deviceCollate) {
1504 Collate = 0;
1505 }
1506 if (deviceReverse) {
1507 Reverse = 0;
1508 }
1509 if (ppd != NULL) {
1510 if (ppd->manual_copies) {
1511 /* sure disable hardware copying */
1512 ppdMarkOption(ppd,"Copies","1");
1513 ppdMarkOption(ppd,"JCLCopies","1");
1514 } else {
1515 /* change for hardware copying */
1516 deviceCopies = Copies;
1517 Copies = 1;
1518 }
1519 }
1520
1521 /*
1522 * See if we need to collate, and if so how we need to do it...
1523 */
1524
1525 if (xpages == 1 && ypages == 1
1526 && (Collate || deviceCollate) && !EvenDuplex) {
1527 /* collate is not needed, disable it */
1528 deviceCollate = 0;
1529 Collate = 0;
1530 ppdMarkOption(ppd,"Collate","False");
1531 }
1532
1533 if (((xpages*ypages) % 2) == 0) {
1534 /* even pages, disable EvenDuplex */
1535 EvenDuplex = 0;
1536 }
1537
1538 /*
1539 * Write any "exit server" options that have been selected...
1540 */
1541
1542 ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
1543
1544 /*
1545 * Write any JCL commands that are needed to print PostScript code...
1546 */
1547
1548 if (ppd && emit_jcl) {
1549 /* pdftopdf only adds JCL to the job if the printer is a native PDF
1550 printer and the PPD is for this mode, having the "*JCLToPDFInterpreter:"
1551 keyword. We need to read this keyword manually from the PPD and replace
1552 the content of ppd->jcl_ps by the value of this keyword, so that
1553 ppdEmitJCL() actalually adds JCL based on the presence on
1554 "*JCLToPDFInterpreter:". */
1555 ppd_attr_t *attr;
1556 char buf[1024];
1557 int devicecopies_done = 0;
1558 char *old_jcl_ps = ppd->jcl_ps;
1559 /* If there is a "Copies" option in the PPD file, assure that hardware
1560 copies are implemented as described by this option */
1561 if (ppdFindOption(ppd,"Copies") != NULL && deviceCopies > 1)
1562 {
1563 snprintf(buf,sizeof(buf),"%d",deviceCopies);
1564 ppdMarkOption(ppd,"Copies",buf);
1565 devicecopies_done = 1;
1566 }
1567 if ((attr = ppdFindAttr(ppd,"JCLToPDFInterpreter",NULL)) != NULL)
1568 {
1569 if (deviceCopies > 1 && devicecopies_done == 0 && /* HW copies */
1570 strncmp(ppd->jcl_begin, "\033%-12345X@", 10) == 0) /* PJL */
1571 {
1572 /* Add a PJL command to implement the hardware copies */
1573 const size_t size = strlen(attr->value) + 1 + 30;
1574 ppd->jcl_ps = (char *)malloc(size * sizeof(char));
1575 if (deviceCollate)
1576 {
1577 snprintf(ppd->jcl_ps, size, "@PJL SET QTY=%d\n%s",
1578 deviceCopies, attr->value);
1579 }
1580 else
1581 {
1582 snprintf(ppd->jcl_ps, size, "@PJL SET COPIES=%d\n%s",
1583 deviceCopies, attr->value);
1584 }
1585 }
1586 else
1587 ppd->jcl_ps = strdup(attr->value);
1588 ppd_decode(ppd->jcl_ps);
1589 pdf_printer = 1;
1590 }
1591 else
1592 {
1593 ppd->jcl_ps = NULL;
1594 pdf_printer = 0;
1595 }
1596 ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
1597 emitJCLOptions(stdout,deviceCopies);
1598 free(ppd->jcl_ps);
1599 ppd->jcl_ps = old_jcl_ps; /* cups uses pool allocator, not free() */
1600 }
1601
1602 /*
1603 * Start sending the document with any commands needed...
1604 */
1605
1606 outPrologue(Copies*xpages*ypages+(EvenDuplex ? 1 : 0));
1607
1608 /*
1609 * Output the pages...
1610 */
1611
1612 row = malloc(cupsImageGetWidth(img) * abs(colorspace) + 3);
1613
1614 fprintf(stderr, "DEBUG: XPosition=%d, YPosition=%d, Orientation=%d\n",
1615 XPosition, YPosition, Orientation);
1616 fprintf(stderr, "DEBUG: xprint=%.0f, yprint=%.0f\n", xprint, yprint);
1617 fprintf(stderr, "DEBUG: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f\n",
1618 PageLeft, PageRight, PageWidth);
1619 fprintf(stderr, "DEBUG: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f\n",
1620 PageBottom, PageTop, PageLength);
1621
1622 if (Flip) {
1623 pr = PageWidth - PageLeft;
1624 pl = PageWidth - PageRight;
1625 } else {
1626 pr = PageRight;
1627 pl = PageLeft;
1628 }
1629
1630 switch (Orientation)
1631 {
1632 default :
1633 switch (XPosition)
1634 {
1635 case -1 :
1636 left = pl;
1637 break;
1638 default :
1639 left = (pr + pl - xprint * 72) / 2;
1640 break;
1641 case 1 :
1642 left = pr - xprint * 72;
1643 break;
1644 }
1645
1646 switch (YPosition)
1647 {
1648 case -1 :
1649 top = PageBottom;
1650 break;
1651 default :
1652 top = (PageTop + PageBottom - yprint * 72) / 2;
1653 break;
1654 case 1 :
1655 top = PageTop - yprint * 72;;
1656 break;
1657 }
1658 break;
1659
1660 case 1 :
1661 switch (XPosition)
1662 {
1663 case -1 :
1664 left = PageBottom;
1665 break;
1666 default :
1667 left = (PageTop + PageBottom - xprint * 72) / 2;
1668 break;
1669 case 1 :
1670 left = PageTop - xprint * 72;
1671 break;
1672 }
1673
1674 switch (YPosition)
1675 {
1676 case -1 :
1677 top = pl;
1678 break;
1679 default :
1680 top = (pr + pl - yprint * 72) / 2;
1681 break;
1682 case 1 :
1683 top = pr - yprint * 72;;
1684 break;
1685 }
1686 break;
1687
1688 case 2 :
1689 switch (XPosition)
1690 {
1691 case -1 :
1692 left = pr - xprint * 72;
1693 break;
1694 default :
1695 left = (pr + pl - xprint * 72) / 2;
1696 break;
1697 case 1 :
1698 left = pl;
1699 break;
1700 }
1701
1702 switch (YPosition)
1703 {
1704 case -1 :
1705 top = PageTop - yprint * 72;
1706 break;
1707 default :
1708 top = (PageTop + PageBottom - yprint * 72) / 2;
1709 break;
1710 case 1 :
1711 top = PageBottom;
1712 break;
1713 }
1714 break;
1715
1716 case 3 :
1717 switch (XPosition)
1718 {
1719 case -1 :
1720 left = PageTop - xprint * 72;
1721 break;
1722 default :
1723 left = (PageTop + PageBottom - xprint * 72) / 2;
1724 break;
1725 case 1 :
1726 left = PageBottom;
1727 break;
1728 }
1729
1730 switch (YPosition)
1731 {
1732 case -1 :
1733 top = pr - yprint * 72;;
1734 break;
1735 default :
1736 top = (pr + pl - yprint * 72) / 2;
1737 break;
1738 case 1 :
1739 top = pl;
1740 break;
1741 }
1742 break;
1743 }
1744
1745 fprintf(stderr, "DEBUG: left=%.2f, top=%.2f\n", left, top);
1746
1747 if (Collate)
1748 {
1749 int *contentsObjs;
1750 int *imgObjs;
1751
1752 if ((contentsObjs = malloc(sizeof(int)*xpages*ypages)) == NULL)
1753 {
1754 fprintf(stderr,"ERROR: Can't allocate contentsObjs\n");
1755 exit(2);
1756 }
1757 if ((imgObjs = malloc(sizeof(int)*xpages*ypages)) == NULL)
1758 {
1759 fprintf(stderr,"ERROR: Can't allocate imgObjs\n");
1760 exit(2);
1761 }
1762 for (xpage = 0; xpage < xpages; xpage ++)
1763 for (ypage = 0; ypage < ypages; ypage ++)
1764 {
1765 int imgObj;
1766 int contentsObj;
1767
1768 contentsObj = contentsObjs[ypages*xpage+ypage] = newObj();
1769 imgObj = imgObjs[ypages*xpage+ypage] = newObj();
1770
1771 /* out contents object */
1772 outPageContents(contentsObj);
1773
1774 /* out image object */
1775 outImage(imgObj);
1776 }
1777 for (page = 0; Copies > 0 ; Copies --) {
1778 for (xpage = 0; xpage < xpages; xpage ++)
1779 for (ypage = 0; ypage < ypages; ypage ++, page ++)
1780 {
1781 /* out Page Object */
1782 outPageObject(pageObjects[page],
1783 contentsObjs[ypages*xpage+ypage],
1784 imgObjs[ypages*xpage+ypage]);
1785 if (pdf_printer)
1786 fprintf(stderr, "PAGE: %d %d\n", page+1, 1);
1787 }
1788 if (EvenDuplex) {
1789 /* out empty page */
1790 outPageObject(pageObjects[page],-1,-1);
1791 if (pdf_printer)
1792 fprintf(stderr, "PAGE: %d %d\n", page+1, 1);
1793 }
1794 }
1795 free(contentsObjs);
1796 free(imgObjs);
1797 }
1798 else {
1799 for (page = 0, xpage = 0; xpage < xpages; xpage ++)
1800 for (ypage = 0; ypage < ypages; ypage ++)
1801 {
1802 int imgObj;
1803 int contentsObj;
1804 int p;
1805
1806 imgObj = newObj();
1807 contentsObj = newObj();
1808
1809 /* out contents object */
1810 outPageContents(contentsObj);
1811
1812 /* out image object */
1813 outImage(imgObj);
1814
1815 for (p = 0;p < Copies;p++, page++)
1816 {
1817 /* out Page Object */
1818 outPageObject(pageObjects[page],contentsObj,imgObj);
1819 if (pdf_printer)
1820 fprintf(stderr, "PAGE: %d %d\n", page+1, 1);
1821 }
1822 }
1823 if (EvenDuplex) {
1824 /* out empty pages */
1825 int p;
1826
1827 for (p = 0;p < Copies;p++, page++)
1828 {
1829 outPageObject(pageObjects[page],-1,-1);
1830 if (pdf_printer)
1831 fprintf(stderr, "PAGE: %d %d\n", page+1, 1);
1832 }
1833 }
1834 }
1835
1836 outXref();
1837 outTrailer();
1838 freeAllObj();
1839 /*
1840 * Close files...
1841 */
1842
1843 #ifndef CUPS_1_1
1844 if (emit_jcl)
1845 {
1846 if (ppd && ppd->jcl_end)
1847 ppdEmitJCLEnd(ppd, stdout);
1848 }
1849 #endif
1850
1851 cupsImageClose(img);
1852 ppdClose(ppd);
1853
1854 return (0);
1855 }
1856
1857 #ifdef OUT_AS_HEX
1858 /*
1859 * 'out_hex()' - Print binary data as a series of hexadecimal numbers.
1860 */
1861
1862 static void
out_hex(cups_ib_t * data,int length,int last_line)1863 out_hex(cups_ib_t *data, /* I - Data to print */
1864 int length, /* I - Number of bytes to print */
1865 int last_line) /* I - Last line of raster data? */
1866 {
1867 static int col = 0; /* Current column */
1868 static char *hex = "0123456789ABCDEF";
1869 /* Hex digits */
1870
1871
1872 while (length > 0)
1873 {
1874 /*
1875 * Put the hex chars out to the file; note that we don't use printf()
1876 * for speed reasons...
1877 */
1878
1879 putcPdf(hex[*data >> 4]);
1880 putcPdf(hex[*data & 15]);
1881
1882 data ++;
1883 length --;
1884
1885 col += 2;
1886 if (col > 78)
1887 {
1888 putcPdf('\n');
1889 col = 0;
1890 }
1891 }
1892
1893 if (last_line && col)
1894 {
1895 putcPdf('\n');
1896 col = 0;
1897 }
1898 }
1899 #else
1900
1901 #ifdef OUT_AS_ASCII85
1902 /*
1903 * 'out_ascii85()' - Print binary data as a series of base-85 numbers.
1904 */
1905
1906 static void
out_ascii85(cups_ib_t * data,int length,int last_line)1907 out_ascii85(cups_ib_t *data, /* I - Data to print */
1908 int length, /* I - Number of bytes to print */
1909 int last_line) /* I - Last line of raster data? */
1910 {
1911 unsigned b; /* Binary data word */
1912 unsigned char c[6]; /* ASCII85 encoded chars */
1913 static int col = 0; /* Current column */
1914
1915
1916 c[5] = '\0'; /* end mark */
1917 while (length > 3)
1918 {
1919 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
1920
1921 if (b == 0)
1922 {
1923 putcPdf('z');
1924 col ++;
1925 }
1926 else
1927 {
1928 c[4] = (b % 85) + '!';
1929 b /= 85;
1930 c[3] = (b % 85) + '!';
1931 b /= 85;
1932 c[2] = (b % 85) + '!';
1933 b /= 85;
1934 c[1] = (b % 85) + '!';
1935 b /= 85;
1936 c[0] = b + '!';
1937
1938 outPdf(c);
1939 col += 5;
1940 }
1941
1942 data += 4;
1943 length -= 4;
1944
1945 if (col >= 75)
1946 {
1947 putcPdf('\n');
1948 col = 0;
1949 }
1950 }
1951
1952 if (last_line)
1953 {
1954 if (length > 0)
1955 {
1956 memset(data + length, 0, 4 - length);
1957 b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
1958
1959 c[4] = (b % 85) + '!';
1960 b /= 85;
1961 c[3] = (b % 85) + '!';
1962 b /= 85;
1963 c[2] = (b % 85) + '!';
1964 b /= 85;
1965 c[1] = (b % 85) + '!';
1966 b /= 85;
1967 c[0] = b + '!';
1968
1969 c[length+1] = '\0';
1970 outPdf(c);
1971 }
1972
1973 outPdf("~>");
1974 col = 0;
1975 }
1976 }
1977 #else
1978 /*
1979 * 'out_bin()' - Print binary data as binary.
1980 */
1981
1982 static void
out_bin(cups_ib_t * data,int length,int last_line)1983 out_bin(cups_ib_t *data, /* I - Data to print */
1984 int length, /* I - Number of bytes to print */
1985 int last_line) /* I - Last line of raster data? */
1986 {
1987 while (length > 0)
1988 {
1989 putcPdf(*data);
1990 data ++;
1991 length --;
1992 }
1993
1994 if (last_line)
1995 {
1996 putcPdf('\n');
1997 }
1998 }
1999 #endif
2000 #endif
2001