2
Copyright (c) 2006-2007, BBR Inc. All rights reserved.
4
Permission is hereby granted, free of charge, to any person obtaining
5
a copy of this software and associated documentation files (the
6
"Software"), to deal in the Software without restriction, including
7
without limitation the rights to use, copy, modify, merge, publish,
8
distribute, sublicense, and/or sell copies of the Software, and to
9
permit persons to whom the Software is furnished to do so, subject to
10
the following conditions:
12
The above copyright notice and this permission notice shall be included
13
in all copies or substantial portions of the Software.
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
#include "goo/GooString.h"
38
#include "P2POutputStream.h"
39
#include <cups/cups.h>
42
#include "GlobalParams.h"
43
#include "PDFFTrueTypeFont.h"
47
GBool fitplot = gFalse;
48
GBool mirror = gFalse;
50
unsigned int numberUpLayout = PDFTOPDF_LAYOUT_LRTB;
51
unsigned int pageBorder = PDFTOPDF_BORDERNONE;
52
double pageLeft = 18.0;
53
double pageRight = 594.0;
54
double pageBottom = 36.0;
55
double pageTop = 756.0;
56
double pageWidth = 612.0;
57
double pageLength = 792.0;
58
GBool emitJCL = gTrue;
62
GBool position = gFalse;
65
double naturalScaling = 1.0;
67
GBool deviceCollate = gFalse;
68
GBool deviceReverse = gFalse;
69
GBool autoRotate = gTrue;
70
GBool forcePageSize = gFalse;
73
void CDECL myErrorFun(int pos, char *msg, va_list args)
76
fprintf(stderr, "ERROR (%d): ", pos);
78
fprintf(stderr, "ERROR: ");
80
vfprintf(stderr, msg, args);
81
fprintf(stderr, "\n");
85
GBool checkFeature(const char *feature, int num_options, cups_option_t *options)
90
return ((val = cupsGetOption(feature,num_options,options)) != 0 &&
91
(!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
92
!strcasecmp(val, "yes"))) ||
93
((attr = ppdFindAttr(ppd,feature,0)) != 0 &&
94
(!strcasecmp(attr->value, "true")
95
|| !strcasecmp(attr->value, "on") ||
96
!strcasecmp(attr->value, "yes")));
99
void emitJCLOptions(FILE *fp, int copies)
102
ppd_choice_t **choices;
109
if (ppd == 0) return;
110
if ((attr = ppdFindAttr(ppd,"pdftopdfJCLBegin",NULL)) != NULL) {
111
int n = strlen(attr->value);
113
for (i = 0;i < n;i++) {
114
if (attr->value[i] == '\r' || attr->value[i] == '\n') {
118
fputc(attr->value[i],fp);
123
snprintf(buf,sizeof(buf),"%d",copies);
124
if (ppdFindOption(ppd,"Copies") != NULL) {
125
ppdMarkOption(ppd,"Copies",buf);
127
if ((attr = ppdFindAttr(ppd,"pdftopdfJCLCopies",buf)) != NULL) {
128
fputs(attr->value,fp);
130
} else if (pdftoopvp) {
131
fprintf(fp,"Copies=%d;",copies);
135
for (section = (int)PPD_ORDER_ANY;
136
section <= (int)PPD_ORDER_PROLOG;section++) {
139
n = ppdCollect(ppd,(ppd_section_t)section,&choices);
140
for (i = 0;i < n;i++) {
141
snprintf(buf,sizeof(buf),"pdftopdfJCL%s",
142
((ppd_option_t *)(choices[i]->option))->keyword);
143
if ((attr = ppdFindAttr(ppd,buf,choices[i]->choice)) != NULL) {
144
fputs(attr->value,fp);
146
} else if (pdftoopvp) {
148
((ppd_option_t *)(choices[i]->option))->keyword,
154
if (datawritten) fputc('\n',fp);
157
void parseOpts(int argc, char **argv)
160
cups_option_t *options;
163
ppd_choice_t *choice;
164
ppd_size_t *pagesize;
167
if (argc < 6 || argc > 7) {
168
error(-1,const_cast<char *>("%s job-id user title copies options [file]"),
172
P2PDoc::options.jobId = atoi(argv[1]);
173
P2PDoc::options.user = argv[2];
174
P2PDoc::options.title = argv[3];
175
P2PDoc::options.copies = atoi(argv[4]);
177
ppd = ppdOpenFile(getenv("PPD"));
178
ppdMarkDefaults(ppd);
180
num_options = cupsParseOptions(argv[5],0,&options);
181
cupsMarkOptions(ppd,num_options,options);
182
if (P2PDoc::options.copies == 1
183
&& (choice = ppdFindMarkedChoice(ppd,"Copies")) != NULL) {
184
P2PDoc::options.copies = atoi(choice->choice);
186
if (P2PDoc::options.copies == 0) P2PDoc::options.copies = 1;
187
if ((val = cupsGetOption("fitplot", num_options, options)) == NULL)
188
val = cupsGetOption("fit-to-page", num_options, options);
189
if (val && strcasecmp(val, "no") && strcasecmp(val, "off") &&
190
strcasecmp(val, "false"))
192
if ((pagesize = ppdPageSize(ppd,0)) != 0) {
193
pageWidth = pagesize->width;
194
pageLength = pagesize->length;
195
pageTop = pagesize->top;
196
pageBottom = pagesize->bottom;
197
pageLeft = pagesize->left;
198
pageRight = pagesize->right;
199
forcePageSize = fitplot;
201
if ((val = cupsGetOption("landscape",num_options,options)) != 0) {
202
if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 &&
203
strcasecmp(val, "false") != 0) {
204
if (ppd && ppd->landscape > 0) {
211
cupsGetOption("orientation-requested",num_options,options)) != 0) {
213
* Map IPP orientation values to 0 to 3:
217
* 5 = -90 degrees = 3
218
* 6 = 180 degrees = 2
221
orientation = atoi(val) - 3;
222
if (orientation >= 2) {
226
if ((val = cupsGetOption("page-left",num_options,options)) != 0) {
227
switch (orientation & 3) {
229
pageLeft = (float)atof(val);
232
pageBottom = (float)atof(val);
235
pageRight = pageWidth - (float)atof(val);
238
pageTop = pageLength - (float)atof(val);
242
if ((val = cupsGetOption("page-right",num_options,options)) != 0) {
243
switch (orientation & 3) {
245
pageRight = pageWidth - (float)atof(val);
248
pageTop = pageLength - (float)atof(val);
251
pageLeft = (float)atof(val);
254
pageBottom = (float)atof(val);
258
if ((val = cupsGetOption("page-bottom",num_options,options)) != 0) {
259
switch (orientation & 3) {
261
pageBottom = (float)atof(val);
264
pageLeft = (float)atof(val);
267
pageTop = pageLength - (float)atof(val);
270
pageRight = pageWidth - (float)atof(val);
274
if ((val = cupsGetOption("page-top",num_options,options)) != 0) {
275
switch (orientation & 3) {
277
pageTop = pageLength - (float)atof(val);
280
pageRight = pageWidth - (float)atof(val);
283
pageBottom = (float)atof(val);
286
pageLeft = (float)atof(val);
290
if (ppdIsMarked(ppd,"Duplex","DuplexNoTumble") ||
291
ppdIsMarked(ppd,"Duplex","DuplexTumble") ||
292
ppdIsMarked(ppd,"JCLDuplex","DuplexNoTumble") ||
293
ppdIsMarked(ppd,"JCLDuplex","DuplexTumble") ||
294
ppdIsMarked(ppd,"EFDuplex","DuplexNoTumble") ||
295
ppdIsMarked(ppd,"EFDuplex","DuplexTumble") ||
296
ppdIsMarked(ppd,"KD03Duplex","DuplexNoTumble") ||
297
ppdIsMarked(ppd,"KD03Duplex","DuplexTumble")) {
298
P2PDoc::options.duplex = gTrue;
299
} else if ((val = cupsGetOption("Duplex",num_options,options)) != 0 &&
300
(!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
301
!strcasecmp(val, "yes"))) {
302
/* for compatiblity */
303
if (ppdFindOption(ppd,"Duplex") != NULL) {
304
ppdMarkOption(ppd,"Duplex","True");
305
ppdMarkOption(ppd,"Duplex","On");
306
P2PDoc::options.duplex = gTrue;
308
} else if ((val = cupsGetOption("sides",num_options,options)) != 0 &&
309
(!strcasecmp(val, "two-sided-long-edge") ||
310
!strcasecmp(val, "two-sided-short-edge"))) {
311
/* for compatiblity */
312
if (ppdFindOption(ppd,"Duplex") != NULL) {
313
ppdMarkOption(ppd,"Duplex","True");
314
ppdMarkOption(ppd,"Duplex","On");
315
P2PDoc::options.duplex = gTrue;
319
if ((val = cupsGetOption("number-up",num_options,options)) != 0) {
320
switch (intval = atoi(val)) {
332
const_cast<char *>("Unsupported number-up value %d, using number-up=1!\n"),
337
if ((val = cupsGetOption("number-up-layout",num_options,options)) != 0) {
338
if (!strcasecmp(val,"lrtb")) {
339
numberUpLayout = PDFTOPDF_LAYOUT_LRTB;
340
} else if (!strcasecmp(val,"lrbt")) {
341
numberUpLayout = PDFTOPDF_LAYOUT_LRBT;
342
} else if (!strcasecmp(val,"rltb")) {
343
numberUpLayout = PDFTOPDF_LAYOUT_RLTB;
344
} else if (!strcasecmp(val,"rlbt")) {
345
numberUpLayout = PDFTOPDF_LAYOUT_RLBT;
346
} else if (!strcasecmp(val,"tblr")) {
347
numberUpLayout = PDFTOPDF_LAYOUT_TBLR;
348
} else if (!strcasecmp(val,"tbrl")) {
349
numberUpLayout = PDFTOPDF_LAYOUT_TBRL;
350
} else if (!strcasecmp(val,"btlr")) {
351
numberUpLayout = PDFTOPDF_LAYOUT_BTLR;
352
} else if (!strcasecmp(val,"btrl")) {
353
numberUpLayout = PDFTOPDF_LAYOUT_BTRL;
355
error(-1, const_cast<char *>("Unsupported number-up-layout value %s,"
356
" using number-up-layout=lrtb!\n"), val);
359
if ((val = cupsGetOption("OutputOrder",num_options,options)) != 0) {
360
if (!strcasecmp(val, "Reverse")) {
361
P2PDoc::options.reverse = gTrue;
365
* Figure out the right default output order from the PPD file...
368
if ((choice = ppdFindMarkedChoice(ppd,"OutputOrder")) != 0) {
369
P2PDoc::options.reverse = !strcasecmp(choice->choice,"Reverse");
370
} else if ((choice = ppdFindMarkedChoice(ppd,"OutputBin")) != 0 &&
371
(attr = ppdFindAttr(ppd,"PageStackOrder",choice->choice)) != 0 &&
373
P2PDoc::options.reverse = !strcasecmp(attr->value,"Reverse");
374
} else if ((attr = ppdFindAttr(ppd,"DefaultOutputOrder",0)) != 0 &&
376
P2PDoc::options.reverse = !strcasecmp(attr->value,"Reverse");
379
if ((val = cupsGetOption("page-border",num_options,options)) != 0) {
380
if (!strcasecmp(val,"none")) {
381
pageBorder = PDFTOPDF_BORDERNONE;
382
} else if (!strcasecmp(val,"single")) {
383
pageBorder = PDFTOPDF_BORDERHAIRLINE;
384
} else if (!strcasecmp(val,"single-thick")) {
385
pageBorder = PDFTOPDF_BORDERTHICK;
386
} else if (!strcasecmp(val,"double")) {
387
pageBorder = PDFTOPDF_BORDERDOUBLE | PDFTOPDF_BORDERHAIRLINE;
388
} else if (!strcasecmp(val,"double-thick")) {
389
pageBorder = PDFTOPDF_BORDERDOUBLE | PDFTOPDF_BORDERTHICK;
391
error(-1, const_cast<char *>("Unsupported page-border value %s, using "
392
"page-border=none!\n"), val);
395
P2PDoc::options.pageLabel = cupsGetOption("page-label",num_options,options);
396
P2PDoc::options.pageSet = cupsGetOption("page-set",num_options,options);
397
P2PDoc::options.pageRanges = cupsGetOption("page-ranges",num_options,options);
399
if ((val = cupsGetOption("mirror",num_options,options)) != 0 &&
400
(!strcasecmp(val,"true") || !strcasecmp(val,"on") ||
401
!strcasecmp(val,"yes"))) {
404
if ((val = cupsGetOption("emit-jcl",num_options,options)) != 0 &&
405
(!strcasecmp(val,"false") || !strcasecmp(val,"off") ||
406
!strcasecmp(val,"no") || !strcmp(val,"0"))) {
409
if ((val = cupsGetOption("position",num_options,options)) != 0) {
410
if (strcasecmp(val,"center") == 0) {
413
} else if (strcasecmp(val,"top") == 0) {
416
} else if (strcasecmp(val,"left") == 0) {
419
} else if (strcasecmp(val,"right") == 0) {
422
} else if (strcasecmp(val,"top-left") == 0) {
425
} else if (strcasecmp(val,"top-right") == 0) {
428
} else if (strcasecmp(val,"bottom") == 0) {
431
} else if (strcasecmp(val,"bottom-left") == 0) {
434
} else if (strcasecmp(val,"bottom-right") == 0) {
441
if ((val = cupsGetOption("multiple-document-handling",num_options,options))
443
P2PDoc::options.collate =
444
strcasecmp(val,"separate-documents-uncollated-copies") != 0;
446
if ((val = cupsGetOption("Collate",num_options,options)) != 0) {
447
if (strcasecmp(val,"True") == 0) {
448
P2PDoc::options.collate = gTrue;
451
if ((choice = ppdFindMarkedChoice(ppd,"Collate")) != NULL
452
&& (!strcasecmp(choice->choice,"true")
453
|| !strcasecmp(choice->choice, "on")
454
|| !strcasecmp(choice->choice, "yes"))) {
455
P2PDoc::options.collate = gTrue;
459
if ((val = cupsGetOption("scaling",num_options,options)) != 0) {
460
scaling = atoi(val) * 0.01;
462
} else if (fitplot) {
465
if ((val = cupsGetOption("natural-scaling",num_options,options)) != 0) {
466
naturalScaling = atoi(val) * 0.01;
468
/* adujst to even page when duplex */
469
if (checkFeature("cupsEvenDuplex",num_options,options)) {
470
P2PDoc::options.even = gTrue;
473
/* embedding fonts into output PDF */
474
if (checkFeature("pdftopdfFontEmbedding",num_options,options)) {
475
P2PDoc::options.fontEmbedding = gTrue;
477
/* embedding whole font file into output PDF */
478
if (checkFeature("pdftopdfFontEmbeddingWhole",num_options,options)) {
479
P2PDoc::options.fontEmbeddingWhole = gTrue;
481
/* embedding pre-loaded fonts specified in PPD into output PDF */
482
if (checkFeature("pdftopdfFontEmbeddingPreLoad",num_options,options)) {
483
P2PDoc::options.fontEmbeddingPreLoad = gTrue;
485
/* compressing embedded fonts */
486
if (checkFeature("pdftopdfFontCompress",num_options,options)) {
487
P2PDoc::options.fontCompress = gTrue;
489
/* compressing page contents */
490
if (checkFeature("pdftopdfContentsCompress",num_options,options)) {
491
P2PDoc::options.contentsCompress = gTrue;
494
if (cupsGetOption("pdftopdfAutoRotate",num_options,options) != 0 ||
495
ppdFindAttr(ppd,"pdftopdfAutoRotate",0) != 0) {
496
if (!checkFeature("pdftopdfAutoRotate",num_options,options)) {
497
/* disable auto rotate */
502
/* pre-loaded fonts */
504
P2PDoc::options.numPreFonts = ppd->num_fonts;
505
P2PDoc::options.preFonts = ppd->fonts;
508
if (P2PDoc::options.copies == 1) {
509
/* collate is not needed */
510
P2PDoc::options.collate = gFalse;
511
ppdMarkOption(ppd,"Collate","False");
513
if (!P2PDoc::options.duplex) {
514
/* evenDuplex is not needed */
515
P2PDoc::options.even = gFalse;
518
/* check collate device */
519
if (P2PDoc::options.collate) {
520
if ((choice = ppdFindMarkedChoice(ppd,"Collate")) != NULL &&
521
!strcasecmp(choice->choice,"true")) {
524
if ((opt = ppdFindOption(ppd,"Collate")) != NULL &&
526
deviceCollate = gTrue;
528
ppdMarkOption(ppd,"Collate","False");
532
/* check OutputOrder device */
533
if (P2PDoc::options.reverse) {
534
if (ppdFindOption(ppd,"OutputOrder") != NULL) {
535
deviceReverse = gTrue;
539
!ppd->manual_copies && P2PDoc::options.collate && !deviceCollate) {
540
/* Copying by device , software collate is impossible */
541
/* Enable software copying */
542
ppd->manual_copies = 1;
544
if (P2PDoc::options.copies > 1 && (ppd == NULL || ppd->manual_copies)
545
&& P2PDoc::options.duplex) {
546
/* Enable software collate , or same pages are printed in both sides */
547
P2PDoc::options.collate = gTrue;
549
deviceCollate = gFalse;
550
ppdMarkOption(ppd,"Collate","False");
553
if (P2PDoc::options.duplex && P2PDoc::options.collate && !deviceCollate) {
554
/* Enable evenDuplex or the first page may be printed other side of the
556
P2PDoc::options.even = gTrue;
558
if (P2PDoc::options.duplex && P2PDoc::options.reverse && !deviceReverse) {
559
/* Enable evenDuplex or the first page may be empty. */
560
P2PDoc::options.even = gTrue;
562
/* change feature for software */
564
P2PDoc::options.collate = gFalse;
567
P2PDoc::options.reverse = gFalse;
571
if (ppd->manual_copies) {
572
/* sure disable hardware copying */
573
ppdMarkOption(ppd,"Copies","1");
574
ppdMarkOption(ppd,"JCLCopies","1");
576
/* change for hardware copying */
577
deviceCopies = P2PDoc::options.copies;
578
P2PDoc::options.copies = 1;
583
int main(int argc, char *argv[]) {
586
P2POutputStream *str;
588
setErrorFunction(::myErrorFun);
589
#ifdef GLOBALPARAMS_HAS_A_ARG
590
globalParams = new GlobalParams(0);
592
globalParams = new GlobalParams();
594
parseOpts(argc, argv);
596
PDFRectangle box(pageLeft,pageBottom,pageRight,pageTop);
597
PDFRectangle mediaBox(0,0,pageWidth,pageLength);
608
fd = cupsTempFd(buf,sizeof(buf));
610
error(-1,const_cast<char *>("Can't create temporary file"));
616
/* copy stdin to the tmp file */
617
while ((n = read(0,buf,BUFSIZ)) > 0) {
618
if (write(fd,buf,n) != n) {
619
error(-1,const_cast<char *>("Can't copy stdin to temporary file"));
624
if (lseek(fd,0,SEEK_SET) < 0) {
625
error(-1,const_cast<char *>("Can't rewind temporary file"));
630
if ((fp = fdopen(fd,"rb")) == 0) {
631
error(-1,const_cast<char *>("Can't fdopen temporary file"));
637
str = new FileStream(fp,0,gFalse,0,&obj);
638
doc = new PDFDoc(str);
640
GooString *fileName = new GooString(argv[6]);
641
/* argc == 7 filenmae is specified */
642
doc = new PDFDoc(fileName,NULL,NULL);
649
if (!doc->okToPrintHighRes() && !doc->okToPrint()) {
650
error(-1,const_cast<char *>("Printing is not allowed\n"));
653
p2pdoc = new P2PDoc(doc);
658
if (orientation != 0) {
659
p2pdoc->rotate(orientation);
660
p2pdoc->position(&box,xposition,yposition);
663
if (naturalScaling != 1.0) {
664
p2pdoc->scale(naturalScaling);
665
p2pdoc->position(&box,xposition,yposition);
669
p2pdoc->fit(&box,scaling);
670
p2pdoc->position(&box,xposition,yposition);
673
p2pdoc->nup(numberUp,&box,pageBorder,numberUpLayout,
674
xposition,yposition);
675
} else if (position) {
676
p2pdoc->position(&box,xposition,yposition);
681
if (autoRotate && orientation == 0
682
&& naturalScaling == 1.0 && !fitplot && numberUp == 1 && !position) {
683
/* If no translation is specified, do auto-rotate.
684
* This is for compatibility with pdftops filter.
686
p2pdoc->autoRotate(&mediaBox);
689
/* set all pages's mediaBox to the target page size, but only if a page
690
* size is given on the command line or an option which influences the
691
* printout size is used */
692
if (forcePageSize || orientation != 0 ||
693
naturalScaling != 1.0 || fitplot || numberUp != 1 || position) {
694
p2pdoc->setMediaBox(&mediaBox);
697
if ((P2PDoc::options.collate || deviceCollate)
698
&& p2pdoc->getNumberOfPages() == 1
699
&& !P2PDoc::options.even) {
700
/* collate is not needed, disable it */
701
/* Number of pages is changed by nup and page-ranges,
702
so check this here */
703
deviceCollate = gFalse;
704
P2PDoc::options.collate = gFalse;
705
ppdMarkOption(ppd,"Collate","False");
708
ppdEmit(ppd,stdout,PPD_ORDER_EXIT);
711
ppdEmitJCL(ppd,stdout,P2PDoc::options.jobId,P2PDoc::options.user,
712
P2PDoc::options.title);
713
emitJCLOptions(stdout,deviceCopies);
715
str = new P2POutputStream(stdout); /* PDF start here */
716
p2pdoc->output(str,deviceCopies,deviceCollate);
719
ppdEmitJCLEnd(ppd,stdout);
728
// Check for memory leaks
729
Object::memCheck(stderr);
735
/* replace memory allocation methods for memory check */
737
void * operator new(size_t size)
739
return gmalloc(size);
742
void operator delete(void *p)
747
void * operator new[](size_t size)
749
return gmalloc(size);
752
void operator delete[](void *p)