1 //========================================================================
2 //
3 // pdftocairo.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, 2017-2020 Albert Astals Cid <aacid@kde.org>
22 // Copyright (C) 2010, 2011-2017 Adrian Johnson <ajohnson@redneon.com>
23 // Copyright (C) 2010, 2014 Hib Eris <hib@hiberis.nl>
24 // Copyright (C) 2010 Jonathan Liu <net147@gmail.com>
25 // Copyright (C) 2010 William Bader <williambader@hotmail.com>
26 // Copyright (C) 2011 Thomas Freitag <Thomas.Freitag@alfa.de>
27 // Copyright (C) 2011, 2015 Carlos Garcia Campos <carlosgc@gnome.org>
28 // Copyright (C) 2012 Koji Otani <sho@bbr.jp>
29 // Copyright (C) 2013 Lu Wang <coolwanglu@gmail.com>
30 // Copyright (C) 2013, 2017 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
31 // Copyright (C) 2014 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
32 // Copyright (C) 2016 Jason Crain <jason@aquaticape.us>
33 // Copyright (C) 2018 Martin Packman <gzlist@googlemail.com>
34 // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
35 // Copyright (C) 2019, 2020 Oliver Sander <oliver.sander@tu-dresden.de>
36 // Copyright (C) 2019 Kris Jurka <jurka@ejurka.com>
37 // Copyright (C) 2020, 2021 Oliver Sander <oliver.sander@tu-dresden.de>
38 // Copyright (C) 2020 Philipp Knechtges <philipp-dev@knechtges.com>
39 // Copyright (C) 2020 Salvo Miosi <salvo.ilmiosi@gmail.com>
40 // Copyright (C) 2021 Peter Williams <peter@newton.cx>
41 // Copyright (C) 2021 Christian Persch <chpe@src.gnome.org>
42 //
43 // To see a description of the changes please see the Changelog file that
44 // came with your tarball or type make ChangeLog if you are building from git
45 //
46 //========================================================================
47 
48 #include "config.h"
49 #include <poppler-config.h>
50 #include <cstdint>
51 #include <cstdio>
52 #include <cmath>
53 #include <cstring>
54 #include <fcntl.h>
55 #if defined(_WIN32) || defined(__CYGWIN__)
56 #    include <io.h> // for _setmode
57 #endif
58 #include "parseargs.h"
59 #include "goo/gmem.h"
60 #include "goo/GooString.h"
61 #include "goo/ImgWriter.h"
62 #include "goo/JpegWriter.h"
63 #include "goo/PNGWriter.h"
64 #include "goo/TiffWriter.h"
65 #include "GlobalParams.h"
66 #include "Object.h"
67 #include "PDFDoc.h"
68 #include "PDFDocFactory.h"
69 #include "CairoOutputDev.h"
70 #include "Win32Console.h"
71 #include "numberofcharacters.h"
72 #ifdef USE_CMS
73 #    include <lcms2.h>
74 #endif
75 #include <cairo.h>
76 #ifdef CAIRO_HAS_PS_SURFACE
77 #    include <cairo-ps.h>
78 #endif
79 #ifdef CAIRO_HAS_PDF_SURFACE
80 #    include <cairo-pdf.h>
81 #endif
82 #ifdef CAIRO_HAS_SVG_SURFACE
83 #    include <cairo-svg.h>
84 #endif
85 
86 #include "pdftocairo-win32.h"
87 
88 static bool png = false;
89 static bool jpeg = false;
90 static bool ps = false;
91 static bool eps = false;
92 static bool pdf = false;
93 static bool printToWin32 = false;
94 static bool printdlg = false;
95 static bool svg = false;
96 static bool tiff = false;
97 
98 static int firstPage = 1;
99 static int lastPage = 0;
100 static bool printOnlyOdd = false;
101 static bool printOnlyEven = false;
102 static bool singleFile = false;
103 static double resolution = 0.0;
104 static double x_resolution = 150.0;
105 static double y_resolution = 150.0;
106 static int scaleTo = 0;
107 static int x_scaleTo = 0;
108 static int y_scaleTo = 0;
109 static int crop_x = 0;
110 static int crop_y = 0;
111 static int crop_w = 0;
112 static int crop_h = 0;
113 static int sz = 0;
114 static bool useCropBox = false;
115 static bool mono = false;
116 static bool gray = false;
117 static bool transp = false;
118 static GooString antialias;
119 static GooString icc;
120 
121 static bool level2 = false;
122 static bool level3 = false;
123 static bool origPageSizes = false;
124 static char paperSize[15] = "";
125 static int paperWidth = -1;
126 static int paperHeight = -1;
127 static bool noCrop = false;
128 static bool expand = false;
129 static bool noShrink = false;
130 static bool noCenter = false;
131 static bool duplex = false;
132 static char tiffCompressionStr[16] = "";
133 
134 static char ownerPassword[33] = "";
135 static char userPassword[33] = "";
136 static bool quiet = false;
137 static bool printVersion = false;
138 static bool printHelp = false;
139 
140 static GooString jpegOpt;
141 static int jpegQuality = -1;
142 static bool jpegProgressive = false;
143 static bool jpegOptimize = false;
144 
145 static GooString printer;
146 static GooString printOpt;
147 #ifdef CAIRO_HAS_WIN32_SURFACE
148 static bool setupdlg = false;
149 #endif
150 
151 static const ArgDesc argDesc[] = {
152 #ifdef ENABLE_LIBPNG
153     { "-png", argFlag, &png, 0, "generate a PNG file" },
154 #endif
155 #ifdef ENABLE_LIBJPEG
156     { "-jpeg", argFlag, &jpeg, 0, "generate a JPEG file" },
157     { "-jpegopt", argGooString, &jpegOpt, 0, "jpeg options, with format <opt1>=<val1>[,<optN>=<valN>]*" },
158 #endif
159 #ifdef ENABLE_LIBTIFF
160     { "-tiff", argFlag, &tiff, 0, "generate a TIFF file" },
161     { "-tiffcompression", argString, tiffCompressionStr, sizeof(tiffCompressionStr), "set TIFF compression: none, packbits, jpeg, lzw, deflate" },
162 #endif
163 #ifdef CAIRO_HAS_PS_SURFACE
164     { "-ps", argFlag, &ps, 0, "generate PostScript file" },
165     { "-eps", argFlag, &eps, 0, "generate Encapsulated PostScript (EPS)" },
166 #endif
167 #ifdef CAIRO_HAS_PDF_SURFACE
168     { "-pdf", argFlag, &pdf, 0, "generate a PDF file" },
169 #endif
170 #ifdef CAIRO_HAS_SVG_SURFACE
171     { "-svg", argFlag, &svg, 0, "generate a Scalable Vector Graphics (SVG) file" },
172 #endif
173 #ifdef CAIRO_HAS_WIN32_SURFACE
174     { "-print", argFlag, &printToWin32, 0, "print to a Windows printer" },
175     { "-printdlg", argFlag, &printdlg, 0, "show Windows print dialog and print" },
176     { "-printer", argGooString, &printer, 0, "printer name or use default if this option is not specified" },
177     { "-printopt", argGooString, &printOpt, 0, "printer options, with format <opt1>=<val1>[,<optN>=<valN>]*" },
178     { "-setupdlg", argFlag, &setupdlg, 0, "show printer setup dialog before printing" },
179 #endif
180 
181     { "-f", argInt, &firstPage, 0, "first page to print" },
182     { "-l", argInt, &lastPage, 0, "last page to print" },
183     { "-o", argFlag, &printOnlyOdd, 0, "print only odd pages" },
184     { "-e", argFlag, &printOnlyEven, 0, "print only even pages" },
185     { "-singlefile", argFlag, &singleFile, 0, "write only the first page and do not add digits" },
186 
187     { "-r", argFP, &resolution, 0, "resolution, in PPI (default is 150)" },
188     { "-rx", argFP, &x_resolution, 0, "X resolution, in PPI (default is 150)" },
189     { "-ry", argFP, &y_resolution, 0, "Y resolution, in PPI (default is 150)" },
190     { "-scale-to", argInt, &scaleTo, 0, "scales each page to fit within scale-to*scale-to pixel box" },
191     { "-scale-to-x", argInt, &x_scaleTo, 0, "scales each page horizontally to fit in scale-to-x pixels" },
192     { "-scale-to-y", argInt, &y_scaleTo, 0, "scales each page vertically to fit in scale-to-y pixels" },
193 
194     { "-x", argInt, &crop_x, 0, "x-coordinate of the crop area top left corner" },
195     { "-y", argInt, &crop_y, 0, "y-coordinate of the crop area top left corner" },
196     { "-W", argInt, &crop_w, 0, "width of crop area in pixels (default is 0)" },
197     { "-H", argInt, &crop_h, 0, "height of crop area in pixels (default is 0)" },
198     { "-sz", argInt, &sz, 0, "size of crop square in pixels (sets W and H)" },
199     { "-cropbox", argFlag, &useCropBox, 0, "use the crop box rather than media box" },
200 
201     { "-mono", argFlag, &mono, 0, "generate a monochrome image file (PNG, JPEG)" },
202     { "-gray", argFlag, &gray, 0, "generate a grayscale image file (PNG, JPEG)" },
203     { "-transp", argFlag, &transp, 0, "use a transparent background instead of white (PNG)" },
204     { "-antialias", argGooString, &antialias, 0, "set cairo antialias option" },
205 #ifdef USE_CMS
206     { "-icc", argGooString, &icc, 0, "ICC color profile to use" },
207 #endif
208 
209     { "-level2", argFlag, &level2, 0, "generate Level 2 PostScript (PS, EPS)" },
210     { "-level3", argFlag, &level3, 0, "generate Level 3 PostScript (PS, EPS)" },
211     { "-origpagesizes", argFlag, &origPageSizes, 0, "conserve original page sizes (PS, PDF, SVG)" },
212     { "-paper", argString, paperSize, sizeof(paperSize), "paper size (letter, legal, A4, A3, match)" },
213     { "-paperw", argInt, &paperWidth, 0, "paper width, in points" },
214     { "-paperh", argInt, &paperHeight, 0, "paper height, in points" },
215     { "-nocrop", argFlag, &noCrop, 0, "don't crop pages to CropBox" },
216     { "-expand", argFlag, &expand, 0, "expand pages smaller than the paper size" },
217     { "-noshrink", argFlag, &noShrink, 0, "don't shrink pages larger than the paper size" },
218     { "-nocenter", argFlag, &noCenter, 0, "don't center pages smaller than the paper size" },
219     { "-duplex", argFlag, &duplex, 0, "enable duplex printing" },
220 
221     { "-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)" },
222     { "-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)" },
223 
224     { "-q", argFlag, &quiet, 0, "don't print any messages or errors" },
225     { "-v", argFlag, &printVersion, 0, "print copyright and version info" },
226     { "-h", argFlag, &printHelp, 0, "print usage information" },
227     { "-help", argFlag, &printHelp, 0, "print usage information" },
228     { "--help", argFlag, &printHelp, 0, "print usage information" },
229     { "-?", argFlag, &printHelp, 0, "print usage information" },
230     {}
231 };
232 
233 static cairo_surface_t *surface;
234 static bool printing;
235 static FILE *output_file;
236 static bool usePDFPageSize;
237 static cairo_antialias_t antialiasEnum = CAIRO_ANTIALIAS_DEFAULT;
238 
239 #ifdef USE_CMS
240 static unsigned char *icc_data;
241 static int icc_data_size;
242 static GfxLCMSProfilePtr profile;
243 #endif
244 
245 struct AntialiasOption
246 {
247     const char *name;
248     cairo_antialias_t value;
249 };
250 
251 static const AntialiasOption antialiasOptions[] = {
252     { "default", CAIRO_ANTIALIAS_DEFAULT }, { "none", CAIRO_ANTIALIAS_NONE }, { "gray", CAIRO_ANTIALIAS_GRAY }, { "subpixel", CAIRO_ANTIALIAS_SUBPIXEL },
253     { "fast", CAIRO_ANTIALIAS_FAST },       { "good", CAIRO_ANTIALIAS_GOOD }, { "best", CAIRO_ANTIALIAS_BEST }, { nullptr, CAIRO_ANTIALIAS_DEFAULT },
254 };
255 
parseAntialiasOption()256 static bool parseAntialiasOption()
257 {
258     const AntialiasOption *option = antialiasOptions;
259     while (option->name) {
260         if (antialias.cmp(option->name) == 0) {
261             antialiasEnum = option->value;
262             return true;
263         }
264         option++;
265     }
266 
267     fprintf(stderr, "Error: Invalid antialias option \"%s\"\n", antialias.c_str());
268     fprintf(stderr, "Valid options are:\n");
269     option = antialiasOptions;
270     while (option->name) {
271         fprintf(stderr, "  %s\n", option->name);
272         option++;
273     }
274     return false;
275 }
276 
parseJpegOptions()277 static bool parseJpegOptions()
278 {
279     // jpegOpt format is: <opt1>=<val1>,<opt2>=<val2>,...
280     const char *nextOpt = jpegOpt.c_str();
281     while (nextOpt && *nextOpt) {
282         const char *comma = strchr(nextOpt, ',');
283         GooString opt;
284         if (comma) {
285             opt.Set(nextOpt, comma - nextOpt);
286             nextOpt = comma + 1;
287         } else {
288             opt.Set(nextOpt);
289             nextOpt = nullptr;
290         }
291         // here opt is "<optN>=<valN> "
292         const char *equal = strchr(opt.c_str(), '=');
293         if (!equal) {
294             fprintf(stderr, "Unknown jpeg option \"%s\"\n", opt.c_str());
295             return false;
296         }
297         int iequal = equal - opt.c_str();
298         GooString value(&opt, iequal + 1, opt.getLength() - iequal - 1);
299         opt.del(iequal, opt.getLength() - iequal);
300         // here opt is "<optN>" and value is "<valN>"
301 
302         if (opt.cmp("quality") == 0) {
303             if (!isInt(value.c_str())) {
304                 fprintf(stderr, "Invalid jpeg quality\n");
305                 return false;
306             }
307             jpegQuality = atoi(value.c_str());
308             if (jpegQuality < 0 || jpegQuality > 100) {
309                 fprintf(stderr, "jpeg quality must be between 0 and 100\n");
310                 return false;
311             }
312         } else if (opt.cmp("progressive") == 0) {
313             jpegProgressive = false;
314             if (value.cmp("y") == 0) {
315                 jpegProgressive = true;
316             } else if (value.cmp("n") != 0) {
317                 fprintf(stderr, "jpeg progressive option must be \"y\" or \"n\"\n");
318                 return false;
319             }
320         } else if (opt.cmp("optimize") == 0 || opt.cmp("optimise") == 0) {
321             jpegOptimize = false;
322             if (value.cmp("y") == 0) {
323                 jpegOptimize = true;
324             } else if (value.cmp("n") != 0) {
325                 fprintf(stderr, "jpeg optimize option must be \"y\" or \"n\"\n");
326                 return false;
327             }
328         } else {
329             fprintf(stderr, "Unknown jpeg option \"%s\"\n", opt.c_str());
330             return false;
331         }
332     }
333     return true;
334 }
335 
writePageImage(GooString * filename)336 static void writePageImage(GooString *filename)
337 {
338     ImgWriter *writer = nullptr;
339     FILE *file;
340     int height, width, stride;
341     unsigned char *data;
342 
343     if (png) {
344 #ifdef ENABLE_LIBPNG
345         if (transp)
346             writer = new PNGWriter(PNGWriter::RGBA);
347         else if (gray)
348             writer = new PNGWriter(PNGWriter::GRAY);
349         else if (mono)
350             writer = new PNGWriter(PNGWriter::MONOCHROME);
351         else
352             writer = new PNGWriter(PNGWriter::RGB);
353 
354 #    ifdef USE_CMS
355         if (icc_data) {
356             cmsUInt8Number profileID[17];
357             profileID[16] = '\0';
358 
359             cmsGetHeaderProfileID(profile.get(), profileID);
360             static_cast<PNGWriter *>(writer)->setICCProfile(reinterpret_cast<char *>(profileID), icc_data, icc_data_size);
361         } else {
362             static_cast<PNGWriter *>(writer)->setSRGBProfile();
363         }
364 #    endif
365 #endif
366 
367     } else if (jpeg) {
368 #ifdef ENABLE_LIBJPEG
369         if (gray)
370             writer = new JpegWriter(JpegWriter::GRAY);
371         else
372             writer = new JpegWriter(JpegWriter::RGB);
373 
374         static_cast<JpegWriter *>(writer)->setOptimize(jpegOptimize);
375         static_cast<JpegWriter *>(writer)->setProgressive(jpegProgressive);
376         if (jpegQuality >= 0)
377             static_cast<JpegWriter *>(writer)->setQuality(jpegQuality);
378 #endif
379     } else if (tiff) {
380 #ifdef ENABLE_LIBTIFF
381         if (transp)
382             writer = new TiffWriter(TiffWriter::RGBA_PREMULTIPLIED);
383         else if (gray)
384             writer = new TiffWriter(TiffWriter::GRAY);
385         else if (mono)
386             writer = new TiffWriter(TiffWriter::MONOCHROME);
387         else
388             writer = new TiffWriter(TiffWriter::RGB);
389         static_cast<TiffWriter *>(writer)->setCompressionString(tiffCompressionStr);
390 #endif
391     }
392     if (!writer)
393         return;
394 
395     if (filename->cmp("fd://0") == 0) {
396 #if defined(_WIN32) || defined(__CYGWIN__)
397         _setmode(fileno(stdout), O_BINARY);
398 #endif
399         file = stdout;
400     } else
401         file = fopen(filename->c_str(), "wb");
402 
403     if (!file) {
404         fprintf(stderr, "Error opening output file %s\n", filename->c_str());
405         exit(2);
406     }
407 
408     height = cairo_image_surface_get_height(surface);
409     width = cairo_image_surface_get_width(surface);
410     stride = cairo_image_surface_get_stride(surface);
411     cairo_surface_flush(surface);
412     data = cairo_image_surface_get_data(surface);
413 
414     if (!writer->init(file, width, height, x_resolution, y_resolution)) {
415         fprintf(stderr, "Error writing %s\n", filename->c_str());
416         exit(2);
417     }
418     unsigned char *row = (unsigned char *)gmallocn(width, 4);
419 
420     for (int y = 0; y < height; y++) {
421         uint32_t *pixel = reinterpret_cast<uint32_t *>((data + y * stride));
422         unsigned char *rowp = row;
423         int bit = 7;
424         for (int x = 0; x < width; x++, pixel++) {
425             if (transp) {
426                 if (tiff) {
427                     // RGBA premultipled format
428                     *rowp++ = (*pixel & 0xff0000) >> 16;
429                     *rowp++ = (*pixel & 0x00ff00) >> 8;
430                     *rowp++ = (*pixel & 0x0000ff) >> 0;
431                     *rowp++ = (*pixel & 0xff000000) >> 24;
432                 } else {
433                     // unpremultiply into RGBA format
434                     uint8_t a;
435                     a = (*pixel & 0xff000000) >> 24;
436                     if (a == 0) {
437                         *rowp++ = 0;
438                         *rowp++ = 0;
439                         *rowp++ = 0;
440                     } else {
441                         *rowp++ = (((*pixel & 0xff0000) >> 16) * 255 + a / 2) / a;
442                         *rowp++ = (((*pixel & 0x00ff00) >> 8) * 255 + a / 2) / a;
443                         *rowp++ = (((*pixel & 0x0000ff) >> 0) * 255 + a / 2) / a;
444                     }
445                     *rowp++ = a;
446                 }
447             } else if (gray || mono) {
448                 // convert to gray
449                 // The PDF Reference specifies the DeviceRGB to DeviceGray conversion as
450                 // gray = 0.3*red + 0.59*green + 0.11*blue
451                 const int r = (*pixel & 0x00ff0000) >> 16;
452                 const int g = (*pixel & 0x0000ff00) >> 8;
453                 const int b = (*pixel & 0x000000ff) >> 0;
454                 // an arbitrary integer approximation of .3*r + .59*g + .11*b
455                 const int grayValue = (r * 19661 + g * 38666 + b * 7209 + 32829) >> 16;
456                 if (mono) {
457                     if (bit == 7)
458                         *rowp = 0;
459                     if (grayValue > 127)
460                         *rowp |= (1 << bit);
461                     bit--;
462                     if (bit < 0) {
463                         bit = 7;
464                         rowp++;
465                     }
466                 } else {
467                     *rowp++ = grayValue;
468                 }
469             } else {
470                 // copy into RGB format
471                 *rowp++ = (*pixel & 0x00ff0000) >> 16;
472                 *rowp++ = (*pixel & 0x0000ff00) >> 8;
473                 *rowp++ = (*pixel & 0x000000ff) >> 0;
474             }
475         }
476         writer->writeRow(&row);
477     }
478     gfree(row);
479     writer->close();
480     delete writer;
481     if (file == stdout)
482         fflush(file);
483     else
484         fclose(file);
485 }
486 
getCropSize(double page_w,double page_h,double * width,double * height)487 static void getCropSize(double page_w, double page_h, double *width, double *height)
488 {
489     int w = crop_w;
490     int h = crop_h;
491 
492     if (w == 0)
493         w = (int)ceil(page_w);
494 
495     if (h == 0)
496         h = (int)ceil(page_h);
497 
498     *width = (crop_x + w > page_w ? (int)ceil(page_w - crop_x) : w);
499     *height = (crop_y + h > page_h ? (int)ceil(page_h - crop_y) : h);
500 }
501 
getOutputSize(double page_w,double page_h,double * width,double * height)502 static void getOutputSize(double page_w, double page_h, double *width, double *height)
503 {
504 
505     if (printing) {
506         if (usePDFPageSize) {
507             *width = page_w;
508             *height = page_h;
509         } else {
510             if (page_w > page_h) {
511                 *width = paperHeight;
512                 *height = paperWidth;
513             } else {
514                 *width = paperWidth;
515                 *height = paperHeight;
516             }
517         }
518     } else {
519         getCropSize(page_w * (x_resolution / 72.0), page_h * (y_resolution / 72.0), width, height);
520     }
521 }
522 
getFitToPageTransform(double page_w,double page_h,double paper_w,double paper_h,cairo_matrix_t * m)523 static void getFitToPageTransform(double page_w, double page_h, double paper_w, double paper_h, cairo_matrix_t *m)
524 {
525     double x_scale, y_scale, scale;
526 
527     x_scale = paper_w / page_w;
528     y_scale = paper_h / page_h;
529     if (x_scale < y_scale)
530         scale = x_scale;
531     else
532         scale = y_scale;
533 
534     if (scale > 1.0 && !expand)
535         scale = 1.0;
536     if (scale < 1.0 && noShrink)
537         scale = 1.0;
538 
539     cairo_matrix_init_identity(m);
540     if (!noCenter) {
541         // centre page
542         cairo_matrix_translate(m, (paper_w - page_w * scale) / 2, (paper_h - page_h * scale) / 2);
543     } else if (!svg) {
544         // move to PostScript origin
545         cairo_matrix_translate(m, 0, (paper_h - page_h * scale));
546     }
547     cairo_matrix_scale(m, scale, scale);
548 }
549 
writeStream(void * closure,const unsigned char * data,unsigned int length)550 static cairo_status_t writeStream(void *closure, const unsigned char *data, unsigned int length)
551 {
552     FILE *file = (FILE *)closure;
553 
554     if (fwrite(data, length, 1, file) == 1)
555         return CAIRO_STATUS_SUCCESS;
556     else
557         return CAIRO_STATUS_WRITE_ERROR;
558 }
559 
beginDocument(GooString * inputFileName,GooString * outputFileName,double w,double h)560 static void beginDocument(GooString *inputFileName, GooString *outputFileName, double w, double h)
561 {
562     if (printing) {
563         if (printToWin32) {
564             output_file = nullptr;
565         } else {
566             if (outputFileName->cmp("fd://0") == 0) {
567 #if defined(_WIN32) || defined(__CYGWIN__)
568                 _setmode(fileno(stdout), O_BINARY);
569 #endif
570                 output_file = stdout;
571             } else {
572                 output_file = fopen(outputFileName->c_str(), "wb");
573                 if (!output_file) {
574                     fprintf(stderr, "Error opening output file %s\n", outputFileName->c_str());
575                     exit(2);
576                 }
577             }
578         }
579 
580         if (ps || eps) {
581 #ifdef CAIRO_HAS_PS_SURFACE
582             surface = cairo_ps_surface_create_for_stream(writeStream, output_file, w, h);
583             if (level2)
584                 cairo_ps_surface_restrict_to_level(surface, CAIRO_PS_LEVEL_2);
585             if (eps)
586                 cairo_ps_surface_set_eps(surface, 1);
587             if (duplex) {
588                 cairo_ps_surface_dsc_comment(surface, "%%Requirements: duplex");
589                 cairo_ps_surface_dsc_begin_setup(surface);
590                 cairo_ps_surface_dsc_comment(surface, "%%IncludeFeature: *Duplex DuplexNoTumble");
591             }
592             cairo_ps_surface_dsc_begin_page_setup(surface);
593 #endif
594         } else if (pdf) {
595 #ifdef CAIRO_HAS_PDF_SURFACE
596             surface = cairo_pdf_surface_create_for_stream(writeStream, output_file, w, h);
597 #endif
598         } else if (svg) {
599 #ifdef CAIRO_HAS_SVG_SURFACE
600             surface = cairo_svg_surface_create_for_stream(writeStream, output_file, w, h);
601             cairo_svg_surface_restrict_to_version(surface, CAIRO_SVG_VERSION_1_2);
602 #endif
603         }
604 #ifdef CAIRO_HAS_WIN32_SURFACE
605         if (printToWin32)
606             surface = win32BeginDocument(inputFileName, outputFileName);
607 #endif
608     }
609 }
610 
beginPage(double * w,double * h)611 static void beginPage(double *w, double *h)
612 {
613     if (printing) {
614         if (ps || eps) {
615 #ifdef CAIRO_HAS_PS_SURFACE
616             if (*w > *h) {
617                 cairo_ps_surface_dsc_comment(surface, "%%PageOrientation: Landscape");
618                 cairo_ps_surface_set_size(surface, *h, *w);
619             } else {
620                 cairo_ps_surface_dsc_comment(surface, "%%PageOrientation: Portrait");
621                 cairo_ps_surface_set_size(surface, *w, *h);
622             }
623 #endif
624         }
625 
626 #ifdef CAIRO_HAS_PDF_SURFACE
627         if (pdf)
628             cairo_pdf_surface_set_size(surface, *w, *h);
629 #endif
630 
631 #ifdef CAIRO_HAS_WIN32_SURFACE
632         if (printToWin32) {
633             bool changePageSize = true;
634             if (setupdlg && !origPageSizes)
635                 changePageSize = false;
636             win32BeginPage(w, h, changePageSize, noShrink); // w,h will be changed to actual size used
637         }
638 #endif
639 
640         cairo_surface_set_fallback_resolution(surface, x_resolution, y_resolution);
641 
642     } else {
643         surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ceil(*w), ceil(*h));
644     }
645 }
646 
renderPage(PDFDoc * doc,CairoOutputDev * cairoOut,int pg,double page_w,double page_h,double output_w,double output_h)647 static void renderPage(PDFDoc *doc, CairoOutputDev *cairoOut, int pg, double page_w, double page_h, double output_w, double output_h)
648 {
649     cairo_t *cr;
650     cairo_status_t status;
651     cairo_matrix_t m;
652     cairo_font_options_t *font_options;
653 
654     cr = cairo_create(surface);
655 
656     cairo_set_antialias(cr, antialiasEnum);
657 
658     font_options = cairo_font_options_create();
659     cairo_get_font_options(cr, font_options);
660     cairo_font_options_set_antialias(font_options, antialiasEnum);
661     cairo_set_font_options(cr, font_options);
662     cairo_font_options_destroy(font_options);
663 
664     cairoOut->setCairo(cr);
665     cairoOut->setPrinting(printing);
666 
667     cairo_save(cr);
668     if (ps && output_w > output_h) {
669         // rotate 90 deg for landscape
670         cairo_translate(cr, 0, output_w);
671         cairo_matrix_init(&m, 0, -1, 1, 0, 0, 0);
672         cairo_transform(cr, &m);
673     }
674     cairo_translate(cr, -crop_x, -crop_y);
675     if (printing) {
676         double cropped_w, cropped_h;
677         getCropSize(page_w, page_h, &cropped_w, &cropped_h);
678         getFitToPageTransform(cropped_w, cropped_h, output_w, output_h, &m);
679         cairo_transform(cr, &m);
680         cairo_rectangle(cr, crop_x, crop_y, cropped_w, cropped_h);
681         cairo_clip(cr);
682     } else {
683         cairo_scale(cr, x_resolution / 72.0, y_resolution / 72.0);
684     }
685     doc->displayPageSlice(cairoOut, pg, 72.0, 72.0, 0, /* rotate */
686                           !useCropBox, /* useMediaBox */
687                           false, /* Crop */
688                           printing, -1, -1, -1, -1);
689     cairo_restore(cr);
690     cairoOut->setCairo(nullptr);
691 
692     // Blend onto white page
693     if (!printing && !transp) {
694         cairo_save(cr);
695         cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER);
696         cairo_set_source_rgb(cr, 1, 1, 1);
697         cairo_paint(cr);
698         cairo_restore(cr);
699     }
700 
701     status = cairo_status(cr);
702     if (status)
703         fprintf(stderr, "cairo error: %s\n", cairo_status_to_string(status));
704     cairo_destroy(cr);
705 }
706 
endPage(GooString * imageFileName)707 static void endPage(GooString *imageFileName)
708 {
709     cairo_status_t status;
710 
711     if (printing) {
712         cairo_surface_show_page(surface);
713 
714 #ifdef CAIRO_HAS_WIN32_SURFACE
715         if (printToWin32)
716             win32EndPage(imageFileName);
717 #endif
718 
719     } else {
720         writePageImage(imageFileName);
721         cairo_surface_finish(surface);
722         status = cairo_surface_status(surface);
723         if (status)
724             fprintf(stderr, "cairo error: %s\n", cairo_status_to_string(status));
725         cairo_surface_destroy(surface);
726     }
727 }
728 
endDocument()729 static void endDocument()
730 {
731     cairo_status_t status;
732 
733     if (printing) {
734         cairo_surface_finish(surface);
735         status = cairo_surface_status(surface);
736         if (status)
737             fprintf(stderr, "cairo error: %s\n", cairo_status_to_string(status));
738         cairo_surface_destroy(surface);
739 #ifdef CAIRO_HAS_WIN32_SURFACE
740         if (printToWin32)
741             win32EndDocument();
742 #endif
743         if (output_file)
744             fclose(output_file);
745     }
746 }
747 
setPSPaperSize(char * size,int & psPaperWidth,int & psPaperHeight)748 static bool setPSPaperSize(char *size, int &psPaperWidth, int &psPaperHeight)
749 {
750     if (!strcmp(size, "match")) {
751         psPaperWidth = psPaperHeight = -1;
752     } else if (!strcmp(size, "letter")) {
753         psPaperWidth = 612;
754         psPaperHeight = 792;
755     } else if (!strcmp(size, "legal")) {
756         psPaperWidth = 612;
757         psPaperHeight = 1008;
758     } else if (!strcmp(size, "A4")) {
759         psPaperWidth = 595;
760         psPaperHeight = 842;
761     } else if (!strcmp(size, "A3")) {
762         psPaperWidth = 842;
763         psPaperHeight = 1190;
764     } else {
765         return false;
766     }
767     return true;
768 }
769 
getImageFileName(GooString * outputFileName,int numDigits,int page)770 static GooString *getImageFileName(GooString *outputFileName, int numDigits, int page)
771 {
772     char buf[10];
773     GooString *imageName = new GooString(outputFileName);
774     if (!singleFile) {
775         snprintf(buf, sizeof(buf), "-%0*d", numDigits, page);
776         imageName->append(buf);
777     }
778     if (outputFileName->cmp("fd://0") != 0) {
779         if (png)
780             imageName->append(".png");
781         else if (jpeg)
782             imageName->append(".jpg");
783         else if (tiff)
784             imageName->append(".tif");
785     }
786 
787     return imageName;
788 }
789 
790 // If (printing || singleFile) the output file name includes the
791 // extension. Otherwise it is the file name base.
getOutputFileName(GooString * fileName,GooString * outputName)792 static GooString *getOutputFileName(GooString *fileName, GooString *outputName)
793 {
794     GooString *name;
795 
796     if (outputName) {
797         if (outputName->cmp("-") == 0) {
798             if (printToWin32 || (!printing && !singleFile)) {
799                 fprintf(stderr, "Error: stdout may only be used with the ps, eps, pdf, svg output options or if -singlefile is used.\n");
800                 exit(99);
801             }
802             return new GooString("fd://0");
803         }
804         return new GooString(outputName);
805     }
806 
807     if (printToWin32)
808         return nullptr; // No output file means print to printer
809 
810     if (fileName->cmp("fd://0") == 0) {
811         fprintf(stderr, "Error: an output filename or '-' must be supplied when the PDF file is stdin.\n");
812         exit(99);
813     }
814 
815     // be careful not to overwrite the input file when the output format is PDF
816     if (pdf && fileName->cmpN("http://", 7) != 0 && fileName->cmpN("https://", 8) != 0) {
817         fprintf(stderr, "Error: an output filename or '-' must be supplied when the output format is PDF and input PDF file is a local file.\n");
818         exit(99);
819     }
820 
821     // strip everything up to last '/'
822     const char *s = fileName->c_str();
823     const char *p = strrchr(s, '/');
824     if (p) {
825         p++;
826         if (*p == 0) {
827             fprintf(stderr, "Error: invalid output filename.\n");
828             exit(99);
829         }
830         name = new GooString(p);
831     } else {
832         name = new GooString(s);
833     }
834 
835     // remove .pdf extension
836     p = strrchr(name->c_str(), '.');
837     if (p && strcasecmp(p, ".pdf") == 0) {
838         GooString *name2 = new GooString(name->c_str(), name->getLength() - 4);
839         delete name;
840         name = name2;
841     }
842 
843     // append new extension
844     if (ps)
845         name->append(".ps");
846     else if (eps)
847         name->append(".eps");
848     else if (pdf)
849         name->append(".pdf");
850     else if (svg)
851         name->append(".svg");
852 
853     return name;
854 }
855 
checkInvalidPrintOption(bool option,const char * option_name)856 static void checkInvalidPrintOption(bool option, const char *option_name)
857 {
858     if (option) {
859         fprintf(stderr, "Error: %s may only be used with the -png, -jpeg, or -tiff output options.\n", option_name);
860         exit(99);
861     }
862 }
863 
checkInvalidImageOption(bool option,const char * option_name)864 static void checkInvalidImageOption(bool option, const char *option_name)
865 {
866     if (option) {
867         fprintf(stderr, "Error: %s may only be used with the -ps, -eps, -pdf, or -svg output options.\n", option_name);
868         exit(99);
869     }
870 }
871 
main(int argc,char * argv[])872 int main(int argc, char *argv[])
873 {
874     GooString *fileName = nullptr;
875     GooString *outputName = nullptr;
876     GooString *outputFileName = nullptr;
877     GooString *imageFileName = nullptr;
878     GooString *ownerPW, *userPW;
879     CairoOutputDev *cairoOut;
880     int pg, pg_num_len;
881     double pg_w, pg_h, tmp, output_w, output_h;
882     int num_outputs;
883 
884     // parse args
885     Win32Console win32Console(&argc, &argv);
886     if (!parseArgs(argDesc, &argc, argv)) {
887         printUsage("pdftocairo", nullptr, argDesc);
888         exit(99);
889     }
890 
891     if (resolution != 0.0 && (x_resolution == 150.0 || y_resolution == 150.0)) {
892         x_resolution = resolution;
893         y_resolution = resolution;
894     }
895     if (argc < 2 || argc > 3 || printVersion || printHelp) {
896         fprintf(stderr, "pdftocairo version %s\n", PACKAGE_VERSION);
897         fprintf(stderr, "%s\n", popplerCopyright);
898         fprintf(stderr, "%s\n", xpdfCopyright);
899         if (!printVersion) {
900             printUsage("pdftocairo", "<PDF-file> [<output-file>]", argDesc);
901         }
902         if (printVersion || printHelp)
903             exit(0);
904         else
905             exit(99);
906     }
907 
908     num_outputs = (png ? 1 : 0) + (jpeg ? 1 : 0) + (tiff ? 1 : 0) + (ps ? 1 : 0) + (eps ? 1 : 0) + (pdf ? 1 : 0) + (printToWin32 ? 1 : 0) + (printdlg ? 1 : 0) + (svg ? 1 : 0);
909     if (num_outputs == 0) {
910         fprintf(stderr, "Error: one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -print, -printdlg, -svg) must be used.\n");
911         exit(99);
912     }
913     if (num_outputs > 1) {
914         fprintf(stderr, "Error: use only one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -printdlg, -print, -svg).\n");
915         exit(99);
916     }
917     if (png || jpeg || tiff)
918         printing = false;
919     else
920         printing = true;
921 
922     if (printing) {
923         checkInvalidPrintOption(mono, "-mono");
924         checkInvalidPrintOption(gray, "-gray");
925         checkInvalidPrintOption(transp, "-transp");
926         checkInvalidPrintOption(icc.c_str()[0], "-icc");
927         checkInvalidPrintOption(singleFile, "-singlefile");
928         checkInvalidPrintOption(useCropBox, "-cropbox");
929         checkInvalidPrintOption(scaleTo != 0, "-scale-to");
930         checkInvalidPrintOption(x_scaleTo != 0, "-scale-to-x");
931         checkInvalidPrintOption(y_scaleTo != 0, "-scale-to-y");
932     } else {
933         checkInvalidImageOption(level2, "-level2");
934         checkInvalidImageOption(level3, "-level3");
935         checkInvalidImageOption(origPageSizes, "-origpagesizes");
936         checkInvalidImageOption(paperSize[0], "-paper");
937         checkInvalidImageOption(paperWidth > 0, "-paperw");
938         checkInvalidImageOption(paperHeight > 0, "-paperh");
939         checkInvalidImageOption(noCrop, "-nocrop");
940         checkInvalidImageOption(expand, "-expand");
941         checkInvalidImageOption(noShrink, "-noshrink");
942         checkInvalidImageOption(noCenter, "-nocenter");
943         checkInvalidImageOption(duplex, "-duplex");
944     }
945 
946     if (printing)
947         useCropBox = !noCrop;
948 
949     if (icc.c_str()[0] && !png) {
950         fprintf(stderr, "Error: -icc may only be used with png output.\n");
951         exit(99);
952     }
953 
954     if (antialias.getLength() > 0) {
955         if (!parseAntialiasOption())
956             exit(99);
957     }
958 
959     if (transp && !(png || tiff)) {
960         fprintf(stderr, "Error: -transp may only be used with png or tiff output.\n");
961         exit(99);
962     }
963 
964     if (mono && gray) {
965         fprintf(stderr, "Error: -mono and -gray may not be used together.\n");
966         exit(99);
967     }
968 
969     if (mono && !(png || tiff)) {
970         fprintf(stderr, "Error: -mono may only be used with png or tiff output.\n");
971         exit(99);
972     }
973 
974     if (jpegOpt.getLength() > 0) {
975         if (!jpeg) {
976             fprintf(stderr, "Error: -jpegopt may only be used with jpeg output.\n");
977             exit(99);
978         }
979         if (!parseJpegOptions())
980             exit(99);
981     }
982 
983     if (strlen(tiffCompressionStr) > 0 && !tiff) {
984         fprintf(stderr, "Error: -tiffcompression may only be used with tiff output.\n");
985         exit(99);
986     }
987 
988     if (level2 && level3) {
989         fprintf(stderr, "Error: use only one of the 'level' options.\n");
990         exit(99);
991     }
992     if (!level2 && !level3)
993         level3 = true;
994 
995     if (eps && (origPageSizes || paperSize[0] || paperWidth > 0 || paperHeight > 0)) {
996         fprintf(stderr, "Error: page size options may not be used with eps output.\n");
997         exit(99);
998     }
999 
1000     if ((paperWidth > 0 && paperHeight <= 0) || (paperWidth <= 0 && paperHeight > 0)) {
1001         fprintf(stderr, "Error: both -paperw and -paperh must be specified.\n");
1002         exit(99);
1003     }
1004 
1005     if (paperSize[0]) {
1006         if (origPageSizes) {
1007             fprintf(stderr, "Error: -origpagesizes and -paper may not be used together.\n");
1008             exit(99);
1009         }
1010         if (!setPSPaperSize(paperSize, paperWidth, paperHeight)) {
1011             fprintf(stderr, "Invalid paper size\n");
1012             exit(99);
1013         }
1014     }
1015     if (origPageSizes || paperWidth < 0 || paperHeight < 0)
1016         usePDFPageSize = true;
1017     else
1018         usePDFPageSize = false;
1019 
1020     if (printdlg)
1021         printToWin32 = true;
1022 
1023     globalParams = std::make_unique<GlobalParams>();
1024     if (quiet) {
1025         globalParams->setErrQuiet(quiet);
1026     }
1027 
1028     // open PDF file
1029     if (ownerPassword[0]) {
1030         ownerPW = new GooString(ownerPassword);
1031     } else {
1032         ownerPW = nullptr;
1033     }
1034     if (userPassword[0]) {
1035         userPW = new GooString(userPassword);
1036     } else {
1037         userPW = nullptr;
1038     }
1039 
1040     fileName = new GooString(argv[1]);
1041     if (fileName->cmp("-") == 0) {
1042         delete fileName;
1043         fileName = new GooString("fd://0");
1044     }
1045     if (argc == 3)
1046         outputName = new GooString(argv[2]);
1047     else
1048         outputName = nullptr;
1049 
1050     outputFileName = getOutputFileName(fileName, outputName);
1051 
1052 #ifdef USE_CMS
1053     icc_data = nullptr;
1054     if (icc.c_str()[0]) {
1055         FILE *file = fopen(icc.c_str(), "rb");
1056         if (!file) {
1057             fprintf(stderr, "Error: unable to open icc profile %s\n", icc.c_str());
1058             exit(4);
1059         }
1060         fseek(file, 0, SEEK_END);
1061         icc_data_size = ftell(file);
1062         fseek(file, 0, SEEK_SET);
1063         icc_data = (unsigned char *)gmalloc(icc_data_size);
1064         if (fread(icc_data, icc_data_size, 1, file) != 1) {
1065             fprintf(stderr, "Error: unable to read icc profile %s\n", icc.c_str());
1066             exit(4);
1067         }
1068         fclose(file);
1069         profile = make_GfxLCMSProfilePtr(cmsOpenProfileFromMem(icc_data, icc_data_size));
1070         if (!profile) {
1071             fprintf(stderr, "Error: lcms error opening profile\n");
1072             exit(4);
1073         }
1074     } else {
1075         profile = make_GfxLCMSProfilePtr(cmsCreate_sRGBProfile());
1076     }
1077 #endif
1078 
1079     std::unique_ptr<PDFDoc> doc = PDFDocFactory().createPDFDoc(*fileName, ownerPW, userPW);
1080     if (!doc->isOk()) {
1081         fprintf(stderr, "Error opening PDF file.\n");
1082         exit(1);
1083     }
1084 
1085 #ifdef ENFORCE_PERMISSIONS
1086     // check for print permission
1087     if (printing && !doc->okToPrint()) {
1088         fprintf(stderr, "Printing this document is not allowed.\n");
1089         exit(3);
1090     }
1091 #endif
1092 
1093     // get page range
1094     if (firstPage < 1)
1095         firstPage = 1;
1096     if (singleFile && lastPage < 1)
1097         lastPage = firstPage;
1098     if (lastPage < 1 || lastPage > doc->getNumPages())
1099         lastPage = doc->getNumPages();
1100 
1101     if (lastPage < firstPage) {
1102         fprintf(stderr, "Wrong page range given: the first page (%d) can not be after the last page (%d).\n", firstPage, lastPage);
1103         exit(99);
1104     }
1105     if (eps && firstPage != lastPage) {
1106         fprintf(stderr, "EPS files can only contain one page.\n");
1107         exit(99);
1108     }
1109 
1110     // If our page range selection and document size indicate we're only
1111     // outputting a single page, ensure that even/odd page selection doesn't
1112     // filter out that single page.
1113     if (firstPage == lastPage && ((printOnlyEven && firstPage % 2 == 1) || (printOnlyOdd && firstPage % 2 == 0))) {
1114         fprintf(stderr, "Invalid even/odd page selection, no pages match criteria.\n");
1115         exit(99);
1116     }
1117 
1118     if (singleFile && firstPage < lastPage) {
1119         if (!quiet) {
1120             fprintf(stderr, "Warning: Single file will write only the first of the %d pages.\n", lastPage + 1 - firstPage);
1121         }
1122         lastPage = firstPage;
1123     }
1124 
1125 #ifdef CAIRO_HAS_WIN32_SURFACE
1126     if (printdlg) {
1127         bool allPages = false;
1128         if (firstPage == 1 && lastPage == doc->getNumPages())
1129             allPages = true;
1130         win32ShowPrintDialog(&expand, &noShrink, &noCenter, &usePDFPageSize, &allPages, &firstPage, &lastPage, doc->getNumPages());
1131         if (allPages) {
1132             firstPage = 1;
1133             lastPage = doc->getNumPages();
1134         }
1135     } else if (printToWin32) {
1136         win32SetupPrinter(&printer, &printOpt, duplex, setupdlg);
1137     }
1138 #endif
1139 
1140     cairoOut = new CairoOutputDev();
1141 #ifdef USE_CMS
1142     cairoOut->setDisplayProfile(profile);
1143 #endif
1144     cairoOut->startDoc(doc.get());
1145     if (sz != 0)
1146         crop_w = crop_h = sz;
1147     pg_num_len = numberOfCharacters(doc->getNumPages());
1148     for (pg = firstPage; pg <= lastPage; ++pg) {
1149         if (printOnlyEven && pg % 2 == 1)
1150             continue;
1151         if (printOnlyOdd && pg % 2 == 0)
1152             continue;
1153         if (useCropBox) {
1154             pg_w = doc->getPageCropWidth(pg);
1155             pg_h = doc->getPageCropHeight(pg);
1156         } else {
1157             pg_w = doc->getPageMediaWidth(pg);
1158             pg_h = doc->getPageMediaHeight(pg);
1159         }
1160 
1161         if (printing && pg == firstPage) {
1162             if (paperWidth < 0 || paperHeight < 0) {
1163                 paperWidth = (int)ceil(pg_w);
1164                 paperHeight = (int)ceil(pg_h);
1165             }
1166         }
1167 
1168         if ((doc->getPageRotate(pg) == 90) || (doc->getPageRotate(pg) == 270)) {
1169             tmp = pg_w;
1170             pg_w = pg_h;
1171             pg_h = tmp;
1172         }
1173         if (scaleTo != 0) {
1174             resolution = (72.0 * scaleTo) / (pg_w > pg_h ? pg_w : pg_h);
1175             x_resolution = y_resolution = resolution;
1176         } else {
1177             if (x_scaleTo > 0) {
1178                 x_resolution = (72.0 * x_scaleTo) / pg_w;
1179                 if (y_scaleTo == -1)
1180                     y_resolution = x_resolution;
1181             }
1182             if (y_scaleTo > 0) {
1183                 y_resolution = (72.0 * y_scaleTo) / pg_h;
1184                 if (x_scaleTo == -1)
1185                     x_resolution = y_resolution;
1186             }
1187         }
1188         if (imageFileName) {
1189             delete imageFileName;
1190             imageFileName = nullptr;
1191         }
1192         if (!printing)
1193             imageFileName = getImageFileName(outputFileName, pg_num_len, pg);
1194         getOutputSize(pg_w, pg_h, &output_w, &output_h);
1195 
1196         if (pg == firstPage)
1197             beginDocument(fileName, outputFileName, output_w, output_h);
1198         beginPage(&output_w, &output_h);
1199         renderPage(doc.get(), cairoOut, pg, pg_w, pg_h, output_w, output_h);
1200         endPage(imageFileName);
1201     }
1202     endDocument();
1203 
1204     // clean up
1205     delete cairoOut;
1206     if (fileName)
1207         delete fileName;
1208     if (outputName)
1209         delete outputName;
1210     if (outputFileName)
1211         delete outputFileName;
1212     if (imageFileName)
1213         delete imageFileName;
1214     if (ownerPW)
1215         delete ownerPW;
1216     if (userPW)
1217         delete userPW;
1218 
1219 #ifdef USE_CMS
1220     if (icc_data)
1221         gfree(icc_data);
1222 #endif
1223 
1224     return 0;
1225 }
1226