~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to filter/pdftopdf/pdftopdf.cxx

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2012-07-22 18:57:32 UTC
  • mfrom: (1.1.17)
  • Revision ID: package-import@ubuntu.com-20120722185732-26kkte5p1lth3rt5
Tags: 1.0.20-0bzr1
* New upstream release
   - pdftops: Added another workaround for Kyocera printers: Some
     models get very slow on images which request interpolation,
     so now we remove the image interpolation requests by additional
     PostScript code only inserted for Kyocera printers (LP: #1026974).
   - Made the Poppler-based filters pdftopdf and pdftoopvp build with
     both Poppler 0.18.x and 0.20.x (Upstream bug #1055).
   - Fixes according to Coverity scan results (Upstream bug #1054).
   - Switched build system to autotools. This especially fixes several
     build problems in Gentoo. Also build-tested with CUPS 1.6.0b1.
   - Fixes for compatibility with clang/gcc-4.7.
   - textonly: Filter did not work as a pipe with copies=1 (Upstream bug
     #1032).
   - texttopdf: Avoid trimming the results of FcFontSort(), as this may
     miss some reasonable candidates under certain circumstances. BTW,
     fix passing a non-pointer as a pointer to "result" (Closes: #670055).
   - Corrected documentation. The option for the maximum image rendering
     resolution in pdftops is "pdftops-max-image-resolution", not
     "pdftops-max-image-resolution-default".
* debian/patches/fcfontsort-no-trim.patch: Removed, fixed upstream.
* debian/rules: Updated options for ./configure and make for the new autotools
  build system.
* debian/watch: Switched to bz2 upstream packages.
* debian/rules, debian/copyright, debian/cups-filters.docs: Updated for
  renamed documentation files.
* debian/control, debian/libfontembed1.install,
  debian/libfontembed-dev.install: Added new binary packages for libfontembed.
* debian/copyright: Updated for recent file additions, and rearrangement of
  directories.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (c) 2006-2011, BBR Inc.  All rights reserved.
 
3
 
 
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:
 
11
 
 
12
The above copyright notice and this permission notice shall be included
 
13
in all copies or substantial portions of the Software.
 
14
 
 
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.
 
22
 
 
23
*/
 
24
/*
 
25
 pdftopdf.cc
 
26
 pdf to pdf filter
 
27
*/
 
28
 
 
29
#include <config.h>
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#ifdef HAVE_CPP_POPPLER_VERSION_H
 
33
#include "cpp/poppler-version.h"
 
34
#endif
 
35
#include "goo/GooString.h"
 
36
#include "goo/gmem.h"
 
37
#include "Object.h"
 
38
#include "Stream.h"
 
39
#include "PDFDoc.h"
 
40
#include "P2PDoc.h"
 
41
#include "P2POutputStream.h"
 
42
#include <cups/cups.h>
 
43
#include <cups/ppd.h>
 
44
#include <stdarg.h>
 
45
#include "P2PError.h"
 
46
#include "GlobalParams.h"
 
47
#include "PDFFTrueTypeFont.h"
 
48
#include <ctype.h>
 
49
 
 
50
namespace {
 
51
  int exitCode = 0;
 
52
  GBool fitplot = gFalse;
 
53
  GBool mirror = gFalse;
 
54
  int numberUp = 1;
 
55
  unsigned int numberUpLayout = PDFTOPDF_LAYOUT_LRTB;
 
56
  unsigned int pageBorder = PDFTOPDF_BORDERNONE;
 
57
  double pageLeft = 18.0;
 
58
  double pageRight = 594.0;
 
59
  double pageBottom = 36.0;
 
60
  double pageTop = 756.0;
 
61
  double pageWidth = 612.0;
 
62
  double pageLength = 792.0;
 
63
  GBool emitJCL = gTrue;
 
64
  ppd_file_t *ppd = 0;
 
65
  int xposition = 0;
 
66
  int yposition = 0;
 
67
  GBool position = gFalse;
 
68
  int orientation = 0;
 
69
  double scaling = 1.0;
 
70
  double naturalScaling = 1.0;
 
71
  int deviceCopies = 1;
 
72
  GBool deviceCollate = gFalse;
 
73
  GBool deviceReverse = gFalse;
 
74
  GBool autoRotate = gTrue;
 
75
  GBool forcePageSize = gFalse;
 
76
};
 
77
 
 
78
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
79
void CDECL myErrorFun(void *data, ErrorCategory category,
 
80
    int pos, char *msg)
 
81
{
 
82
  if (pos >= 0) {
 
83
    fprintf(stderr, "ERROR (%d): ", pos);
 
84
  } else {
 
85
    fprintf(stderr, "ERROR: ");
 
86
  }
 
87
  fprintf(stderr, "%s\n",msg);
 
88
  fflush(stderr);
 
89
}
 
90
#else
 
91
void CDECL myErrorFun(int pos, char *msg, va_list args)
 
92
{
 
93
  if (pos >= 0) {
 
94
    fprintf(stderr, "ERROR (%d): ", pos);
 
95
  } else {
 
96
    fprintf(stderr, "ERROR: ");
 
97
  }
 
98
  vfprintf(stderr, msg, args);
 
99
  fprintf(stderr, "\n");
 
100
  fflush(stderr);
 
101
}
 
102
#endif
 
103
 
 
104
GBool checkFeature(const char *feature, int num_options, cups_option_t *options)
 
105
{
 
106
  const char *val;
 
107
  ppd_attr_t *attr;
 
108
 
 
109
  return ((val = cupsGetOption(feature,num_options,options)) != 0 &&
 
110
             (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
 
111
               !strcasecmp(val, "yes"))) ||
 
112
         ((attr = ppdFindAttr(ppd,feature,0)) != 0 &&
 
113
             (!strcasecmp(attr->value, "true")
 
114
               || !strcasecmp(attr->value, "on") ||
 
115
               !strcasecmp(attr->value, "yes")));
 
116
}
 
117
 
 
118
void emitJCLOptions(FILE *fp, int copies)
 
119
{
 
120
  int section;
 
121
  ppd_choice_t **choices;
 
122
  int i;
 
123
  char buf[1024];
 
124
  ppd_attr_t *attr;
 
125
  int pdftoopvp = 0;
 
126
  int datawritten = 0;
 
127
 
 
128
  if (ppd == 0) return;
 
129
  if ((attr = ppdFindAttr(ppd,"pdftopdfJCLBegin",NULL)) != NULL) {
 
130
    int n = strlen(attr->value);
 
131
    pdftoopvp = 1;
 
132
    for (i = 0;i < n;i++) {
 
133
        if (attr->value[i] == '\r' || attr->value[i] == '\n') {
 
134
            /* skip new line */
 
135
            continue;
 
136
        }
 
137
        fputc(attr->value[i],fp);
 
138
        datawritten = 1;
 
139
    }
 
140
  }
 
141
         
 
142
  snprintf(buf,sizeof(buf),"%d",copies);
 
143
  if (ppdFindOption(ppd,"Copies") != NULL) {
 
144
    ppdMarkOption(ppd,"Copies",buf);
 
145
  } else {
 
146
    if ((attr = ppdFindAttr(ppd,"pdftopdfJCLCopies",buf)) != NULL) {
 
147
      fputs(attr->value,fp);
 
148
      datawritten = 1;
 
149
    } else if (pdftoopvp) {
 
150
      fprintf(fp,"Copies=%d;",copies);
 
151
      datawritten = 1;
 
152
    }
 
153
  }
 
154
  for (section = (int)PPD_ORDER_ANY;
 
155
      section <= (int)PPD_ORDER_PROLOG;section++) {
 
156
    int n;
 
157
 
 
158
    n = ppdCollect(ppd,(ppd_section_t)section,&choices);
 
159
    for (i = 0;i < n;i++) {
 
160
      snprintf(buf,sizeof(buf),"pdftopdfJCL%s",
 
161
        ((ppd_option_t *)(choices[i]->option))->keyword);
 
162
      if ((attr = ppdFindAttr(ppd,buf,choices[i]->choice)) != NULL) {
 
163
        fputs(attr->value,fp);
 
164
        datawritten = 1;
 
165
      } else if (pdftoopvp) {
 
166
        fprintf(fp,"%s=%s;",
 
167
          ((ppd_option_t *)(choices[i]->option))->keyword,
 
168
          choices[i]->choice);
 
169
        datawritten = 1;
 
170
      }
 
171
    }
 
172
  }
 
173
  if (datawritten) fputc('\n',fp);
 
174
}
 
175
 
 
176
void parseOpts(int argc, char **argv)
 
177
{
 
178
  int num_options;
 
179
  cups_option_t *options;
 
180
  const char *val;
 
181
  ppd_attr_t *attr;
 
182
  ppd_choice_t *choice;
 
183
  ppd_size_t *pagesize;
 
184
  int intval;
 
185
 
 
186
  if (argc < 6 || argc > 7) {
 
187
    p2pError(-1,const_cast<char *>("%s job-id user title copies options [file]"),
 
188
      argv[0]);
 
189
    exit(1);
 
190
  }
 
191
  P2PDoc::options.jobId = atoi(argv[1]);
 
192
  P2PDoc::options.user = argv[2];
 
193
  P2PDoc::options.title = argv[3];
 
194
  P2PDoc::options.copies = atoi(argv[4]);
 
195
 
 
196
  ppd = ppdOpenFile(getenv("PPD"));
 
197
  ppdMarkDefaults(ppd);
 
198
  options = NULL;
 
199
  num_options = cupsParseOptions(argv[5],0,&options);
 
200
  cupsMarkOptions(ppd,num_options,options);
 
201
  if (P2PDoc::options.copies == 1
 
202
     && (choice = ppdFindMarkedChoice(ppd,"Copies")) != NULL) {
 
203
    P2PDoc::options.copies = atoi(choice->choice);
 
204
  }
 
205
  if (P2PDoc::options.copies == 0) P2PDoc::options.copies = 1;
 
206
  if ((val = cupsGetOption("fitplot", num_options, options)) == NULL) {
 
207
    if ((val = cupsGetOption("fit-to-page", num_options, options)) == NULL) {
 
208
        val = cupsGetOption("ipp-attribute-fidelity", num_options, options);
 
209
    }
 
210
  }
 
211
  if (val && strcasecmp(val, "no") && strcasecmp(val, "off") &&
 
212
      strcasecmp(val, "false"))
 
213
    fitplot = gTrue;
 
214
  if ((pagesize = ppdPageSize(ppd,0)) != 0) {
 
215
    pageWidth = pagesize->width;
 
216
    pageLength = pagesize->length;
 
217
    pageTop = pagesize->top;
 
218
    pageBottom = pagesize->bottom;
 
219
    pageLeft = pagesize->left;
 
220
    pageRight = pagesize->right;
 
221
    forcePageSize = fitplot;
 
222
  }
 
223
  if ((val = cupsGetOption("landscape",num_options,options)) != 0) {
 
224
    if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 &&
 
225
        strcasecmp(val, "false") != 0) {
 
226
      if (ppd && ppd->landscape > 0) {
 
227
        orientation = 1;
 
228
      } else {
 
229
        orientation = 3;
 
230
      }
 
231
    }
 
232
  } else if ((val =
 
233
     cupsGetOption("orientation-requested",num_options,options)) != 0) {
 
234
   /*
 
235
    * Map IPP orientation values to 0 to 3:
 
236
    *
 
237
    *   3 = 0 degrees   = 0
 
238
    *   4 = 90 degrees  = 1
 
239
    *   5 = -90 degrees = 3
 
240
    *   6 = 180 degrees = 2
 
241
    */
 
242
 
 
243
    orientation = atoi(val) - 3;
 
244
    if (orientation >= 2) {
 
245
      orientation ^= 1;
 
246
    }
 
247
  }
 
248
  if ((val = cupsGetOption("page-left",num_options,options)) != 0) {
 
249
    switch (orientation & 3) {
 
250
      case 0 :
 
251
          pageLeft = (float)atof(val);
 
252
          break;
 
253
      case 1 :
 
254
          pageBottom = (float)atof(val);
 
255
          break;
 
256
      case 2 :
 
257
          pageRight = pageWidth - (float)atof(val);
 
258
          break;
 
259
      case 3 :
 
260
          pageTop = pageLength - (float)atof(val);
 
261
          break;
 
262
    }
 
263
  }
 
264
  if ((val = cupsGetOption("page-right",num_options,options)) != 0) {
 
265
    switch (orientation & 3) {
 
266
      case 0 :
 
267
          pageRight = pageWidth - (float)atof(val);
 
268
          break;
 
269
      case 1 :
 
270
          pageTop = pageLength - (float)atof(val);
 
271
          break;
 
272
      case 2 :
 
273
          pageLeft = (float)atof(val);
 
274
          break;
 
275
      case 3 :
 
276
          pageBottom = (float)atof(val);
 
277
          break;
 
278
    }
 
279
  }
 
280
  if ((val = cupsGetOption("page-bottom",num_options,options)) != 0) {
 
281
    switch (orientation & 3) {
 
282
      case 0 :
 
283
          pageBottom = (float)atof(val);
 
284
          break;
 
285
      case 1 :
 
286
          pageLeft = (float)atof(val);
 
287
          break;
 
288
      case 2 :
 
289
          pageTop = pageLength - (float)atof(val);
 
290
          break;
 
291
      case 3 :
 
292
          pageRight = pageWidth - (float)atof(val);
 
293
          break;
 
294
    }
 
295
  }
 
296
  if ((val = cupsGetOption("page-top",num_options,options)) != 0) {
 
297
    switch (orientation & 3) {
 
298
      case 0 :
 
299
          pageTop = pageLength - (float)atof(val);
 
300
          break;
 
301
      case 1 :
 
302
          pageRight = pageWidth - (float)atof(val);
 
303
          break;
 
304
      case 2 :
 
305
          pageBottom = (float)atof(val);
 
306
          break;
 
307
      case 3 :
 
308
          pageLeft = (float)atof(val);
 
309
          break;
 
310
    }
 
311
  }
 
312
  if (ppdIsMarked(ppd,"Duplex","DuplexNoTumble") ||
 
313
      ppdIsMarked(ppd,"Duplex","DuplexTumble") ||
 
314
      ppdIsMarked(ppd,"JCLDuplex","DuplexNoTumble") ||
 
315
      ppdIsMarked(ppd,"JCLDuplex","DuplexTumble") ||
 
316
      ppdIsMarked(ppd,"EFDuplex","DuplexNoTumble") ||
 
317
      ppdIsMarked(ppd,"EFDuplex","DuplexTumble") ||
 
318
      ppdIsMarked(ppd,"KD03Duplex","DuplexNoTumble") ||
 
319
      ppdIsMarked(ppd,"KD03Duplex","DuplexTumble")) {
 
320
      P2PDoc::options.duplex = gTrue;
 
321
  } else if ((val = cupsGetOption("Duplex",num_options,options)) != 0 &&
 
322
      (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
 
323
       !strcasecmp(val, "yes"))) {
 
324
      /* for compatiblity */
 
325
      if (ppdFindOption(ppd,"Duplex") != NULL) {
 
326
        ppdMarkOption(ppd,"Duplex","True");
 
327
        ppdMarkOption(ppd,"Duplex","On");
 
328
        P2PDoc::options.duplex = gTrue;
 
329
      }
 
330
  } else if ((val = cupsGetOption("sides",num_options,options)) != 0 &&
 
331
      (!strcasecmp(val, "two-sided-long-edge") ||
 
332
       !strcasecmp(val, "two-sided-short-edge"))) {
 
333
      /* for compatiblity */
 
334
      if (ppdFindOption(ppd,"Duplex") != NULL) {
 
335
        ppdMarkOption(ppd,"Duplex","True");
 
336
        ppdMarkOption(ppd,"Duplex","On");
 
337
        P2PDoc::options.duplex = gTrue;
 
338
      }
 
339
  }
 
340
 
 
341
  if ((val = cupsGetOption("number-up",num_options,options)) != 0) {
 
342
    switch (intval = atoi(val)) {
 
343
      case 1 :
 
344
      case 2 :
 
345
      case 4 :
 
346
      case 6 :
 
347
      case 8 :
 
348
      case 9 :
 
349
      case 16 :
 
350
          numberUp = intval;
 
351
          break;
 
352
      default :
 
353
          p2pError(-1,
 
354
                  const_cast<char *>("Unsupported number-up value %d, using number-up=1!\n"),
 
355
                  intval);
 
356
          break;
 
357
    }
 
358
  }
 
359
  if ((val = cupsGetOption("number-up-layout",num_options,options)) != 0) {
 
360
    if (!strcasecmp(val,"lrtb")) {
 
361
      numberUpLayout = PDFTOPDF_LAYOUT_LRTB;
 
362
    } else if (!strcasecmp(val,"lrbt")) {
 
363
      numberUpLayout = PDFTOPDF_LAYOUT_LRBT;
 
364
    } else if (!strcasecmp(val,"rltb")) {
 
365
      numberUpLayout = PDFTOPDF_LAYOUT_RLTB;
 
366
    } else if (!strcasecmp(val,"rlbt")) {
 
367
      numberUpLayout = PDFTOPDF_LAYOUT_RLBT;
 
368
    } else if (!strcasecmp(val,"tblr")) {
 
369
      numberUpLayout = PDFTOPDF_LAYOUT_TBLR;
 
370
    } else if (!strcasecmp(val,"tbrl")) {
 
371
      numberUpLayout = PDFTOPDF_LAYOUT_TBRL;
 
372
    } else if (!strcasecmp(val,"btlr")) {
 
373
      numberUpLayout = PDFTOPDF_LAYOUT_BTLR;
 
374
    } else if (!strcasecmp(val,"btrl")) {
 
375
      numberUpLayout = PDFTOPDF_LAYOUT_BTRL;
 
376
    } else {
 
377
      p2pError(-1, const_cast<char *>("Unsupported number-up-layout value %s,"
 
378
              " using number-up-layout=lrtb!\n"), val);
 
379
    }
 
380
  }
 
381
  if ((val = cupsGetOption("OutputOrder",num_options,options)) != 0) {
 
382
    if (!strcasecmp(val, "Reverse")) {
 
383
      P2PDoc::options.reverse = gTrue;
 
384
    }
 
385
  } else if (ppd) {
 
386
   /*
 
387
    * Figure out the right default output order from the PPD file...
 
388
    */
 
389
 
 
390
    if ((choice = ppdFindMarkedChoice(ppd,"OutputOrder")) != 0) {
 
391
      P2PDoc::options.reverse = !strcasecmp(choice->choice,"Reverse");
 
392
    } else if ((choice = ppdFindMarkedChoice(ppd,"OutputBin")) != 0 &&
 
393
        (attr = ppdFindAttr(ppd,"PageStackOrder",choice->choice)) != 0 &&
 
394
        attr->value) {
 
395
      P2PDoc::options.reverse = !strcasecmp(attr->value,"Reverse");
 
396
    } else if ((attr = ppdFindAttr(ppd,"DefaultOutputOrder",0)) != 0 &&
 
397
             attr->value) {
 
398
      P2PDoc::options.reverse = !strcasecmp(attr->value,"Reverse");
 
399
    }
 
400
  }
 
401
  if ((val = cupsGetOption("page-border",num_options,options)) != 0) {
 
402
    if (!strcasecmp(val,"none")) {
 
403
      pageBorder = PDFTOPDF_BORDERNONE;
 
404
    } else if (!strcasecmp(val,"single")) {
 
405
      pageBorder = PDFTOPDF_BORDERHAIRLINE;
 
406
    } else if (!strcasecmp(val,"single-thick")) {
 
407
      pageBorder = PDFTOPDF_BORDERTHICK;
 
408
    } else if (!strcasecmp(val,"double")) {
 
409
      pageBorder = PDFTOPDF_BORDERDOUBLE | PDFTOPDF_BORDERHAIRLINE;
 
410
    } else if (!strcasecmp(val,"double-thick")) {
 
411
      pageBorder = PDFTOPDF_BORDERDOUBLE | PDFTOPDF_BORDERTHICK;
 
412
    } else {
 
413
      p2pError(-1, const_cast<char *>("Unsupported page-border value %s, using "
 
414
                      "page-border=none!\n"), val);
 
415
    }
 
416
  }
 
417
  P2PDoc::options.pageLabel = cupsGetOption("page-label",num_options,options);
 
418
  P2PDoc::options.pageSet = cupsGetOption("page-set",num_options,options);
 
419
  P2PDoc::options.pageRanges = cupsGetOption("page-ranges",num_options,options);
 
420
 
 
421
  if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL) {
 
422
    val = choice->choice;
 
423
    choice->marked =0;
 
424
    if (val && (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
 
425
                    !strcasecmp(val, "yes"))) {
 
426
      mirror = gTrue;
 
427
    }
 
428
  } else if ((val = cupsGetOption("mirror",num_options,options)) != 0 &&
 
429
      (!strcasecmp(val,"true") || !strcasecmp(val,"on") ||
 
430
       !strcasecmp(val,"yes"))) {
 
431
    mirror = gTrue;
 
432
  }
 
433
  if ((val = cupsGetOption("emit-jcl",num_options,options)) != 0 &&
 
434
      (!strcasecmp(val,"false") || !strcasecmp(val,"off") ||
 
435
       !strcasecmp(val,"no") || !strcmp(val,"0"))) {
 
436
    emitJCL = gFalse;
 
437
  }
 
438
  if ((val = cupsGetOption("position",num_options,options)) != 0) {
 
439
    if (strcasecmp(val,"center") == 0) {
 
440
      xposition = 0;
 
441
      yposition = 0;
 
442
    } else if (strcasecmp(val,"top") == 0) {
 
443
      xposition = 0;
 
444
      yposition = 1;
 
445
    } else if (strcasecmp(val,"left") == 0) {
 
446
      xposition = -1;
 
447
      yposition = 0;
 
448
    } else if (strcasecmp(val,"right") == 0) {
 
449
      xposition = 1;
 
450
      yposition = 0;
 
451
    } else if (strcasecmp(val,"top-left") == 0) {
 
452
      xposition = -1;
 
453
      yposition = 1;
 
454
    } else if (strcasecmp(val,"top-right") == 0) {
 
455
      xposition = 1;
 
456
      yposition = 1;
 
457
    } else if (strcasecmp(val,"bottom") == 0) {
 
458
      xposition = 0;
 
459
      yposition = -1;
 
460
    } else if (strcasecmp(val,"bottom-left") == 0) {
 
461
      xposition = -1;
 
462
      yposition = -1;
 
463
    } else if (strcasecmp(val,"bottom-right") == 0) {
 
464
      xposition = 1;
 
465
      yposition = -1;
 
466
    }
 
467
    position = gTrue;
 
468
  }
 
469
 
 
470
  if ((val = cupsGetOption("multiple-document-handling",num_options,options)) 
 
471
      != 0) {
 
472
    P2PDoc::options.collate =
 
473
      strcasecmp(val,"separate-documents-uncollated-copies") != 0;
 
474
  }
 
475
  if ((val = cupsGetOption("Collate",num_options,options)) != 0) {
 
476
    if (strcasecmp(val,"True") == 0) {
 
477
      P2PDoc::options.collate = gTrue;
 
478
    }
 
479
  } else {
 
480
    if ((choice = ppdFindMarkedChoice(ppd,"Collate")) != NULL
 
481
      && (!strcasecmp(choice->choice,"true")
 
482
        || !strcasecmp(choice->choice, "on")
 
483
        || !strcasecmp(choice->choice, "yes"))) {
 
484
      P2PDoc::options.collate = gTrue;
 
485
    }
 
486
  }
 
487
 
 
488
  if ((val = cupsGetOption("scaling",num_options,options)) != 0) {
 
489
    scaling = atoi(val) * 0.01;
 
490
    fitplot = gTrue;
 
491
  } else if (fitplot) {
 
492
    scaling = 1.0;
 
493
  }
 
494
  if ((val = cupsGetOption("natural-scaling",num_options,options)) != 0) {
 
495
    naturalScaling = atoi(val) * 0.01;
 
496
  }
 
497
  /* adujst to even page when duplex */
 
498
  if (checkFeature("cupsEvenDuplex",num_options,options)) {
 
499
    P2PDoc::options.even = gTrue;
 
500
  }
 
501
 
 
502
  /* embedding fonts into output PDF */
 
503
  if (checkFeature("pdftopdfFontEmbedding",num_options,options)) {
 
504
    P2PDoc::options.fontEmbedding = gTrue;
 
505
  }
 
506
  /* embedding whole font file into output PDF */
 
507
  if (checkFeature("pdftopdfFontEmbeddingWhole",num_options,options)) {
 
508
    P2PDoc::options.fontEmbeddingWhole = gTrue;
 
509
  }
 
510
  /* embedding pre-loaded fonts specified in PPD into output PDF */
 
511
  if (checkFeature("pdftopdfFontEmbeddingPreLoad",num_options,options)) {
 
512
    P2PDoc::options.fontEmbeddingPreLoad = gTrue;
 
513
  }
 
514
  /* compressing embedded fonts */
 
515
  if (checkFeature("pdftopdfFontCompress",num_options,options)) {
 
516
    P2PDoc::options.fontCompress = gTrue;
 
517
  }
 
518
  /* compressing page contents */
 
519
  if (checkFeature("pdftopdfContentsCompress",num_options,options)) {
 
520
    P2PDoc::options.contentsCompress = gTrue;
 
521
  }
 
522
  /* auto rotate */
 
523
  if (cupsGetOption("pdftopdfAutoRotate",num_options,options) != 0 ||
 
524
         ppdFindAttr(ppd,"pdftopdfAutoRotate",0) != 0) {
 
525
      if (!checkFeature("pdftopdfAutoRotate",num_options,options)) {
 
526
        /* disable auto rotate */
 
527
        autoRotate = gFalse;
 
528
      }
 
529
  }
 
530
 
 
531
  /* pre-loaded fonts */
 
532
  if (ppd != 0) {
 
533
    P2PDoc::options.numPreFonts = ppd->num_fonts;
 
534
    P2PDoc::options.preFonts = ppd->fonts;
 
535
  }
 
536
 
 
537
  if (P2PDoc::options.copies == 1) {
 
538
    /* collate is not needed */
 
539
    P2PDoc::options.collate = gFalse;
 
540
    ppdMarkOption(ppd,"Collate","False");
 
541
  }
 
542
  if (!P2PDoc::options.duplex) {
 
543
    /* evenDuplex is not needed */
 
544
    P2PDoc::options.even = gFalse;
 
545
  }
 
546
 
 
547
  /* check collate device */
 
548
  if (P2PDoc::options.collate && !ppd->manual_copies) {
 
549
    if ((choice = ppdFindMarkedChoice(ppd,"Collate")) != NULL &&
 
550
       !strcasecmp(choice->choice,"true")) {
 
551
      ppd_option_t *opt;
 
552
 
 
553
      if ((opt = ppdFindOption(ppd,"Collate")) != NULL &&
 
554
        !opt->conflicted) {
 
555
        deviceCollate = gTrue;
 
556
      } else {
 
557
        ppdMarkOption(ppd,"Collate","False");
 
558
      }
 
559
    }
 
560
  }
 
561
  /* check OutputOrder device */
 
562
  if (P2PDoc::options.reverse) {
 
563
    if (ppdFindOption(ppd,"OutputOrder") != NULL) {
 
564
      deviceReverse = gTrue;
 
565
    }
 
566
  }
 
567
  if (ppd != NULL &&
 
568
       !ppd->manual_copies && P2PDoc::options.collate && !deviceCollate) {
 
569
    /* Copying by device , software collate is impossible */
 
570
    /* Enable software copying */
 
571
    ppd->manual_copies = 1;
 
572
  }
 
573
  if (P2PDoc::options.copies > 1 && (ppd == NULL || ppd->manual_copies)
 
574
      && P2PDoc::options.duplex) {
 
575
    /* Enable software collate , or same pages are printed in both sides */
 
576
      P2PDoc::options.collate = gTrue;
 
577
      if (deviceCollate) {
 
578
        deviceCollate = gFalse;
 
579
        ppdMarkOption(ppd,"Collate","False");
 
580
      }
 
581
  }
 
582
  if (P2PDoc::options.duplex && P2PDoc::options.collate && !deviceCollate) {
 
583
    /* Enable evenDuplex or the first page may be printed other side of the
 
584
      end of precedings */
 
585
    P2PDoc::options.even = gTrue;
 
586
  }
 
587
  if (P2PDoc::options.duplex && P2PDoc::options.reverse && !deviceReverse) {
 
588
    /* Enable evenDuplex or the first page may be empty. */
 
589
    P2PDoc::options.even = gTrue;
 
590
  }
 
591
  /* change feature for software */
 
592
  if (deviceCollate) {
 
593
    P2PDoc::options.collate = gFalse;
 
594
  }
 
595
  if (deviceReverse) {
 
596
    P2PDoc::options.reverse = gFalse;
 
597
  }
 
598
 
 
599
  if (ppd != NULL) {
 
600
    if (ppd->manual_copies) {
 
601
      /* sure disable hardware copying */
 
602
      ppdMarkOption(ppd,"Copies","1");
 
603
      ppdMarkOption(ppd,"JCLCopies","1");
 
604
    } else {
 
605
      /* change for hardware copying */
 
606
      deviceCopies = P2PDoc::options.copies;
 
607
      P2PDoc::options.copies = 1;
 
608
    }
 
609
  }
 
610
}
 
611
 
 
612
 
 
613
/* Copied ppd_decode() from CUPS which is not exported to the API */
 
614
 
 
615
static int                              /* O - Length of decoded string */
 
616
ppd_decode(char *string)                /* I - String to decode */
 
617
{
 
618
  char  *inptr,                         /* Input pointer */
 
619
        *outptr;                        /* Output pointer */
 
620
 
 
621
 
 
622
  inptr  = string;
 
623
  outptr = string;
 
624
 
 
625
  while (*inptr != '\0')
 
626
    if (*inptr == '<' && isxdigit(inptr[1] & 255))
 
627
    {
 
628
     /*
 
629
      * Convert hex to 8-bit values...
 
630
      */
 
631
 
 
632
      inptr ++;
 
633
      while (isxdigit(*inptr & 255))
 
634
      {
 
635
        if (isalpha(*inptr))
 
636
          *outptr = (tolower(*inptr) - 'a' + 10) << 4;
 
637
        else
 
638
          *outptr = (*inptr - '0') << 4;
 
639
 
 
640
        inptr ++;
 
641
 
 
642
        if (!isxdigit(*inptr & 255))
 
643
          break;
 
644
 
 
645
        if (isalpha(*inptr))
 
646
          *outptr |= tolower(*inptr) - 'a' + 10;
 
647
        else
 
648
          *outptr |= *inptr - '0';
 
649
 
 
650
        inptr ++;
 
651
        outptr ++;
 
652
      }
 
653
 
 
654
      while (*inptr != '>' && *inptr != '\0')
 
655
        inptr ++;
 
656
      while (*inptr == '>')
 
657
        inptr ++;
 
658
    }
 
659
    else
 
660
      *outptr++ = *inptr++;
 
661
 
 
662
  *outptr = '\0';
 
663
 
 
664
  return ((int)(outptr - string));
 
665
}
 
666
 
 
667
int main(int argc, char *argv[]) {
 
668
  PDFDoc *doc;
 
669
  P2PDoc *p2pdoc;
 
670
  P2POutputStream *str;
 
671
 
 
672
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
673
  setErrorCallback(::myErrorFun,NULL);
 
674
#else
 
675
  setErrorFunction(::myErrorFun);
 
676
#endif
 
677
  globalParams = new GlobalParams();
 
678
  parseOpts(argc, argv);
 
679
 
 
680
  PDFRectangle box(pageLeft,pageBottom,pageRight,pageTop);
 
681
  PDFRectangle mediaBox(0,0,pageWidth,pageLength);
 
682
 
 
683
  if (argc == 6) {
 
684
    /* stdin */
 
685
    int fd;
 
686
    Object obj;
 
687
    BaseStream *str;
 
688
    FILE *fp;
 
689
    char buf[BUFSIZ];
 
690
    int n;
 
691
 
 
692
    fd = cupsTempFd(buf,sizeof(buf));
 
693
    if (fd < 0) {
 
694
      p2pError(-1,const_cast<char *>("Can't create temporary file"));
 
695
      exit(1);
 
696
    }
 
697
    /* remove name */
 
698
    unlink(buf);
 
699
 
 
700
    /* copy stdin to the tmp file */
 
701
    while ((n = read(0,buf,BUFSIZ)) > 0) {
 
702
      if (write(fd,buf,n) != n) {
 
703
        p2pError(-1,const_cast<char *>("Can't copy stdin to temporary file"));
 
704
        close(fd);
 
705
        exit(1);
 
706
      }
 
707
    }
 
708
    if (lseek(fd,0,SEEK_SET) < 0) {
 
709
        p2pError(-1,const_cast<char *>("Can't rewind temporary file"));
 
710
        close(fd);
 
711
        exit(1);
 
712
    }
 
713
 
 
714
    if ((fp = fdopen(fd,"rb")) == 0) {
 
715
        p2pError(-1,const_cast<char *>("Can't fdopen temporary file"));
 
716
        close(fd);
 
717
        exit(1);
 
718
    }
 
719
 
 
720
    obj.initNull();
 
721
    str = new FileStream(fp,0,gFalse,0,&obj);
 
722
    doc = new PDFDoc(str);
 
723
  } else {
 
724
    GooString *fileName = new GooString(argv[6]);
 
725
    /* argc == 7 filenmae is specified */
 
726
    doc = new PDFDoc(fileName,NULL,NULL);
 
727
  }
 
728
 
 
729
  if (!doc->isOk()) {
 
730
    exitCode = 1;
 
731
    goto err1;
 
732
  }
 
733
  if (!doc->okToPrintHighRes() && !doc->okToPrint()) {
 
734
    p2pError(-1,const_cast<char *>("Printing is not allowed\n"));
 
735
    exit(1);
 
736
  }
 
737
  p2pdoc = new P2PDoc(doc);
 
738
  if (mirror) {
 
739
    p2pdoc->mirror();
 
740
  }
 
741
 
 
742
  if (orientation != 0) {
 
743
    p2pdoc->rotate(orientation);
 
744
    p2pdoc->position(&box,xposition,yposition);
 
745
  }
 
746
 
 
747
  if (naturalScaling != 1.0) {
 
748
    p2pdoc->scale(naturalScaling);
 
749
    p2pdoc->position(&box,xposition,yposition);
 
750
  }
 
751
 
 
752
  if (fitplot) {
 
753
    p2pdoc->fit(&box,scaling);
 
754
    p2pdoc->position(&box,xposition,yposition);
 
755
  }
 
756
  if (numberUp != 1) {
 
757
    p2pdoc->nup(numberUp,&box,pageBorder,numberUpLayout,
 
758
      xposition,yposition);
 
759
  } else if (position) {
 
760
    p2pdoc->position(&box,xposition,yposition);
 
761
  }
 
762
 
 
763
  p2pdoc->select();
 
764
 
 
765
  if (autoRotate && orientation == 0
 
766
     && naturalScaling == 1.0 && !fitplot && numberUp == 1 && !position) {
 
767
    /* If no translation is specified, do auto-rotate.
 
768
     * This is for compatibility with pdftops filter.
 
769
     */
 
770
    p2pdoc->autoRotate(&mediaBox);
 
771
  }
 
772
 
 
773
  /* set all pages's mediaBox to the target page size, but only if a page
 
774
   * size is given on the command line or an option which influences the
 
775
   * printout size is used */
 
776
  if (forcePageSize || orientation != 0 ||
 
777
      naturalScaling != 1.0 || fitplot || numberUp != 1 || position) {
 
778
    p2pdoc->setMediaBox(&mediaBox);
 
779
  }
 
780
 
 
781
  if ((P2PDoc::options.collate || deviceCollate)
 
782
      && p2pdoc->getNumberOfPages() == 1
 
783
      && !P2PDoc::options.even) {
 
784
    /* collate is not needed, disable it */
 
785
    /* Number of pages is changed by nup and page-ranges,
 
786
        so check this here */
 
787
    deviceCollate = gFalse;
 
788
    P2PDoc::options.collate = gFalse;
 
789
    ppdMarkOption(ppd,"Collate","False");
 
790
  }
 
791
 
 
792
  ppdEmit(ppd,stdout,PPD_ORDER_EXIT);
 
793
 
 
794
  if (ppd != NULL && emitJCL) {
 
795
    /* pdftopdf only adds JCL to the job if the printer is a native PDF
 
796
       printer and the PPD is for this mode, having the "*JCLToPDFInterpreter:"
 
797
       keyword. We need to read this keyword manually from the PPD and replace
 
798
       the content of ppd->jcl_ps by the value of this keyword, so that
 
799
       ppdEmitJCL() actalually adds JCL based on the presence on 
 
800
       "*JCLToPDFInterpreter:". */
 
801
    ppd_attr_t *attr;
 
802
    if ((attr = ppdFindAttr(ppd,"JCLToPDFInterpreter",NULL)) != NULL) {
 
803
      ppd->jcl_ps = strdup(attr->value);
 
804
      ppd_decode(ppd->jcl_ps);
 
805
      P2PDoc::options.pdfPrinter = gTrue;
 
806
    } else {
 
807
      ppd->jcl_ps = NULL;
 
808
      P2PDoc::options.pdfPrinter = gFalse;
 
809
    }
 
810
    ppdEmitJCL(ppd,stdout,P2PDoc::options.jobId,P2PDoc::options.user,
 
811
      P2PDoc::options.title);
 
812
    emitJCLOptions(stdout,deviceCopies);
 
813
  }
 
814
  str = new P2POutputStream(stdout); /* PDF start here */
 
815
  p2pdoc->output(str,deviceCopies,deviceCollate);
 
816
#ifndef CUPS_1_1
 
817
  if (emitJCL) {
 
818
    ppdEmitJCLEnd(ppd,stdout);
 
819
  }
 
820
#endif
 
821
 
 
822
  delete str;
 
823
  delete p2pdoc;
 
824
err1:
 
825
  delete doc;
 
826
 
 
827
  // Check for memory leaks
 
828
  Object::memCheck(stderr);
 
829
  gMemReport(stderr);
 
830
 
 
831
  return exitCode;
 
832
}
 
833
 
 
834
/* replace memory allocation methods for memory check */
 
835
 
 
836
void * operator new(size_t size) throw(std::bad_alloc)
 
837
{
 
838
  return gmalloc(size);
 
839
}
 
840
 
 
841
void operator delete(void *p) throw()
 
842
{
 
843
  gfree(p);
 
844
}
 
845
 
 
846
void * operator new[](size_t size) throw(std::bad_alloc)
 
847
{
 
848
  return gmalloc(size);
 
849
}
 
850
 
 
851
void operator delete[](void *p) throw()
 
852
{
 
853
  gfree(p);
 
854
}