[PATCH 01/10] Add pdftocairo util
Adrian Johnson
ajohnson at redneon.com
Fri Dec 11 00:16:23 PST 2009
---
utils/Makefile.am | 20 +++-
utils/pdftocairo.cc | 379 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 397 insertions(+), 2 deletions(-)
create mode 100644 utils/pdftocairo.cc
diff --git a/utils/Makefile.am b/utils/Makefile.am
index e57c71b..ac08b5e 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -17,7 +17,8 @@ INCLUDES = \
-I$(top_srcdir)/poppler \
$(UTILS_CFLAGS) \
$(FONTCONFIG_CFLAGS) \
- $(ABIWORD_CFLAGS)
+ $(ABIWORD_CFLAGS) \
+ $(CAIRO_CFLAGS)
LDADD = \
$(top_builddir)/poppler/libpoppler.la \
@@ -36,6 +37,20 @@ pdftoabw_binary = pdftoabw
endif
+if BUILD_CAIRO_OUTPUT
+
+pdftocairo_SOURCES = \
+ pdftocairo.cc \
+ $(common)
+
+pdftocairo_LDADD = $(LDADD) $(CAIRO_LIBS) \
+ $(top_builddir)/poppler/libpoppler-cairo.la
+
+
+pdftocairo_binary = pdftocairo
+
+endif
+
AM_LDFLAGS = @auto_import_flags@
bin_PROGRAMS = \
@@ -46,7 +61,8 @@ bin_PROGRAMS = \
pdftotext \
pdftohtml \
$(pdftoppm_binary) \
- $(pdftoabw_binary)
+ $(pdftoabw_binary) \
+ $(pdftocairo_binary)
dist_man1_MANS = \
pdffonts.1 \
diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
new file mode 100644
index 0000000..8540b42
--- /dev/null
+++ b/utils/pdftocairo.cc
@@ -0,0 +1,379 @@
+//========================================================================
+//
+// pdftocairo.cc
+//
+// Copyright 2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen at gmail.com>
+// Copyright (C) 2008 Richard Airlie <richard.airlie at maglabs.net>
+// Copyright (C) 2009 Michael K. Johnson <a1237 at danlj.org>
+// Copyright (C) 2009 Shen Liang <shenzhuxi at gmail.com>
+// Copyright (C) 2009 Stefan Thomas <thomas at eload24.com>
+// Copyright (C) 2009 Adrian Johnson <ajohnson at redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include "config.h"
+#include <poppler-config.h>
+#include <stdio.h>
+#include <math.h>
+#include <cairo.h>
+#include <cairo-ps.h>
+#include <cairo-pdf.h>
+#include "parseargs.h"
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "GlobalParams.h"
+#include "Object.h"
+#include "PDFDoc.h"
+#include "CairoOutputDev.h"
+
+#define OUT_FILE_SZ 512
+
+static int firstPage = 1;
+static int lastPage = 0;
+static double resolution = 0.0;
+static double x_resolution = 150.0;
+static double y_resolution = 150.0;
+static int scaleTo = 0;
+static int x_scaleTo = 0;
+static int y_scaleTo = 0;
+static int x = 0;
+static int y = 0;
+static int w = 0;
+static int h = 0;
+static int sz = 0;
+static GBool useCropBox = gFalse;
+static GBool png = gFalse;
+static GBool ps = gFalse;
+static GBool pdf = gFalse;
+static char ownerPassword[33] = "";
+static char userPassword[33] = "";
+static GBool quiet = gFalse;
+static GBool printVersion = gFalse;
+static GBool printHelp = gFalse;
+
+static const ArgDesc argDesc[] = {
+ {"-f", argInt, &firstPage, 0,
+ "first page to print"},
+ {"-l", argInt, &lastPage, 0,
+ "last page to print"},
+
+ {"-r", argFP, &resolution, 0,
+ "resolution, in DPI (default is 150)"},
+ {"-rx", argFP, &x_resolution, 0,
+ "X resolution, in DPI (default is 150)"},
+ {"-ry", argFP, &y_resolution, 0,
+ "Y resolution, in DPI (default is 150)"},
+ {"-scale-to", argInt, &scaleTo, 0,
+ "scales each page to fit within scale-to*scale-to pixel box"},
+ {"-scale-to-x", argInt, &x_scaleTo, 0,
+ "scales each page horizontally to fit in scale-to-x pixels"},
+ {"-scale-to-y", argInt, &y_scaleTo, 0,
+ "scales each page vertically to fit in scale-to-y pixels"},
+
+ {"-x", argInt, &x, 0,
+ "x-coordinate of the crop area top left corner"},
+ {"-y", argInt, &y, 0,
+ "y-coordinate of the crop area top left corner"},
+ {"-W", argInt, &w, 0,
+ "width of crop area in pixels (default is 0)"},
+ {"-H", argInt, &h, 0,
+ "height of crop area in pixels (default is 0)"},
+ {"-sz", argInt, &sz, 0,
+ "size of crop square in pixels (sets W and H)"},
+ {"-cropbox",argFlag, &useCropBox, 0,
+ "use the crop box rather than media box"},
+
+ {"-png", argFlag, &png, 0,
+ "generate a PNG file"},
+ {"-ps", argFlag, &ps, 0,
+ "generate PostScript file"},
+ {"-pdf", argFlag, &pdf, 0,
+ "generate a PDF file"},
+
+
+ {"-opw", argString, ownerPassword, sizeof(ownerPassword),
+ "owner password (for encrypted files)"},
+ {"-upw", argString, userPassword, sizeof(userPassword),
+ "user password (for encrypted files)"},
+
+ {"-q", argFlag, &quiet, 0,
+ "don't print any messages or errors"},
+ {"-v", argFlag, &printVersion, 0,
+ "print copyright and version info"},
+ {"-h", argFlag, &printHelp, 0,
+ "print usage information"},
+ {"-help", argFlag, &printHelp, 0,
+ "print usage information"},
+ {"--help", argFlag, &printHelp, 0,
+ "print usage information"},
+ {"-?", argFlag, &printHelp, 0,
+ "print usage information"},
+ {NULL}
+};
+
+
+static void create_surface(char *outFile, cairo_surface_t **surface_out,
+ GBool *printing_out)
+{
+ char file[OUT_FILE_SZ];
+
+ strcpy(file, outFile);
+ if (png) {
+ *surface_out = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ *printing_out = gFalse;
+ } else if (ps) {
+ strcat(file, ".ps");
+ *surface_out = cairo_ps_surface_create (file, w, h);
+ *printing_out = gTrue;
+ } else if (pdf) {
+ strcat(file, ".pdf");
+ *surface_out = cairo_pdf_surface_create (file, w, h);
+ *printing_out = gTrue;
+ }
+}
+
+static void start_page(cairo_surface_t **surface, int w, int h,
+ double x_res, double y_res, int rotate)
+{
+ if (png) {
+ cairo_surface_destroy(*surface);
+ *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w*x_res/72.0, h*y_res/72.0);
+ } else if (ps) {
+ cairo_ps_surface_set_size(*surface, w, h);
+ } else if (pdf) {
+ cairo_pdf_surface_set_size(*surface, w, h);
+ }
+}
+
+static void end_page(cairo_surface_t *surface, char *outFile)
+{
+ char file[OUT_FILE_SZ];
+
+ strcpy(file, outFile);
+ if (png) {
+ strcat(file, ".png");
+ cairo_surface_write_to_png (surface, file);
+ } else if (ps || pdf) {
+ cairo_surface_show_page(surface);
+ }
+}
+
+static int render_page(CairoOutputDev *output_dev, PDFDoc *doc,
+ cairo_surface_t *surface,
+ GBool printing, int pg,
+ int x, int y, int w, int h,
+ double pg_w, double pg_h,
+ double x_res, double y_res)
+{
+ cairo_t *cr;
+ cairo_status_t status;
+ TextPage *text = NULL;
+
+ if (w == 0) w = (int)ceil(pg_w);
+ if (h == 0) h = (int)ceil(pg_h);
+ w = (x+w > pg_w ? (int)ceil(pg_w-x) : w);
+ h = (y+h > pg_h ? (int)ceil(pg_h-y) : h);
+
+ cr = cairo_create (surface);
+ cairo_save (cr);
+ output_dev->setCairo (cr);
+ output_dev->setPrinting (printing);
+
+ if (!printing)
+ cairo_scale (cr, x_res/72.0, y_res/72.0);
+
+ text = new TextPage(gFalse);
+ if (!printing)
+ output_dev->setTextPage (text);
+
+ /* NOTE: instead of passing -1 we should/could use cairo_clip_extents()
+ * to get a bounding box */
+ cairo_save (cr);
+ doc->displayPageSlice(output_dev, pg, /* page */
+ 72.0, 72.0, 0,
+ gFalse, /* useMediaBox */
+ !useCropBox, /* Crop */
+ printing,
+ x, y, w, h);
+ cairo_restore (cr);
+
+ output_dev->setCairo (NULL);
+ output_dev->setTextPage (NULL);
+
+ if (!printing) {
+ cairo_save (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+ cairo_restore (cr);
+ }
+
+ status = cairo_status(cr);
+ if (status)
+ fprintf(stderr, "cairo error: %s\n", cairo_status_to_string (status));
+ cairo_destroy (cr);
+
+ if (text != NULL)
+ text->decRefCnt();
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ PDFDoc *doc;
+ GooString *fileName = NULL;
+ char *outRoot;
+ char outFile[OUT_FILE_SZ];
+ GooString *ownerPW, *userPW;
+ GBool ok;
+ int exitCode;
+ int pg, pg_num_len;
+ double pg_w, pg_h, tmp;
+ char *p;
+ CairoOutputDev *output_dev;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ GBool printing;
+
+ exitCode = 99;
+
+ // parse args
+ ok = parseArgs(argDesc, &argc, argv);
+
+ if ( resolution != 0.0 &&
+ (x_resolution == 150.0 ||
+ y_resolution == 150.0)) {
+ x_resolution = resolution;
+ y_resolution = resolution;
+ }
+ if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) {
+ fprintf(stderr, "pdftocairo version %s\n", PACKAGE_VERSION);
+ fprintf(stderr, "%s\n", popplerCopyright);
+ fprintf(stderr, "%s\n", xpdfCopyright);
+ if (!printVersion) {
+ printUsage("pdftocairo", "PDF-file [output-file]", argDesc);
+ }
+ goto err0;
+ }
+
+ if (!png && !ps && !pdf) {
+ fprintf(stderr, "One of -png, -ps, or -pdf must be specified\n");
+ goto err0;
+ }
+
+ fileName = new GooString(argv[1]);
+ if (argc == 3)
+ outRoot = strdup(argv[2]);
+ else
+ outRoot = strdup(argv[1]);
+
+ p = strrchr(outRoot, '.');
+ if (p)
+ *p = 0;
+
+ // read config file
+ globalParams = new GlobalParams();
+ if (quiet) {
+ globalParams->setErrQuiet(quiet);
+ }
+
+ // open PDF file
+ if (ownerPassword[0]) {
+ ownerPW = new GooString(ownerPassword);
+ } else {
+ ownerPW = NULL;
+ }
+ if (userPassword[0]) {
+ userPW = new GooString(userPassword);
+ } else {
+ userPW = NULL;
+ }
+ doc = new PDFDoc(fileName, ownerPW, userPW);
+ if (userPW) {
+ delete userPW;
+ }
+ if (ownerPW) {
+ delete ownerPW;
+ }
+ if (!doc->isOk()) {
+ exitCode = 1;
+ goto err1;
+ }
+
+ // get page range
+ if (firstPage < 1)
+ firstPage = 1;
+ if (lastPage < 1 || lastPage > doc->getNumPages())
+ lastPage = doc->getNumPages();
+
+ if (sz != 0)
+ w = h = sz;
+
+ create_surface(outRoot, &surface, &printing);
+ output_dev = new CairoOutputDev ();
+ output_dev->startDoc(doc->getXRef (), doc->getCatalog ());
+
+ pg_num_len = (int)ceil(log((double)doc->getNumPages()) / log((double)10));
+ for (pg = firstPage; pg <= lastPage; ++pg) {
+ if (useCropBox) {
+ pg_w = doc->getPageCropWidth(pg);
+ pg_h = doc->getPageCropHeight(pg);
+ } else {
+ pg_w = doc->getPageMediaWidth(pg);
+ pg_h = doc->getPageMediaHeight(pg);
+ }
+
+ if (scaleTo != 0) {
+ resolution = (72.0 * scaleTo) / (pg_w > pg_h ? pg_w : pg_h);
+ x_resolution = y_resolution = resolution;
+ } else {
+ if (x_scaleTo != 0) {
+ x_resolution = (72.0 * x_scaleTo) / pg_w;
+ }
+ if (y_scaleTo != 0) {
+ y_resolution = (72.0 * y_scaleTo) / pg_h;
+ }
+ }
+
+ start_page(&surface, pg_w, pg_h, x_resolution, y_resolution, doc->getPageRotate(pg));
+ render_page(output_dev, doc, surface, printing, pg,
+ x, y, w, h, pg_w, pg_h, x_resolution, y_resolution);
+ snprintf(outFile, OUT_FILE_SZ, "%.*s-%0*d",
+ OUT_FILE_SZ - 32, outRoot, pg_num_len, pg);
+ end_page(surface, outFile);
+ }
+ cairo_surface_finish(surface);
+ status = cairo_surface_status(surface);
+ if (status)
+ fprintf(stderr, "cairo error: %s\n", cairo_status_to_string (status));
+ cairo_surface_destroy(surface);
+ delete output_dev;
+
+ exitCode = 0;
+
+ // clean up
+ err1:
+ delete doc;
+ delete globalParams;
+ err0:
+
+ // check for memory leaks
+ Object::memCheck(stderr);
+ gMemReport(stderr);
+
+ return exitCode;
+}
--
1.7.0.4
More information about the poppler
mailing list