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