[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