1 //========================================================================
2 //
3 // pdftops.cc
4 //
5 // Copyright 1996-2003 Glyph & Cog, LLC
6 //
7 // Modified for Debian by Hamish Moffatt, 22 May 2002.
8 //
9 //========================================================================
10 
11 //========================================================================
12 //
13 // Modified under the Poppler project - http://poppler.freedesktop.org
14 //
15 // All changes made under the Poppler project to this file are licensed
16 // under GPL version 2 or later
17 //
18 // Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
19 // Copyright (C) 2007-2008, 2010 Albert Astals Cid <aacid@kde.org>
20 // Copyright (C) 2009 Till Kamppeter <till.kamppeter@gmail.com>
21 // Copyright (C) 2009 Sanjoy Mahajan <sanjoy@mit.edu>
22 // Copyright (C) 2009 William Bader <williambader@hotmail.com>
23 // Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
24 //
25 // To see a description of the changes please see the Changelog file that
26 // came with your tarball or type make ChangeLog if you are building from git
27 //
28 //========================================================================
29 
30 #include "config.h"
31 #include <poppler-config.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stddef.h>
35 #include <string.h>
36 #include "parseargs.h"
37 #include "goo/GooString.h"
38 #include "goo/gmem.h"
39 #include "GlobalParams.h"
40 #include "Object.h"
41 #include "Stream.h"
42 #include "Array.h"
43 #include "Dict.h"
44 #include "XRef.h"
45 #include "Catalog.h"
46 #include "Page.h"
47 #include "PDFDoc.h"
48 #include "PDFDocFactory.h"
49 #include "PSOutputDev.h"
50 #include "Error.h"
51 
setPSPaperSize(char * size,int & psPaperWidth,int & psPaperHeight)52 static GBool setPSPaperSize(char *size, int &psPaperWidth, int &psPaperHeight) {
53   if (!strcmp(size, "match")) {
54     psPaperWidth = psPaperHeight = -1;
55   } else if (!strcmp(size, "letter")) {
56     psPaperWidth = 612;
57     psPaperHeight = 792;
58   } else if (!strcmp(size, "legal")) {
59     psPaperWidth = 612;
60     psPaperHeight = 1008;
61   } else if (!strcmp(size, "A4")) {
62     psPaperWidth = 595;
63     psPaperHeight = 842;
64   } else if (!strcmp(size, "A3")) {
65     psPaperWidth = 842;
66     psPaperHeight = 1190;
67   } else {
68     return gFalse;
69   }
70   return gTrue;
71 }
72 
73 
74 static int firstPage = 1;
75 static int lastPage = 0;
76 static GBool level1 = gFalse;
77 static GBool level1Sep = gFalse;
78 static GBool level2 = gFalse;
79 static GBool level2Sep = gFalse;
80 static GBool level3 = gFalse;
81 static GBool level3Sep = gFalse;
82 static GBool doOrigPageSizes = gFalse;
83 static GBool doEPS = gFalse;
84 static GBool doForm = gFalse;
85 #if OPI_SUPPORT
86 static GBool doOPI = gFalse;
87 #endif
88 static GBool noEmbedT1Fonts = gFalse;
89 static GBool noEmbedTTFonts = gFalse;
90 static GBool noEmbedCIDPSFonts = gFalse;
91 static GBool noEmbedCIDTTFonts = gFalse;
92 static GBool noSubstFonts = gFalse;
93 static GBool preload = gFalse;
94 static char paperSize[15] = "";
95 static int paperWidth = -1;
96 static int paperHeight = -1;
97 static GBool noCrop = gFalse;
98 static GBool expand = gFalse;
99 static GBool noShrink = gFalse;
100 static GBool noCenter = gFalse;
101 static GBool duplex = gFalse;
102 static char ownerPassword[33] = "\001";
103 static char userPassword[33] = "\001";
104 static GBool quiet = gFalse;
105 static GBool printVersion = gFalse;
106 static GBool printHelp = gFalse;
107 
108 static const ArgDesc argDesc[] = {
109   {"-f",          argInt,      &firstPage,      0,
110    "first page to print"},
111   {"-l",          argInt,      &lastPage,       0,
112    "last page to print"},
113   {"-level1",     argFlag,     &level1,         0,
114    "generate Level 1 PostScript"},
115   {"-level1sep",  argFlag,     &level1Sep,      0,
116    "generate Level 1 separable PostScript"},
117   {"-level2",     argFlag,     &level2,         0,
118    "generate Level 2 PostScript"},
119   {"-level2sep",  argFlag,     &level2Sep,      0,
120    "generate Level 2 separable PostScript"},
121   {"-level3",     argFlag,     &level3,         0,
122    "generate Level 3 PostScript"},
123   {"-level3sep",  argFlag,     &level3Sep,      0,
124    "generate Level 3 separable PostScript"},
125   {"-origpagesizes",argFlag,   &doOrigPageSizes,0,
126    "conserve original page sizes"},
127   {"-eps",        argFlag,     &doEPS,          0,
128    "generate Encapsulated PostScript (EPS)"},
129   {"-form",       argFlag,     &doForm,         0,
130    "generate a PostScript form"},
131 #if OPI_SUPPORT
132   {"-opi",        argFlag,     &doOPI,          0,
133    "generate OPI comments"},
134 #endif
135   {"-noembt1",    argFlag,     &noEmbedT1Fonts, 0,
136    "don't embed Type 1 fonts"},
137   {"-noembtt",    argFlag,     &noEmbedTTFonts, 0,
138    "don't embed TrueType fonts"},
139   {"-noembcidps", argFlag,     &noEmbedCIDPSFonts, 0,
140    "don't embed CID PostScript fonts"},
141   {"-noembcidtt", argFlag, &noEmbedCIDTTFonts,  0,
142    "don't embed CID TrueType fonts"},
143   {"-passfonts",  argFlag,        &noSubstFonts,0,
144    "don't substitute missing fonts"},
145   {"-preload",    argFlag,     &preload,        0,
146    "preload images and forms"},
147   {"-paper",      argString,   paperSize,       sizeof(paperSize),
148    "paper size (letter, legal, A4, A3, match)"},
149   {"-paperw",     argInt,      &paperWidth,     0,
150    "paper width, in points"},
151   {"-paperh",     argInt,      &paperHeight,    0,
152    "paper height, in points"},
153   {"-nocrop",     argFlag,     &noCrop,         0,
154    "don't crop pages to CropBox"},
155   {"-expand",     argFlag,     &expand,         0,
156    "expand pages smaller than the paper size"},
157   {"-noshrink",   argFlag,     &noShrink,       0,
158    "don't shrink pages larger than the paper size"},
159   {"-nocenter",   argFlag,     &noCenter,       0,
160    "don't center pages smaller than the paper size"},
161   {"-duplex",     argFlag,     &duplex,         0,
162    "enable duplex printing"},
163   {"-opw",        argString,   ownerPassword,   sizeof(ownerPassword),
164    "owner password (for encrypted files)"},
165   {"-upw",        argString,   userPassword,    sizeof(userPassword),
166    "user password (for encrypted files)"},
167   {"-q",          argFlag,     &quiet,          0,
168    "don't print any messages or errors"},
169   {"-v",          argFlag,     &printVersion,   0,
170    "print copyright and version info"},
171   {"-h",          argFlag,     &printHelp,      0,
172    "print usage information"},
173   {"-help",       argFlag,     &printHelp,      0,
174    "print usage information"},
175   {"--help",      argFlag,     &printHelp,      0,
176    "print usage information"},
177   {"-?",          argFlag,     &printHelp,      0,
178    "print usage information"},
179   {NULL}
180 };
181 
main(int argc,char * argv[])182 int main(int argc, char *argv[]) {
183   PDFDoc *doc;
184   GooString *fileName;
185   GooString *psFileName;
186   PSLevel level;
187   PSOutMode mode;
188   GooString *ownerPW, *userPW;
189   PSOutputDev *psOut;
190   GBool ok;
191   char *p;
192   int exitCode;
193 
194   exitCode = 99;
195 
196   // parse args
197   ok = parseArgs(argDesc, &argc, argv);
198   if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) {
199     fprintf(stderr, "pdftops version %s\n", PACKAGE_VERSION);
200     fprintf(stderr, "%s\n", popplerCopyright);
201     fprintf(stderr, "%s\n", xpdfCopyright);
202     if (!printVersion) {
203       printUsage("pdftops", "<PDF-file> [<PS-file>]", argDesc);
204     }
205     if (printVersion || printHelp)
206       exit(0);
207     else
208       exit(1);
209   }
210   if ((level1 ? 1 : 0) +
211       (level1Sep ? 1 : 0) +
212       (level2 ? 1 : 0) +
213       (level2Sep ? 1 : 0) +
214       (level3 ? 1 : 0) +
215       (level3Sep ? 1 : 0) > 1) {
216     fprintf(stderr, "Error: use only one of the 'level' options.\n");
217     exit(1);
218   }
219   if ((doOrigPageSizes ? 1 : 0) +
220       (doEPS ? 1 : 0) +
221       (doForm ? 1 : 0) > 1) {
222     fprintf(stderr, "Error: use only one of -origpagesizes, -eps, and -form\n");
223     exit(1);
224   }
225   if (level1) {
226     level = psLevel1;
227   } else if (level1Sep) {
228     level = psLevel1Sep;
229   } else if (level2Sep) {
230     level = psLevel2Sep;
231   } else if (level3) {
232     level = psLevel3;
233   } else if (level3Sep) {
234     level = psLevel3Sep;
235   } else {
236     level = psLevel2;
237   }
238   if (doForm && level < psLevel2) {
239     fprintf(stderr, "Error: forms are only available with Level 2 output.\n");
240     exit(1);
241   }
242   mode = doOrigPageSizes ? psModePSOrigPageSizes
243                          : doEPS ? psModeEPS
244                                  : doForm ? psModeForm
245                                           : psModePS;
246   fileName = new GooString(argv[1]);
247 
248   // read config file
249   globalParams = new GlobalParams();
250   if (paperSize[0]) {
251     if (!setPSPaperSize(paperSize, paperWidth, paperHeight)) {
252       fprintf(stderr, "Invalid paper size\n");
253       delete fileName;
254       goto err0;
255     }
256   }
257   if (expand) {
258     globalParams->setPSExpandSmaller(gTrue);
259   }
260   if (noShrink) {
261     globalParams->setPSShrinkLarger(gFalse);
262   }
263   if (noCenter) {
264     globalParams->setPSCenter(gFalse);
265   }
266   if (level1 || level1Sep || level2 || level2Sep || level3 || level3Sep) {
267     globalParams->setPSLevel(level);
268   }
269   if (noEmbedT1Fonts) {
270     globalParams->setPSEmbedType1(!noEmbedT1Fonts);
271   }
272   if (noEmbedTTFonts) {
273     globalParams->setPSEmbedTrueType(!noEmbedTTFonts);
274   }
275   if (noEmbedCIDPSFonts) {
276     globalParams->setPSEmbedCIDPostScript(!noEmbedCIDPSFonts);
277   }
278   if (noEmbedCIDTTFonts) {
279     globalParams->setPSEmbedCIDTrueType(!noEmbedCIDTTFonts);
280   }
281   if (noSubstFonts) {
282     globalParams->setPSSubstFonts(!noSubstFonts);
283   }
284   if (preload) {
285     globalParams->setPSPreload(preload);
286   }
287 #if OPI_SUPPORT
288   if (doOPI) {
289     globalParams->setPSOPI(doOPI);
290   }
291 #endif
292   if (quiet) {
293     globalParams->setErrQuiet(quiet);
294   }
295 
296   // open PDF file
297   if (ownerPassword[0] != '\001') {
298     ownerPW = new GooString(ownerPassword);
299   } else {
300     ownerPW = NULL;
301   }
302   if (userPassword[0] != '\001') {
303     userPW = new GooString(userPassword);
304   } else {
305     userPW = NULL;
306   }
307   if (fileName->cmp("-") == 0) {
308       delete fileName;
309       fileName = new GooString("fd://0");
310   }
311 
312   doc = PDFDocFactory().createPDFDoc(*fileName, ownerPW, userPW);
313 
314   if (userPW) {
315     delete userPW;
316   }
317   if (ownerPW) {
318     delete ownerPW;
319   }
320   if (!doc->isOk()) {
321     exitCode = 1;
322     goto err1;
323   }
324 
325 #ifdef ENFORCE_PERMISSIONS
326   // check for print permission
327   if (!doc->okToPrint()) {
328     error(-1, "Printing this document is not allowed.");
329     exitCode = 3;
330     goto err1;
331   }
332 #endif
333 
334   // construct PostScript file name
335   if (argc == 3) {
336     psFileName = new GooString(argv[2]);
337   } else if (fileName->cmp("fd://0") == 0) {
338     error(-1, "You have to provide an output filename when reading form stdin.");
339     goto err1;
340   } else {
341     p = fileName->getCString() + fileName->getLength() - 4;
342     if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) {
343       psFileName = new GooString(fileName->getCString(),
344 			       fileName->getLength() - 4);
345     } else {
346       psFileName = fileName->copy();
347     }
348     psFileName->append(doEPS ? ".eps" : ".ps");
349   }
350 
351   // get page range
352   if (firstPage < 1) {
353     firstPage = 1;
354   }
355   if (lastPage < 1 || lastPage > doc->getNumPages()) {
356     lastPage = doc->getNumPages();
357   }
358 
359   // check for multi-page EPS or form
360   if ((doEPS || doForm) && firstPage != lastPage) {
361     error(-1, "EPS and form files can only contain one page.");
362     goto err2;
363   }
364 
365   // write PostScript file
366   psOut = new PSOutputDev(psFileName->getCString(), doc, doc->getXRef(),
367 			  doc->getCatalog(), NULL, firstPage, lastPage, mode,
368 			  paperWidth,
369 			  paperHeight,
370 			  duplex);
371   if (psOut->isOk()) {
372     doc->displayPages(psOut, firstPage, lastPage, 72, 72,
373 		      0, noCrop, !noCrop, gTrue);
374   } else {
375     delete psOut;
376     exitCode = 2;
377     goto err2;
378   }
379   delete psOut;
380 
381   exitCode = 0;
382 
383   // clean up
384  err2:
385   delete psFileName;
386  err1:
387   delete doc;
388   delete fileName;
389  err0:
390   delete globalParams;
391 
392   // check for memory leaks
393   Object::memCheck(stderr);
394   gMemReport(stderr);
395 
396   return exitCode;
397 }
398