1 //========================================================================
2 //
3 // pdftoppm.cc
4 //
5 // Copyright 2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 //========================================================================
10 //
11 // Modified under the Poppler project - http://poppler.freedesktop.org
12 //
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
15 //
16 // Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com>
17 // Copyright (C) 2008 Richard Airlie <richard.airlie@maglabs.net>
18 // Copyright (C) 2009 Michael K. Johnson <a1237@danlj.org>
19 // Copyright (C) 2009 Shen Liang <shenzhuxi@gmail.com>
20 // Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
21 // Copyright (C) 2009, 2010 Albert Astals Cid <aacid@kde.org>
22 // Copyright (C) 2010 Adrian Johnson <ajohnson@redneon.com>
23 // Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
24 // Copyright (C) 2010 Jonathan Liu <net147@gmail.com>
25 //
26 // To see a description of the changes please see the Changelog file that
27 // came with your tarball or type make ChangeLog if you are building from git
28 //
29 //========================================================================
30
31 #include "config.h"
32 #include <poppler-config.h>
33 #ifdef _WIN32
34 #include <fcntl.h> // for O_BINARY
35 #include <io.h> // for setmode
36 #endif
37 #include <stdio.h>
38 #include <math.h>
39 #include "parseargs.h"
40 #include "goo/gmem.h"
41 #include "goo/GooString.h"
42 #include "GlobalParams.h"
43 #include "Object.h"
44 #include "PDFDoc.h"
45 #include "PDFDocFactory.h"
46 #include "splash/SplashBitmap.h"
47 #include "splash/Splash.h"
48 #include "SplashOutputDev.h"
49
50 #define PPM_FILE_SZ 512
51
52 static int firstPage = 1;
53 static int lastPage = 0;
54 static GBool printOnlyOdd = gFalse;
55 static GBool printOnlyEven = gFalse;
56 static double resolution = 0.0;
57 static double x_resolution = 150.0;
58 static double y_resolution = 150.0;
59 static int scaleTo = 0;
60 static int x_scaleTo = 0;
61 static int y_scaleTo = 0;
62 static int x = 0;
63 static int y = 0;
64 static int w = 0;
65 static int h = 0;
66 static int sz = 0;
67 static GBool useCropBox = gFalse;
68 static GBool mono = gFalse;
69 static GBool gray = gFalse;
70 static GBool png = gFalse;
71 static GBool jpeg = gFalse;
72 static char enableFreeTypeStr[16] = "";
73 static char antialiasStr[16] = "";
74 static char vectorAntialiasStr[16] = "";
75 static char ownerPassword[33] = "";
76 static char userPassword[33] = "";
77 static GBool quiet = gFalse;
78 static GBool printVersion = gFalse;
79 static GBool printHelp = gFalse;
80
81 static const ArgDesc argDesc[] = {
82 {"-f", argInt, &firstPage, 0,
83 "first page to print"},
84 {"-l", argInt, &lastPage, 0,
85 "last page to print"},
86 {"-o", argFlag, &printOnlyOdd, 0,
87 "print only odd pages"},
88 {"-e", argFlag, &printOnlyEven, 0,
89 "print only even pages"},
90
91 {"-r", argFP, &resolution, 0,
92 "resolution, in DPI (default is 150)"},
93 {"-rx", argFP, &x_resolution, 0,
94 "X resolution, in DPI (default is 150)"},
95 {"-ry", argFP, &y_resolution, 0,
96 "Y resolution, in DPI (default is 150)"},
97 {"-scale-to", argInt, &scaleTo, 0,
98 "scales each page to fit within scale-to*scale-to pixel box"},
99 {"-scale-to-x", argInt, &x_scaleTo, 0,
100 "scales each page horizontally to fit in scale-to-x pixels"},
101 {"-scale-to-y", argInt, &y_scaleTo, 0,
102 "scales each page vertically to fit in scale-to-y pixels"},
103
104 {"-x", argInt, &x, 0,
105 "x-coordinate of the crop area top left corner"},
106 {"-y", argInt, &y, 0,
107 "y-coordinate of the crop area top left corner"},
108 {"-W", argInt, &w, 0,
109 "width of crop area in pixels (default is 0)"},
110 {"-H", argInt, &h, 0,
111 "height of crop area in pixels (default is 0)"},
112 {"-sz", argInt, &sz, 0,
113 "size of crop square in pixels (sets W and H)"},
114 {"-cropbox",argFlag, &useCropBox, 0,
115 "use the crop box rather than media box"},
116
117 {"-mono", argFlag, &mono, 0,
118 "generate a monochrome PBM file"},
119 {"-gray", argFlag, &gray, 0,
120 "generate a grayscale PGM file"},
121 #if ENABLE_LIBPNG
122 {"-png", argFlag, &png, 0,
123 "generate a PNG file"},
124 #endif
125 #if ENABLE_LIBJPEG
126 {"-jpeg", argFlag, &jpeg, 0,
127 "generate a JPEG file"},
128 #endif
129 #if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H
130 {"-freetype", argString, enableFreeTypeStr, sizeof(enableFreeTypeStr),
131 "enable FreeType font rasterizer: yes, no"},
132 #endif
133
134 {"-aa", argString, antialiasStr, sizeof(antialiasStr),
135 "enable font anti-aliasing: yes, no"},
136 {"-aaVector", argString, vectorAntialiasStr, sizeof(vectorAntialiasStr),
137 "enable vector anti-aliasing: yes, no"},
138
139 {"-opw", argString, ownerPassword, sizeof(ownerPassword),
140 "owner password (for encrypted files)"},
141 {"-upw", argString, userPassword, sizeof(userPassword),
142 "user password (for encrypted files)"},
143
144 {"-q", argFlag, &quiet, 0,
145 "don't print any messages or errors"},
146 {"-v", argFlag, &printVersion, 0,
147 "print copyright and version info"},
148 {"-h", argFlag, &printHelp, 0,
149 "print usage information"},
150 {"-help", argFlag, &printHelp, 0,
151 "print usage information"},
152 {"--help", argFlag, &printHelp, 0,
153 "print usage information"},
154 {"-?", argFlag, &printHelp, 0,
155 "print usage information"},
156 {NULL}
157 };
158
savePageSlice(PDFDoc * doc,SplashOutputDev * splashOut,int pg,int x,int y,int w,int h,double pg_w,double pg_h,char * ppmFile)159 static void savePageSlice(PDFDoc *doc,
160 SplashOutputDev *splashOut,
161 int pg, int x, int y, int w, int h,
162 double pg_w, double pg_h,
163 char *ppmFile) {
164 if (w == 0) w = (int)ceil(pg_w);
165 if (h == 0) h = (int)ceil(pg_h);
166 w = (x+w > pg_w ? (int)ceil(pg_w-x) : w);
167 h = (y+h > pg_h ? (int)ceil(pg_h-y) : h);
168 doc->displayPageSlice(splashOut,
169 pg, x_resolution, y_resolution,
170 0,
171 !useCropBox, gFalse, gFalse,
172 x, y, w, h
173 );
174
175 SplashBitmap *bitmap = splashOut->getBitmap();
176
177 if (ppmFile != NULL) {
178 if (png) {
179 bitmap->writeImgFile(splashFormatPng, ppmFile, x_resolution, y_resolution);
180 } else if (jpeg) {
181 bitmap->writeImgFile(splashFormatJpeg, ppmFile, x_resolution, y_resolution);
182 } else {
183 bitmap->writePNMFile(ppmFile);
184 }
185 } else {
186 #ifdef __EMSCRIPTEN__ // XXX EMSCRIPTEN: avoid writing to stdout, better for benchmarking
187 printf("avoiding writing to stdout\n");
188 #else
189
190 #ifdef _WIN32
191 setmode(fileno(stdout), O_BINARY);
192 #endif
193
194 if (png) {
195 bitmap->writeImgFile(splashFormatPng, stdout, x_resolution, y_resolution);
196 } else if (jpeg) {
197 bitmap->writeImgFile(splashFormatJpeg, stdout, x_resolution, y_resolution);
198 } else {
199 bitmap->writePNMFile(stdout);
200 }
201 #endif
202 }
203 }
204
numberOfCharacters(unsigned int n)205 static int numberOfCharacters(unsigned int n)
206 {
207 int charNum = 0;
208 while (n >= 10)
209 {
210 n = n / 10;
211 charNum++;
212 }
213 charNum++;
214 return charNum;
215 }
216
main(int argc,char * argv[])217 int main(int argc, char *argv[]) {
218 PDFDoc *doc;
219 GooString *fileName = NULL;
220 char *ppmRoot = NULL;
221 char ppmFile[PPM_FILE_SZ];
222 GooString *ownerPW, *userPW;
223 SplashColor paperColor;
224 SplashOutputDev *splashOut;
225 GBool ok;
226 int exitCode;
227 int pg, pg_num_len;
228 double pg_w, pg_h, tmp;
229
230 exitCode = 99;
231
232 // parse args
233 ok = parseArgs(argDesc, &argc, argv);
234 if (mono && gray) {
235 ok = gFalse;
236 }
237 if ( resolution != 0.0 &&
238 (x_resolution == 150.0 ||
239 y_resolution == 150.0)) {
240 x_resolution = resolution;
241 y_resolution = resolution;
242 }
243 if (!ok || argc > 3 || printVersion || printHelp) {
244 fprintf(stderr, "pdftoppm version %s\n", PACKAGE_VERSION);
245 fprintf(stderr, "%s\n", popplerCopyright);
246 fprintf(stderr, "%s\n", xpdfCopyright);
247 if (!printVersion) {
248 printUsage("pdftoppm", "[PDF-file [PPM-file-prefix]]", argDesc);
249 }
250 if (printVersion || printHelp)
251 exitCode = 0;
252 goto err0;
253 }
254 if (argc > 1) fileName = new GooString(argv[1]);
255 if (argc == 3) ppmRoot = argv[2];
256
257 // read config file
258 globalParams = new GlobalParams();
259 if (enableFreeTypeStr[0]) {
260 if (!globalParams->setEnableFreeType(enableFreeTypeStr)) {
261 fprintf(stderr, "Bad '-freetype' value on command line\n");
262 }
263 }
264 if (antialiasStr[0]) {
265 if (!globalParams->setAntialias(antialiasStr)) {
266 fprintf(stderr, "Bad '-aa' value on command line\n");
267 }
268 }
269 if (vectorAntialiasStr[0]) {
270 if (!globalParams->setVectorAntialias(vectorAntialiasStr)) {
271 fprintf(stderr, "Bad '-aaVector' value on command line\n");
272 }
273 }
274 if (quiet) {
275 globalParams->setErrQuiet(quiet);
276 }
277
278 // open PDF file
279 if (ownerPassword[0]) {
280 ownerPW = new GooString(ownerPassword);
281 } else {
282 ownerPW = NULL;
283 }
284 if (userPassword[0]) {
285 userPW = new GooString(userPassword);
286 } else {
287 userPW = NULL;
288 }
289
290 if (fileName == NULL) {
291 fileName = new GooString("fd://0");
292 }
293 if (fileName->cmp("-") == 0) {
294 delete fileName;
295 fileName = new GooString("fd://0");
296 }
297 doc = PDFDocFactory().createPDFDoc(*fileName, ownerPW, userPW);
298 delete fileName;
299
300 if (userPW) {
301 delete userPW;
302 }
303 if (ownerPW) {
304 delete ownerPW;
305 }
306 if (!doc->isOk()) {
307 exitCode = 1;
308 goto err1;
309 }
310
311 // get page range
312 if (firstPage < 1)
313 firstPage = 1;
314 if (lastPage < 1 || lastPage > doc->getNumPages())
315 lastPage = doc->getNumPages();
316
317 // write PPM files
318 paperColor[0] = 255;
319 paperColor[1] = 255;
320 paperColor[2] = 255;
321 splashOut = new SplashOutputDev(mono ? splashModeMono1 :
322 gray ? splashModeMono8 :
323 splashModeRGB8, 4,
324 gFalse, paperColor);
325 splashOut->startDoc(doc->getXRef());
326 if (sz != 0) w = h = sz;
327 pg_num_len = numberOfCharacters(doc->getNumPages());
328 for (pg = firstPage; pg <= lastPage; ++pg) {
329 if (printOnlyEven && pg % 2 == 0) continue;
330 if (printOnlyOdd && pg % 2 == 1) continue;
331 if (useCropBox) {
332 pg_w = doc->getPageCropWidth(pg);
333 pg_h = doc->getPageCropHeight(pg);
334 } else {
335 pg_w = doc->getPageMediaWidth(pg);
336 pg_h = doc->getPageMediaHeight(pg);
337 }
338
339 if (scaleTo != 0) {
340 resolution = (72.0 * scaleTo) / (pg_w > pg_h ? pg_w : pg_h);
341 x_resolution = y_resolution = resolution;
342 } else {
343 if (x_scaleTo != 0) {
344 x_resolution = (72.0 * x_scaleTo) / pg_w;
345 }
346 if (y_scaleTo != 0) {
347 y_resolution = (72.0 * y_scaleTo) / pg_h;
348 }
349 }
350 pg_w = pg_w * (x_resolution / 72.0);
351 pg_h = pg_h * (y_resolution / 72.0);
352 if ((doc->getPageRotate(pg) == 90) || (doc->getPageRotate(pg) == 270)) {
353 tmp = pg_w;
354 pg_w = pg_h;
355 pg_h = tmp;
356 }
357 if (ppmRoot != NULL) {
358 snprintf(ppmFile, PPM_FILE_SZ, "%.*s-%0*d.%s",
359 PPM_FILE_SZ - 32, ppmRoot, pg_num_len, pg,
360 png ? "png" : jpeg ? "jpg" : mono ? "pbm" : gray ? "pgm" : "ppm");
361 savePageSlice(doc, splashOut, pg, x, y, w, h, pg_w, pg_h, ppmFile);
362 } else {
363 savePageSlice(doc, splashOut, pg, x, y, w, h, pg_w, pg_h, NULL);
364 }
365 }
366 delete splashOut;
367
368 exitCode = 0;
369
370 // clean up
371 err1:
372 delete doc;
373 delete globalParams;
374 err0:
375
376 // check for memory leaks
377 Object::memCheck(stderr);
378 gMemReport(stderr);
379
380 return exitCode;
381 }
382