1 | //======================================================================== |
2 | // |
3 | // pdfimages.cc |
4 | // |
5 | // Copyright 1998-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) 2007-2008, 2010, 2018, 2022, 2024 Albert Astals Cid <aacid@kde.org> |
19 | // Copyright (C) 2010 Hib Eris <hib@hiberis.nl> |
20 | // Copyright (C) 2010 Jakob Voss <jakob.voss@gbv.de> |
21 | // Copyright (C) 2012, 2013, 2017 Adrian Johnson <ajohnson@redneon.com> |
22 | // Copyright (C) 2013 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp> |
23 | // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de> |
24 | // Copyright (C) 2019, 2021 Oliver Sander <oliver.sander@tu-dresden.de> |
25 | // Copyright (C) 2019 Hartmut Goebel <h.goebel@crazy-compilers.com> |
26 | // Copyright (C) 2024 Fernando Herrera <fherrera@onirica.com> |
27 | // Copyright (C) 2024 Sebastian J. Bronner <waschtl@sbronner.com> |
28 | // |
29 | // To see a description of the changes please see the Changelog file that |
30 | // came with your tarball or type make ChangeLog if you are building from git |
31 | // |
32 | //======================================================================== |
33 | |
34 | #include "config.h" |
35 | #include <poppler-config.h> |
36 | #include <cstdio> |
37 | #include <cstdlib> |
38 | #include <cstddef> |
39 | #include <cstring> |
40 | #include "parseargs.h" |
41 | #include "goo/GooString.h" |
42 | #include "goo/gmem.h" |
43 | #include "GlobalParams.h" |
44 | #include "Object.h" |
45 | #include "Stream.h" |
46 | #include "Array.h" |
47 | #include "Dict.h" |
48 | #include "XRef.h" |
49 | #include "Catalog.h" |
50 | #include "Page.h" |
51 | #include "PDFDoc.h" |
52 | #include "PDFDocFactory.h" |
53 | #include "ImageOutputDev.h" |
54 | #include "Error.h" |
55 | #include "Win32Console.h" |
56 | |
57 | static int firstPage = 1; |
58 | static int lastPage = 0; |
59 | static bool listImages = false; |
60 | static bool enablePNG = false; |
61 | static bool enableTiff = false; |
62 | static bool dumpJPEG = false; |
63 | static bool dumpJP2 = false; |
64 | static bool dumpJBIG2 = false; |
65 | static bool dumpCCITT = false; |
66 | static bool allFormats = false; |
67 | static bool pageNames = false; |
68 | static bool printFilenames = false; |
69 | static char ownerPassword[33] = "\001" ; |
70 | static char userPassword[33] = "\001" ; |
71 | static bool quiet = false; |
72 | static bool printVersion = false; |
73 | static bool printHelp = false; |
74 | |
75 | static const ArgDesc argDesc[] = { { .arg: "-f" , .kind: argInt, .val: &firstPage, .size: 0, .usage: "first page to convert" }, |
76 | { .arg: "-l" , .kind: argInt, .val: &lastPage, .size: 0, .usage: "last page to convert" }, |
77 | #ifdef ENABLE_LIBPNG |
78 | { .arg: "-png" , .kind: argFlag, .val: &enablePNG, .size: 0, .usage: "change the default output format to PNG" }, |
79 | #endif |
80 | #ifdef ENABLE_LIBTIFF |
81 | { .arg: "-tiff" , .kind: argFlag, .val: &enableTiff, .size: 0, .usage: "change the default output format to TIFF" }, |
82 | #endif |
83 | { .arg: "-j" , .kind: argFlag, .val: &dumpJPEG, .size: 0, .usage: "write JPEG images as JPEG files" }, |
84 | { .arg: "-jp2" , .kind: argFlag, .val: &dumpJP2, .size: 0, .usage: "write JPEG2000 images as JP2 files" }, |
85 | { .arg: "-jbig2" , .kind: argFlag, .val: &dumpJBIG2, .size: 0, .usage: "write JBIG2 images as JBIG2 files" }, |
86 | { .arg: "-ccitt" , .kind: argFlag, .val: &dumpCCITT, .size: 0, .usage: "write CCITT images as CCITT files" }, |
87 | { .arg: "-all" , .kind: argFlag, .val: &allFormats, .size: 0, .usage: "equivalent to -png -tiff -j -jp2 -jbig2 -ccitt" }, |
88 | { .arg: "-list" , .kind: argFlag, .val: &listImages, .size: 0, .usage: "print list of images instead of saving" }, |
89 | { .arg: "-opw" , .kind: argString, .val: ownerPassword, .size: sizeof(ownerPassword), .usage: "owner password (for encrypted files)" }, |
90 | { .arg: "-upw" , .kind: argString, .val: userPassword, .size: sizeof(userPassword), .usage: "user password (for encrypted files)" }, |
91 | { .arg: "-p" , .kind: argFlag, .val: &pageNames, .size: 0, .usage: "include page numbers in output file names" }, |
92 | { .arg: "-print-filenames" , .kind: argFlag, .val: &printFilenames, .size: 0, .usage: "print image filenames to stdout" }, |
93 | { .arg: "-q" , .kind: argFlag, .val: &quiet, .size: 0, .usage: "don't print any messages or errors" }, |
94 | { .arg: "-v" , .kind: argFlag, .val: &printVersion, .size: 0, .usage: "print copyright and version info" }, |
95 | { .arg: "-h" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
96 | { .arg: "-help" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
97 | { .arg: "--help" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
98 | { .arg: "-?" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
99 | {} }; |
100 | |
101 | int main(int argc, char *argv[]) |
102 | { |
103 | char *imgRoot = nullptr; |
104 | std::optional<GooString> ownerPW, userPW; |
105 | |
106 | Win32Console win32Console(&argc, &argv); |
107 | |
108 | // parse args |
109 | const bool ok = parseArgs(args: argDesc, argc: &argc, argv); |
110 | if (!ok || (listImages && argc != 2) || (!listImages && argc != 3) || printVersion || printHelp) { |
111 | fprintf(stderr, format: "pdfimages version %s\n" , PACKAGE_VERSION); |
112 | fprintf(stderr, format: "%s\n" , popplerCopyright); |
113 | fprintf(stderr, format: "%s\n" , xpdfCopyright); |
114 | if (!printVersion) { |
115 | printUsage(program: "pdfimages" , otherArgs: "<PDF-file> <image-root>" , args: argDesc); |
116 | } |
117 | if (printVersion || printHelp) { |
118 | return 0; |
119 | } |
120 | return 99; |
121 | } |
122 | GooString *fileName = new GooString(argv[1]); |
123 | if (!listImages) { |
124 | imgRoot = argv[2]; |
125 | } |
126 | |
127 | // read config file |
128 | globalParams = std::make_unique<GlobalParams>(); |
129 | if (quiet) { |
130 | globalParams->setErrQuiet(quiet); |
131 | } |
132 | |
133 | // open PDF file |
134 | if (ownerPassword[0] != '\001') { |
135 | ownerPW = GooString(ownerPassword); |
136 | } |
137 | if (userPassword[0] != '\001') { |
138 | userPW = GooString(userPassword); |
139 | } |
140 | if (fileName->cmp(sA: "-" ) == 0) { |
141 | delete fileName; |
142 | fileName = new GooString("fd://0" ); |
143 | } |
144 | |
145 | std::unique_ptr<PDFDoc> doc = PDFDocFactory().createPDFDoc(uri: *fileName, ownerPassword: ownerPW, userPassword: userPW); |
146 | delete fileName; |
147 | |
148 | if (!doc->isOk()) { |
149 | return 1; |
150 | } |
151 | |
152 | // check for copy permission |
153 | #ifdef ENFORCE_PERMISSIONS |
154 | if (!doc->okToCopy()) { |
155 | error(errNotAllowed, -1, "Copying of images from this document is not allowed." ); |
156 | return 3; |
157 | } |
158 | #endif |
159 | |
160 | // get page range |
161 | if (firstPage < 1) { |
162 | firstPage = 1; |
163 | } |
164 | if (firstPage > doc->getNumPages()) { |
165 | error(category: errCommandLine, pos: -1, msg: "Wrong page range given: the first page ({0:d}) can not be larger then the number of pages in the document ({1:d})." , firstPage, doc->getNumPages()); |
166 | return 99; |
167 | } |
168 | if (lastPage < 1 || lastPage > doc->getNumPages()) { |
169 | lastPage = doc->getNumPages(); |
170 | } |
171 | if (lastPage < firstPage) { |
172 | error(category: errCommandLine, pos: -1, msg: "Wrong page range given: the first page ({0:d}) can not be after the last page ({1:d})." , firstPage, lastPage); |
173 | return 99; |
174 | } |
175 | |
176 | // write image files |
177 | ImageOutputDev *imgOut = new ImageOutputDev(imgRoot, pageNames, listImages); |
178 | if (imgOut->isOk()) { |
179 | if (allFormats) { |
180 | imgOut->enablePNG(png: true); |
181 | imgOut->enableTiff(tiff: true); |
182 | imgOut->enableJpeg(jpeg: true); |
183 | imgOut->enableJpeg2000(jp2: true); |
184 | imgOut->enableJBig2(jbig2: true); |
185 | imgOut->enableCCITT(ccitt: true); |
186 | } else { |
187 | imgOut->enablePNG(png: enablePNG); |
188 | imgOut->enableTiff(tiff: enableTiff); |
189 | imgOut->enableJpeg(jpeg: dumpJPEG); |
190 | imgOut->enableJpeg2000(jp2: dumpJP2); |
191 | imgOut->enableJBig2(jbig2: dumpJBIG2); |
192 | imgOut->enableCCITT(ccitt: dumpCCITT); |
193 | } |
194 | imgOut->enablePrintFilenames(filenames: printFilenames); |
195 | doc->displayPages(out: imgOut, firstPage, lastPage, hDPI: 72, vDPI: 72, rotate: 0, useMediaBox: true, crop: false, printing: false); |
196 | } |
197 | const int exitCode = imgOut->isOk() ? 0 : imgOut->getErrorCode(); |
198 | delete imgOut; |
199 | return exitCode; |
200 | } |
201 | |