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