• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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