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, 2015, 2017, 2018, 2020-2022 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, 2011, 2012, 2014-2016, 2020 William Bader <williambader@hotmail.com> |
23 | // Copyright (C) 2010 Hib Eris <hib@hiberis.nl> |
24 | // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de> |
25 | // Copyright (C) 2013 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp> |
26 | // Copyright (C) 2014, 2017 Adrian Johnson <ajohnson@redneon.com> |
27 | // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de> |
28 | // Copyright (C) 2019, 2021, 2023 Oliver Sander <oliver.sander@tu-dresden.de> |
29 | // Copyright (C) 2020 Philipp Knechtges <philipp-dev@knechtges.com> |
30 | // Copyright (C) 2021 Hubert Figuiere <hub@figuiere.net> |
31 | // |
32 | // To see a description of the changes please see the Changelog file that |
33 | // came with your tarball or type make ChangeLog if you are building from git |
34 | // |
35 | //======================================================================== |
36 | |
37 | #include "config.h" |
38 | #include <poppler-config.h> |
39 | #include <cstdio> |
40 | #include <cstdlib> |
41 | #include <cstddef> |
42 | #include <cstring> |
43 | #include "parseargs.h" |
44 | #include "goo/GooString.h" |
45 | #include "goo/gmem.h" |
46 | #include "GlobalParams.h" |
47 | #include "Object.h" |
48 | #include "Stream.h" |
49 | #include "Array.h" |
50 | #include "Dict.h" |
51 | #include "XRef.h" |
52 | #include "Catalog.h" |
53 | #include "Page.h" |
54 | #include "PDFDoc.h" |
55 | #include "PDFDocFactory.h" |
56 | #include "PSOutputDev.h" |
57 | #include "Error.h" |
58 | #include "Win32Console.h" |
59 | #include "sanitychecks.h" |
60 | |
61 | #ifdef USE_CMS |
62 | # include <lcms2.h> |
63 | #endif |
64 | |
65 | static bool setPSPaperSize(char *size, int &psPaperWidth, int &psPaperHeight) |
66 | { |
67 | if (!strcmp(s1: size, s2: "match" )) { |
68 | psPaperWidth = psPaperHeight = -1; |
69 | } else if (!strcmp(s1: size, s2: "letter" )) { |
70 | psPaperWidth = 612; |
71 | psPaperHeight = 792; |
72 | } else if (!strcmp(s1: size, s2: "legal" )) { |
73 | psPaperWidth = 612; |
74 | psPaperHeight = 1008; |
75 | } else if (!strcmp(s1: size, s2: "A4" )) { |
76 | psPaperWidth = 595; |
77 | psPaperHeight = 842; |
78 | } else if (!strcmp(s1: size, s2: "A3" )) { |
79 | psPaperWidth = 842; |
80 | psPaperHeight = 1190; |
81 | } else { |
82 | return false; |
83 | } |
84 | return true; |
85 | } |
86 | |
87 | static int firstPage = 1; |
88 | static int lastPage = 0; |
89 | static bool level1 = false; |
90 | static bool level1Sep = false; |
91 | static bool level2 = false; |
92 | static bool level2Sep = false; |
93 | static bool level3 = false; |
94 | static bool level3Sep = false; |
95 | static bool origPageSizes = false; |
96 | static bool doEPS = false; |
97 | static bool doForm = false; |
98 | #ifdef OPI_SUPPORT |
99 | static bool doOPI = false; |
100 | #endif |
101 | static int splashResolution = 0; |
102 | static bool psBinary = false; |
103 | static bool noEmbedT1Fonts = false; |
104 | static bool noEmbedTTFonts = false; |
105 | static bool noEmbedCIDPSFonts = false; |
106 | static bool noEmbedCIDTTFonts = false; |
107 | static bool fontPassthrough = false; |
108 | static bool optimizeColorSpace = false; |
109 | static bool passLevel1CustomColor = false; |
110 | static char rasterAntialiasStr[16] = "" ; |
111 | static char forceRasterizeStr[16] = "" ; |
112 | static bool preload = false; |
113 | static char paperSize[15] = "" ; |
114 | static int paperWidth = -1; |
115 | static int paperHeight = -1; |
116 | static bool noCrop = false; |
117 | static bool expand = false; |
118 | static bool noShrink = false; |
119 | static bool noCenter = false; |
120 | static bool duplex = false; |
121 | static char ownerPassword[33] = "\001" ; |
122 | static char userPassword[33] = "\001" ; |
123 | static bool quiet = false; |
124 | static bool printVersion = false; |
125 | static bool printHelp = false; |
126 | static bool overprint = false; |
127 | static GooString processcolorformatname; |
128 | static SplashColorMode processcolorformat; |
129 | static bool processcolorformatspecified = false; |
130 | #ifdef USE_CMS |
131 | static GooString processcolorprofilename; |
132 | static GfxLCMSProfilePtr processcolorprofile; |
133 | static GooString defaultgrayprofilename; |
134 | static GfxLCMSProfilePtr defaultgrayprofile; |
135 | static GooString defaultrgbprofilename; |
136 | static GfxLCMSProfilePtr defaultrgbprofile; |
137 | static GooString defaultcmykprofilename; |
138 | static GfxLCMSProfilePtr defaultcmykprofile; |
139 | #endif |
140 | |
141 | static const ArgDesc argDesc[] = { { .arg: "-f" , .kind: argInt, .val: &firstPage, .size: 0, .usage: "first page to print" }, |
142 | { .arg: "-l" , .kind: argInt, .val: &lastPage, .size: 0, .usage: "last page to print" }, |
143 | { .arg: "-level1" , .kind: argFlag, .val: &level1, .size: 0, .usage: "generate Level 1 PostScript" }, |
144 | { .arg: "-level1sep" , .kind: argFlag, .val: &level1Sep, .size: 0, .usage: "generate Level 1 separable PostScript" }, |
145 | { .arg: "-level2" , .kind: argFlag, .val: &level2, .size: 0, .usage: "generate Level 2 PostScript" }, |
146 | { .arg: "-level2sep" , .kind: argFlag, .val: &level2Sep, .size: 0, .usage: "generate Level 2 separable PostScript" }, |
147 | { .arg: "-level3" , .kind: argFlag, .val: &level3, .size: 0, .usage: "generate Level 3 PostScript" }, |
148 | { .arg: "-level3sep" , .kind: argFlag, .val: &level3Sep, .size: 0, .usage: "generate Level 3 separable PostScript" }, |
149 | { .arg: "-origpagesizes" , .kind: argFlag, .val: &origPageSizes, .size: 0, .usage: "conserve original page sizes" }, |
150 | { .arg: "-eps" , .kind: argFlag, .val: &doEPS, .size: 0, .usage: "generate Encapsulated PostScript (EPS)" }, |
151 | { .arg: "-form" , .kind: argFlag, .val: &doForm, .size: 0, .usage: "generate a PostScript form" }, |
152 | #ifdef OPI_SUPPORT |
153 | { .arg: "-opi" , .kind: argFlag, .val: &doOPI, .size: 0, .usage: "generate OPI comments" }, |
154 | #endif |
155 | { .arg: "-r" , .kind: argInt, .val: &splashResolution, .size: 0, .usage: "resolution for rasterization, in DPI (default is 300)" }, |
156 | { .arg: "-binary" , .kind: argFlag, .val: &psBinary, .size: 0, .usage: "write binary data in Level 1 PostScript" }, |
157 | { .arg: "-noembt1" , .kind: argFlag, .val: &noEmbedT1Fonts, .size: 0, .usage: "don't embed Type 1 fonts" }, |
158 | { .arg: "-noembtt" , .kind: argFlag, .val: &noEmbedTTFonts, .size: 0, .usage: "don't embed TrueType fonts" }, |
159 | { .arg: "-noembcidps" , .kind: argFlag, .val: &noEmbedCIDPSFonts, .size: 0, .usage: "don't embed CID PostScript fonts" }, |
160 | { .arg: "-noembcidtt" , .kind: argFlag, .val: &noEmbedCIDTTFonts, .size: 0, .usage: "don't embed CID TrueType fonts" }, |
161 | { .arg: "-passfonts" , .kind: argFlag, .val: &fontPassthrough, .size: 0, .usage: "don't substitute missing fonts" }, |
162 | { .arg: "-aaRaster" , .kind: argString, .val: rasterAntialiasStr, .size: sizeof(rasterAntialiasStr), .usage: "enable anti-aliasing on rasterization: yes, no" }, |
163 | { .arg: "-rasterize" , .kind: argString, .val: forceRasterizeStr, .size: sizeof(forceRasterizeStr), .usage: "control rasterization: always, never, whenneeded" }, |
164 | { .arg: "-processcolorformat" , .kind: argGooString, .val: &processcolorformatname, .size: 0, .usage: "color format that is used during rasterization and transparency reduction: MONO8, RGB8, CMYK8" }, |
165 | #ifdef USE_CMS |
166 | { "-processcolorprofile" , argGooString, &processcolorprofilename, 0, "ICC color profile to use as the process color profile during rasterization and transparency reduction" }, |
167 | { "-defaultgrayprofile" , argGooString, &defaultgrayprofilename, 0, "ICC color profile to use as the DefaultGray color space" }, |
168 | { "-defaultrgbprofile" , argGooString, &defaultrgbprofilename, 0, "ICC color profile to use as the DefaultRGB color space" }, |
169 | { "-defaultcmykprofile" , argGooString, &defaultcmykprofilename, 0, "ICC color profile to use as the DefaultCMYK color space" }, |
170 | #endif |
171 | { .arg: "-optimizecolorspace" , .kind: argFlag, .val: &optimizeColorSpace, .size: 0, .usage: "convert gray RGB images to gray color space" }, |
172 | { .arg: "-passlevel1customcolor" , .kind: argFlag, .val: &passLevel1CustomColor, .size: 0, .usage: "pass custom color in level1sep" }, |
173 | { .arg: "-preload" , .kind: argFlag, .val: &preload, .size: 0, .usage: "preload images and forms" }, |
174 | { .arg: "-paper" , .kind: argString, .val: paperSize, .size: sizeof(paperSize), .usage: "paper size (letter, legal, A4, A3, match)" }, |
175 | { .arg: "-paperw" , .kind: argInt, .val: &paperWidth, .size: 0, .usage: "paper width, in points" }, |
176 | { .arg: "-paperh" , .kind: argInt, .val: &paperHeight, .size: 0, .usage: "paper height, in points" }, |
177 | { .arg: "-nocrop" , .kind: argFlag, .val: &noCrop, .size: 0, .usage: "don't crop pages to CropBox" }, |
178 | { .arg: "-expand" , .kind: argFlag, .val: &expand, .size: 0, .usage: "expand pages smaller than the paper size" }, |
179 | { .arg: "-noshrink" , .kind: argFlag, .val: &noShrink, .size: 0, .usage: "don't shrink pages larger than the paper size" }, |
180 | { .arg: "-nocenter" , .kind: argFlag, .val: &noCenter, .size: 0, .usage: "don't center pages smaller than the paper size" }, |
181 | { .arg: "-duplex" , .kind: argFlag, .val: &duplex, .size: 0, .usage: "enable duplex printing" }, |
182 | { .arg: "-opw" , .kind: argString, .val: ownerPassword, .size: sizeof(ownerPassword), .usage: "owner password (for encrypted files)" }, |
183 | { .arg: "-upw" , .kind: argString, .val: userPassword, .size: sizeof(userPassword), .usage: "user password (for encrypted files)" }, |
184 | { .arg: "-overprint" , .kind: argFlag, .val: &overprint, .size: 0, .usage: "enable overprint emulation during rasterization" }, |
185 | { .arg: "-q" , .kind: argFlag, .val: &quiet, .size: 0, .usage: "don't print any messages or errors" }, |
186 | { .arg: "-v" , .kind: argFlag, .val: &printVersion, .size: 0, .usage: "print copyright and version info" }, |
187 | { .arg: "-h" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
188 | { .arg: "-help" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
189 | { .arg: "--help" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
190 | { .arg: "-?" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
191 | {} }; |
192 | |
193 | int main(int argc, char *argv[]) |
194 | { |
195 | std::unique_ptr<PDFDoc> doc; |
196 | GooString *fileName; |
197 | std::string psFileName; |
198 | PSLevel level; |
199 | PSOutMode mode; |
200 | std::optional<GooString> ownerPW, userPW; |
201 | PSOutputDev *psOut; |
202 | bool ok; |
203 | int exitCode; |
204 | bool rasterAntialias = false; |
205 | std::vector<int> pages; |
206 | #ifdef USE_CMS |
207 | cmsColorSpaceSignature profilecolorspace; |
208 | #endif |
209 | |
210 | Win32Console win32Console(&argc, &argv); |
211 | exitCode = 99; |
212 | |
213 | // parse args |
214 | ok = parseArgs(args: argDesc, argc: &argc, argv); |
215 | if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) { |
216 | fprintf(stderr, format: "pdftops version %s\n" , PACKAGE_VERSION); |
217 | fprintf(stderr, format: "%s\n" , popplerCopyright); |
218 | fprintf(stderr, format: "%s\n" , xpdfCopyright); |
219 | if (!printVersion) { |
220 | printUsage(program: "pdftops" , otherArgs: "<PDF-file> [<PS-file>]" , args: argDesc); |
221 | } |
222 | if (printVersion || printHelp) { |
223 | exit(status: 0); |
224 | } else { |
225 | exit(status: 1); |
226 | } |
227 | } |
228 | if ((level1 ? 1 : 0) + (level1Sep ? 1 : 0) + (level2 ? 1 : 0) + (level2Sep ? 1 : 0) + (level3 ? 1 : 0) + (level3Sep ? 1 : 0) > 1) { |
229 | fprintf(stderr, format: "Error: use only one of the 'level' options.\n" ); |
230 | exit(status: 1); |
231 | } |
232 | if ((doEPS ? 1 : 0) + (doForm ? 1 : 0) > 1) { |
233 | fprintf(stderr, format: "Error: use only one of -eps, and -form\n" ); |
234 | exit(status: 1); |
235 | } |
236 | if (level1) { |
237 | level = psLevel1; |
238 | } else if (level1Sep) { |
239 | level = psLevel1Sep; |
240 | } else if (level2Sep) { |
241 | level = psLevel2Sep; |
242 | } else if (level3) { |
243 | level = psLevel3; |
244 | } else if (level3Sep) { |
245 | level = psLevel3Sep; |
246 | } else { |
247 | level = psLevel2; |
248 | } |
249 | if (doForm && level < psLevel2) { |
250 | fprintf(stderr, format: "Error: forms are only available with Level 2 output.\n" ); |
251 | exit(status: 1); |
252 | } |
253 | mode = doEPS ? psModeEPS : doForm ? psModeForm : psModePS; |
254 | fileName = new GooString(argv[1]); |
255 | |
256 | // read config file |
257 | globalParams = std::make_unique<GlobalParams>(); |
258 | if (origPageSizes) { |
259 | paperWidth = paperHeight = -1; |
260 | } |
261 | if (paperSize[0]) { |
262 | if (origPageSizes) { |
263 | fprintf(stderr, format: "Error: -origpagesizes and -paper may not be used together.\n" ); |
264 | exit(status: 1); |
265 | } |
266 | if (!setPSPaperSize(size: paperSize, psPaperWidth&: paperWidth, psPaperHeight&: paperHeight)) { |
267 | fprintf(stderr, format: "Invalid paper size\n" ); |
268 | delete fileName; |
269 | goto err0; |
270 | } |
271 | } |
272 | if (quiet) { |
273 | globalParams->setErrQuiet(quiet); |
274 | } |
275 | |
276 | if (!processcolorformatname.toStr().empty()) { |
277 | if (processcolorformatname.toStr() == "MONO8" ) { |
278 | processcolorformat = splashModeMono8; |
279 | processcolorformatspecified = true; |
280 | } else if (processcolorformatname.toStr() == "CMYK8" ) { |
281 | processcolorformat = splashModeCMYK8; |
282 | processcolorformatspecified = true; |
283 | } else if (processcolorformatname.toStr() == "RGB8" ) { |
284 | processcolorformat = splashModeRGB8; |
285 | processcolorformatspecified = true; |
286 | } else { |
287 | fprintf(stderr, format: "Error: Unknown process color format \"%s\".\n" , processcolorformatname.c_str()); |
288 | goto err1; |
289 | } |
290 | } |
291 | |
292 | #ifdef USE_CMS |
293 | if (!processcolorprofilename.toStr().empty()) { |
294 | processcolorprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(processcolorprofilename.c_str(), "r" )); |
295 | if (!processcolorprofile) { |
296 | fprintf(stderr, "Error: Could not open the ICC profile \"%s\".\n" , processcolorprofilename.c_str()); |
297 | goto err1; |
298 | } |
299 | if (!cmsIsIntentSupported(processcolorprofile.get(), INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_OUTPUT) && !cmsIsIntentSupported(processcolorprofile.get(), INTENT_ABSOLUTE_COLORIMETRIC, LCMS_USED_AS_OUTPUT) |
300 | && !cmsIsIntentSupported(processcolorprofile.get(), INTENT_SATURATION, LCMS_USED_AS_OUTPUT) && !cmsIsIntentSupported(processcolorprofile.get(), INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT)) { |
301 | fprintf(stderr, "Error: ICC profile \"%s\" is not an output profile.\n" , processcolorprofilename.c_str()); |
302 | goto err1; |
303 | } |
304 | profilecolorspace = cmsGetColorSpace(processcolorprofile.get()); |
305 | if (profilecolorspace == cmsSigCmykData) { |
306 | if (!processcolorformatspecified) { |
307 | processcolorformat = splashModeCMYK8; |
308 | processcolorformatspecified = true; |
309 | } else if (processcolorformat != splashModeCMYK8) { |
310 | fprintf(stderr, "Error: Supplied ICC profile \"%s\" is a CMYK profile, but process color format is not CMYK8.\n" , processcolorprofilename.c_str()); |
311 | goto err1; |
312 | } |
313 | } else if (profilecolorspace == cmsSigGrayData) { |
314 | if (!processcolorformatspecified) { |
315 | processcolorformat = splashModeMono8; |
316 | processcolorformatspecified = true; |
317 | } else if (processcolorformat != splashModeMono8) { |
318 | fprintf(stderr, "Error: Supplied ICC profile \"%s\" is a monochrome profile, but process color format is not monochrome.\n" , processcolorprofilename.c_str()); |
319 | goto err1; |
320 | } |
321 | } else if (profilecolorspace == cmsSigRgbData) { |
322 | if (!processcolorformatspecified) { |
323 | processcolorformat = splashModeRGB8; |
324 | processcolorformatspecified = true; |
325 | } else if (processcolorformat != splashModeRGB8) { |
326 | fprintf(stderr, "Error: Supplied ICC profile \"%s\" is a RGB profile, but process color format is not RGB.\n" , processcolorprofilename.c_str()); |
327 | goto err1; |
328 | } |
329 | } |
330 | } |
331 | #endif |
332 | |
333 | if (processcolorformatspecified) { |
334 | if (level1 && processcolorformat != splashModeMono8) { |
335 | fprintf(stderr, format: "Error: Setting -level1 requires -processcolorformat MONO8" ); |
336 | goto err1; |
337 | } else if ((level1Sep || level2Sep || level3Sep || overprint) && processcolorformat != splashModeCMYK8) { |
338 | fprintf(stderr, format: "Error: Setting -level1sep/-level2sep/-level3sep/-overprint requires -processcolorformat CMYK8" ); |
339 | goto err1; |
340 | } |
341 | } |
342 | |
343 | #ifdef USE_CMS |
344 | if (!defaultgrayprofilename.toStr().empty()) { |
345 | defaultgrayprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultgrayprofilename.c_str(), "r" )); |
346 | if (!checkICCProfile(defaultgrayprofile, defaultgrayprofilename.c_str(), LCMS_USED_AS_INPUT, cmsSigGrayData)) { |
347 | goto err1; |
348 | } |
349 | } |
350 | if (!defaultrgbprofilename.toStr().empty()) { |
351 | defaultrgbprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultrgbprofilename.c_str(), "r" )); |
352 | if (!checkICCProfile(defaultrgbprofile, defaultrgbprofilename.c_str(), LCMS_USED_AS_INPUT, cmsSigRgbData)) { |
353 | goto err1; |
354 | } |
355 | } |
356 | if (!defaultcmykprofilename.toStr().empty()) { |
357 | defaultcmykprofile = make_GfxLCMSProfilePtr(cmsOpenProfileFromFile(defaultcmykprofilename.c_str(), "r" )); |
358 | if (!checkICCProfile(defaultcmykprofile, defaultcmykprofilename.c_str(), LCMS_USED_AS_INPUT, cmsSigCmykData)) { |
359 | goto err1; |
360 | } |
361 | } |
362 | #endif |
363 | |
364 | // open PDF file |
365 | if (ownerPassword[0] != '\001') { |
366 | ownerPW = GooString(ownerPassword); |
367 | } |
368 | if (userPassword[0] != '\001') { |
369 | userPW = GooString(userPassword); |
370 | } |
371 | if (fileName->cmp(sA: "-" ) == 0) { |
372 | delete fileName; |
373 | fileName = new GooString("fd://0" ); |
374 | } |
375 | |
376 | doc = PDFDocFactory().createPDFDoc(uri: *fileName, ownerPassword: ownerPW, userPassword: userPW); |
377 | |
378 | if (!doc->isOk()) { |
379 | exitCode = 1; |
380 | goto err1; |
381 | } |
382 | |
383 | #ifdef ENFORCE_PERMISSIONS |
384 | // check for print permission |
385 | if (!doc->okToPrint()) { |
386 | error(errNotAllowed, -1, "Printing this document is not allowed." ); |
387 | exitCode = 3; |
388 | goto err1; |
389 | } |
390 | #endif |
391 | |
392 | // construct PostScript file name |
393 | if (argc == 3) { |
394 | psFileName = std::string(argv[2]); |
395 | } else if (fileName->cmp(sA: "fd://0" ) == 0) { |
396 | error(category: errCommandLine, pos: -1, msg: "You have to provide an output filename when reading from stdin." ); |
397 | goto err1; |
398 | } else { |
399 | const char *p = fileName->c_str() + fileName->getLength() - 4; |
400 | if (!strcmp(s1: p, s2: ".pdf" ) || !strcmp(s1: p, s2: ".PDF" )) { |
401 | psFileName = std::string(fileName->c_str(), fileName->getLength() - 4); |
402 | |
403 | } else { |
404 | psFileName = fileName->toStr(); |
405 | } |
406 | psFileName += (doEPS ? ".eps" : ".ps" ); |
407 | } |
408 | |
409 | // get page range |
410 | if (firstPage < 1) { |
411 | firstPage = 1; |
412 | } |
413 | if (lastPage < 1 || lastPage > doc->getNumPages()) { |
414 | lastPage = doc->getNumPages(); |
415 | } |
416 | if (lastPage < firstPage) { |
417 | 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); |
418 | goto err1; |
419 | } |
420 | |
421 | // check for multi-page EPS or form |
422 | if ((doEPS || doForm) && firstPage != lastPage) { |
423 | error(category: errCommandLine, pos: -1, msg: "EPS and form files can only contain one page." ); |
424 | goto err1; |
425 | } |
426 | |
427 | for (int i = firstPage; i <= lastPage; ++i) { |
428 | pages.push_back(x: i); |
429 | } |
430 | |
431 | // write PostScript file |
432 | psOut = new PSOutputDev(psFileName.c_str(), doc.get(), nullptr, pages, mode, paperWidth, paperHeight, noCrop, duplex, /*imgLLXA*/ 0, /*imgLLYA*/ 0, |
433 | /*imgURXA*/ 0, /*imgURYA*/ 0, psRasterizeWhenNeeded, /*manualCtrlA*/ false, /*customCodeCbkA*/ nullptr, /*customCodeCbkDataA*/ nullptr, level); |
434 | if (noCenter) { |
435 | psOut->setPSCenter(false); |
436 | } |
437 | if (expand) { |
438 | psOut->setPSExpandSmaller(true); |
439 | } |
440 | if (noShrink) { |
441 | psOut->setPSShrinkLarger(false); |
442 | } |
443 | if (overprint) { |
444 | psOut->setOverprintPreview(true); |
445 | } |
446 | |
447 | if (rasterAntialiasStr[0]) { |
448 | if (!GlobalParams::parseYesNo2(token: rasterAntialiasStr, flag: &rasterAntialias)) { |
449 | fprintf(stderr, format: "Bad '-aaRaster' value on command line\n" ); |
450 | } |
451 | } |
452 | |
453 | if (forceRasterizeStr[0]) { |
454 | PSForceRasterize forceRasterize = psRasterizeWhenNeeded; |
455 | if (strcmp(s1: forceRasterizeStr, s2: "whenneeded" ) == 0) { |
456 | forceRasterize = psRasterizeWhenNeeded; |
457 | } else if (strcmp(s1: forceRasterizeStr, s2: "always" ) == 0) { |
458 | forceRasterize = psAlwaysRasterize; |
459 | } else if (strcmp(s1: forceRasterizeStr, s2: "never" ) == 0) { |
460 | forceRasterize = psNeverRasterize; |
461 | } else { |
462 | fprintf(stderr, format: "Bad '-rasterize' value on command line\n" ); |
463 | } |
464 | psOut->setForceRasterize(forceRasterize); |
465 | } |
466 | |
467 | if (splashResolution > 0) { |
468 | psOut->setRasterResolution(splashResolution); |
469 | } |
470 | if (processcolorformatspecified) { |
471 | psOut->setProcessColorFormat(processcolorformat); |
472 | } |
473 | #ifdef USE_CMS |
474 | psOut->setDisplayProfile(processcolorprofile); |
475 | psOut->setDefaultGrayProfile(defaultgrayprofile); |
476 | psOut->setDefaultRGBProfile(defaultrgbprofile); |
477 | psOut->setDefaultCMYKProfile(defaultcmykprofile); |
478 | #endif |
479 | psOut->setEmbedType1(!noEmbedT1Fonts); |
480 | psOut->setEmbedTrueType(!noEmbedTTFonts); |
481 | psOut->setEmbedCIDPostScript(!noEmbedCIDPSFonts); |
482 | psOut->setEmbedCIDTrueType(!noEmbedCIDTTFonts); |
483 | psOut->setFontPassthrough(fontPassthrough); |
484 | psOut->setPreloadImagesForms(preload); |
485 | psOut->setOptimizeColorSpace(optimizeColorSpace); |
486 | psOut->setPassLevel1CustomColor(passLevel1CustomColor); |
487 | #ifdef OPI_SUPPORT |
488 | psOut->setGenerateOPI(doOPI); |
489 | #endif |
490 | psOut->setUseBinary(psBinary); |
491 | |
492 | psOut->setRasterAntialias(rasterAntialias); |
493 | if (psOut->isOk()) { |
494 | for (int i = firstPage; i <= lastPage; ++i) { |
495 | doc->displayPage(out: psOut, page: i, hDPI: 72, vDPI: 72, rotate: 0, useMediaBox: noCrop, crop: !noCrop, printing: true); |
496 | } |
497 | } else { |
498 | delete psOut; |
499 | exitCode = 2; |
500 | goto err1; |
501 | } |
502 | delete psOut; |
503 | |
504 | exitCode = 0; |
505 | |
506 | // clean up |
507 | err1: |
508 | delete fileName; |
509 | err0: |
510 | |
511 | return exitCode; |
512 | } |
513 | |