Hello there,

A while back a fellow by the name of Adrian Johnson contributed a patch that added a new utility "pdftocairo". We've been using the tool for a couple of months and have made a few updates to it. I'm attaching the original patch as well as the updates.

It supports PS, PDF, SVG, PNG and JPEG output formats.

Cheers,

Stefan Thomas


>From bcbb9ccb153f112580f14369c416cdbc6077abb5 Mon Sep 17 00:00:00 2001
From: Adrian Johnson <ajohn...@redneon.com>
Date: Fri, 11 Dec 2009 18:46:23 +1030
Subject: [PATCH 1/6] Add pdftocairo util

---
 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.heikki...@gmail.com>
+// Copyright (C) 2008 Richard Airlie <richard.air...@maglabs.net>
+// Copyright (C) 2009 Michael K. Johnson <a1...@danlj.org>
+// Copyright (C) 2009 Shen Liang <shenzh...@gmail.com>
+// Copyright (C) 2009 Stefan Thomas <tho...@eload24.com>
+// Copyright (C) 2009 Adrian Johnson <ajohn...@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

>From 3c1ca561e49d55dc5fab18333397815edb04ee29 Mon Sep 17 00:00:00 2001
From: Stefan Thomas <tho...@txtbear.com>
Date: Sat, 9 Jan 2010 17:08:11 +0000
Subject: [PATCH 2/6] pdftocairo: Added SVG support.

Simplified initialization code (necessary because there is no resize option for 
Cairo SVG surfaces.)
---
 utils/.gitignore    |    1 +
 utils/pdftocairo.cc |   49 +++++++++++++++++++++++--------------------------
 2 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/utils/.gitignore b/utils/.gitignore
index 696f074..a77622a 100644
--- a/utils/.gitignore
+++ b/utils/.gitignore
@@ -7,6 +7,7 @@ pdfimages
 pdfinfo
 pdftohtml
 pdftoppm
+pdftocairo
 pdftops
 pdftotext
 pdftoabw
diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index 8540b42..2a8b6dc 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -32,6 +32,7 @@
 #include <cairo.h>
 #include <cairo-ps.h>
 #include <cairo-pdf.h>
+#include <cairo-svg.h>
 #include "parseargs.h"
 #include "goo/gmem.h"
 #include "goo/GooString.h"
@@ -59,6 +60,7 @@ static GBool useCropBox = gFalse;
 static GBool png = gFalse;
 static GBool ps = gFalse;
 static GBool pdf = gFalse;
+static GBool svg = gFalse;
 static char ownerPassword[33] = "";
 static char userPassword[33] = "";
 static GBool quiet = gFalse;
@@ -103,6 +105,8 @@ static const ArgDesc argDesc[] = {
    "generate PostScript file"},
   {"-pdf",   argFlag,     &pdf,          0,
    "generate a PDF file"},
+  {"-svg",   argFlag,     &svg,          0,
+   "generate a SVG file"},
 
 
   {"-opw",    argString,   ownerPassword,  sizeof(ownerPassword),
@@ -126,37 +130,28 @@ static const ArgDesc argDesc[] = {
 };
 
 
-static void create_surface(char *outFile, cairo_surface_t **surface_out,
-                          GBool *printing_out)
+static cairo_surface_t *start_page(char *outFile, int w, int h,
+                      double x_res, double y_res, int rotate)
 {
   char file[OUT_FILE_SZ];
+  cairo_surface_t *surface;
 
   strcpy(file, outFile);
+  
   if (png) {
-    *surface_out = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
-    *printing_out = gFalse;
+    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w*x_res/72.0, 
h*y_res/72.0);
   } else if (ps) {
     strcat(file, ".ps");
-    *surface_out = cairo_ps_surface_create (file, w, h);
-    *printing_out = gTrue;
+    surface = cairo_ps_surface_create (file, w, h);
   } 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);
+    surface = cairo_pdf_surface_create (file, w, h);
+  } else if (svg) {
+    strcat(file, ".svg");
+    surface = cairo_svg_surface_create (file, w, h);
   }
+  
+  return surface;
 }
 
 static void end_page(cairo_surface_t *surface, char *outFile)
@@ -167,7 +162,7 @@ static void end_page(cairo_surface_t *surface, char 
*outFile)
   if (png) {
     strcat(file, ".png");
     cairo_surface_write_to_png (surface, file);
-  } else if (ps || pdf) {
+  } else if (ps || pdf || svg) {
     cairo_surface_show_page(surface);
   }
 }
@@ -270,8 +265,8 @@ int main(int argc, char *argv[]) {
     goto err0;
   }
 
-  if (!png && !ps && !pdf) {
-    fprintf(stderr, "One of -png, -ps, or -pdf must be specified\n");
+  if (!png && !ps && !pdf && !svg) {
+    fprintf(stderr, "One of -png, -ps, -pdf or -svg must be specified\n");
     goto err0;
   }
 
@@ -323,7 +318,6 @@ int main(int argc, char *argv[]) {
   if (sz != 0)
     w = h = sz;
 
-  create_surface(outRoot, &surface, &printing);
   output_dev = new CairoOutputDev ();
   output_dev->startDoc(doc->getXRef (), doc->getCatalog ());
 
@@ -348,8 +342,11 @@ int main(int argc, char *argv[]) {
         y_resolution = (72.0 * y_scaleTo) / pg_h;
       }
     }
+    
+    // Enable printing mode for all output types except PNG
+    printing = (png) ? gFalse : gTrue;
 
-    start_page(&surface, pg_w, pg_h, x_resolution, y_resolution, 
doc->getPageRotate(pg));
+    surface = start_page(outRoot, 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",
-- 
1.7.0.4

>From ca12ce32d7dc92114cf40891c7be9aaacae4d6ad Mon Sep 17 00:00:00 2001
From: Stefan Thomas <tho...@txtbear.com>
Date: Sat, 9 Jan 2010 17:11:45 +0000
Subject: [PATCH 3/6] pdftocairo: Code style; Removed spaces before parentheses 
in function calls.

---
 utils/pdftocairo.cc |   22 +++++++++++-----------
 1 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index 2a8b6dc..b13d5d2 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -204,17 +204,17 @@ static int render_page(CairoOutputDev *output_dev, PDFDoc 
*doc,
                        !useCropBox, /* Crop */
                        printing,
                        x, y, w, h);
-  cairo_restore (cr);
+  cairo_restore(cr);
 
-  output_dev->setCairo (NULL);
-  output_dev->setTextPage (NULL);
+  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);
+    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);
@@ -318,8 +318,8 @@ int main(int argc, char *argv[]) {
   if (sz != 0)
     w = h = sz;
 
-  output_dev = new CairoOutputDev ();
-  output_dev->startDoc(doc->getXRef (), doc->getCatalog ());
+  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) {
@@ -356,7 +356,7 @@ int main(int argc, char *argv[]) {
   cairo_surface_finish(surface);
   status = cairo_surface_status(surface);
   if (status)
-    fprintf(stderr, "cairo error: %s\n", cairo_status_to_string (status));
+    fprintf(stderr, "cairo error: %s\n", cairo_status_to_string(status));
   cairo_surface_destroy(surface);
   delete output_dev;
 
-- 
1.7.0.4

>From e0a81209b6a86552eba385296fce389a8744d600 Mon Sep 17 00:00:00 2001
From: Stefan Thomas <tho...@txtbear.com>
Date: Sat, 9 Jan 2010 17:32:07 +0000
Subject: [PATCH 4/6] pdftocairo: Centralized output filename generation.

Nicer to have the filename generated in one place, also the filenames now all 
have numbers, not just png.
---
 utils/pdftocairo.cc |   58 ++++++++++++++++++++++++++++----------------------
 1 files changed, 32 insertions(+), 26 deletions(-)

diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index b13d5d2..9c4981f 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -130,25 +130,36 @@ static const ArgDesc argDesc[] = {
 };
 
 
+static void format_output_filename(char *outFile, char *outRoot,
+           int pg_num_len, int pg)
+{
+  snprintf(outFile, OUT_FILE_SZ, "%.*s-%0*d",
+    OUT_FILE_SZ - 32, outRoot, pg_num_len, pg);
+  
+  if (png) {
+    strcat(outFile, ".png");
+  } else if (ps) {
+    strcat(outFile, ".ps");
+  } else if (pdf) {
+    strcat(outFile, ".pdf");
+  } else if (svg) {
+    strcat(outFile, ".svg");
+  }
+}
+
 static cairo_surface_t *start_page(char *outFile, int w, int h,
                       double x_res, double y_res, int rotate)
 {
-  char file[OUT_FILE_SZ];
   cairo_surface_t *surface;
-
-  strcpy(file, outFile);
   
   if (png) {
-    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w*x_res/72.0, 
h*y_res/72.0);
+    surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w*x_res/72.0, 
h*y_res/72.0);
   } else if (ps) {
-    strcat(file, ".ps");
-    surface = cairo_ps_surface_create (file, w, h);
+    surface = cairo_ps_surface_create(outFile, w, h);
   } else if (pdf) {
-    strcat(file, ".pdf");
-    surface = cairo_pdf_surface_create (file, w, h);
+    surface = cairo_pdf_surface_create(outFile, w, h);
   } else if (svg) {
-    strcat(file, ".svg");
-    surface = cairo_svg_surface_create (file, w, h);
+    surface = cairo_svg_surface_create(outFile, w, h);
   }
   
   return surface;
@@ -156,12 +167,8 @@ static cairo_surface_t *start_page(char *outFile, int w, 
int 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);
+    cairo_surface_write_to_png(surface, outFile);
   } else if (ps || pdf || svg) {
     cairo_surface_show_page(surface);
   }
@@ -231,7 +238,7 @@ static int render_page(CairoOutputDev *output_dev, PDFDoc 
*doc,
 int main(int argc, char *argv[]) {
   PDFDoc *doc;
   GooString *fileName = NULL;
-  char *outRoot;
+  char *outRoot = NULL;
   char outFile[OUT_FILE_SZ];
   GooString *ownerPW, *userPW;
   GBool ok;
@@ -270,15 +277,14 @@ int main(int argc, char *argv[]) {
     goto err0;
   }
 
-  fileName = new GooString(argv[1]);
-  if (argc == 3)
+  if (argc > 1) fileName = new GooString(argv[1]);
+  if (argc == 3) {
     outRoot = strdup(argv[2]);
-  else
-    outRoot = strdup(argv[1]);
 
-  p = strrchr(outRoot, '.');
-  if (p)
-    *p = 0;
+    p = strrchr(outRoot, '.');
+    if (p)
+      *p = 0;
+  }
 
   // read config file
   globalParams = new GlobalParams();
@@ -345,12 +351,12 @@ int main(int argc, char *argv[]) {
     
     // Enable printing mode for all output types except PNG
     printing = (png) ? gFalse : gTrue;
+    
+    format_output_filename(outFile, outRoot, pg_num_len, pg);
 
-    surface = start_page(outRoot, pg_w, pg_h, x_resolution, y_resolution, 
doc->getPageRotate(pg));
+    surface = start_page(outFile, 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);
-- 
1.7.0.4

>From d85e99891c0089f2805362dbfae2e2372f668377 Mon Sep 17 00:00:00 2001
From: Stefan Thomas <tho...@txtbear.com>
Date: Tue, 13 Jul 2010 14:53:34 +0100
Subject: [PATCH 5/6] pdftocairo: Updated to use PDFDocFactory.

---
 utils/pdftocairo.cc |   15 ++++++++++++++-
 1 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index 9c4981f..a832e8c 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -39,6 +39,7 @@
 #include "GlobalParams.h"
 #include "Object.h"
 #include "PDFDoc.h"
+#include "PDFDocFactory.h"
 #include "CairoOutputDev.h"
 
 #define OUT_FILE_SZ 512
@@ -133,6 +134,8 @@ static const ArgDesc argDesc[] = {
 static void format_output_filename(char *outFile, char *outRoot,
            int pg_num_len, int pg)
 {
+  if (!outRoot) outRoot = "cairoout";
+  
   snprintf(outFile, OUT_FILE_SZ, "%.*s-%0*d",
     OUT_FILE_SZ - 32, outRoot, pg_num_len, pg);
   
@@ -303,7 +306,17 @@ int main(int argc, char *argv[]) {
   } else {
     userPW = NULL;
   }
-  doc = new PDFDoc(fileName, ownerPW, userPW);
+
+  if (fileName == NULL) {
+    fileName = new GooString("fd://0");
+  }
+  if (fileName->cmp("-") == 0) {
+    delete fileName;
+    fileName = new GooString("fd://0");
+  }
+  doc = PDFDocFactory().createPDFDoc(*fileName, ownerPW, userPW);
+  delete fileName;
+  
   if (userPW) {
     delete userPW;
   }
-- 
1.7.0.4

>From 185a860d64654a85bc31b60d2ceac162ed16de20 Mon Sep 17 00:00:00 2001
From: Stefan Thomas <tho...@txtbear.com>
Date: Thu, 15 Jul 2010 04:12:04 +0100
Subject: [PATCH 6/6] pdftocairo: Added -jpeg output option.

---
 utils/pdftocairo.cc |   61 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index a832e8c..8e5db15 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -36,6 +36,7 @@
 #include "parseargs.h"
 #include "goo/gmem.h"
 #include "goo/GooString.h"
+#include "goo/JpegWriter.h"
 #include "GlobalParams.h"
 #include "Object.h"
 #include "PDFDoc.h"
@@ -59,6 +60,7 @@ static int h = 0;
 static int sz = 0;
 static GBool useCropBox = gFalse;
 static GBool png = gFalse;
+static GBool jpg = gFalse;
 static GBool ps = gFalse;
 static GBool pdf = gFalse;
 static GBool svg = gFalse;
@@ -102,11 +104,13 @@ static const ArgDesc argDesc[] = {
 
   {"-png",    argFlag,     &png,           0,
    "generate a PNG file"},
-  {"-ps",   argFlag,     &ps,          0,
+  {"-jpeg",   argFlag,     &jpg,           0,
+   "generate a JPEG file"},
+  {"-ps",     argFlag,     &ps,            0,
    "generate PostScript file"},
-  {"-pdf",   argFlag,     &pdf,          0,
+  {"-pdf",    argFlag,     &pdf,           0,
    "generate a PDF file"},
-  {"-svg",   argFlag,     &svg,          0,
+  {"-svg",    argFlag,     &svg,           0,
    "generate a SVG file"},
 
 
@@ -141,6 +145,8 @@ static void format_output_filename(char *outFile, char 
*outRoot,
   
   if (png) {
     strcat(outFile, ".png");
+  } else if (jpg) {
+    strcat(outFile, ".jpg");
   } else if (ps) {
     strcat(outFile, ".ps");
   } else if (pdf) {
@@ -157,6 +163,8 @@ static cairo_surface_t *start_page(char *outFile, int w, 
int h,
   
   if (png) {
     surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w*x_res/72.0, 
h*y_res/72.0);
+  } else if (jpg) {
+    surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w*x_res/72.0, 
h*y_res/72.0);
   } else if (ps) {
     surface = cairo_ps_surface_create(outFile, w, h);
   } else if (pdf) {
@@ -168,10 +176,43 @@ static cairo_surface_t *start_page(char *outFile, int w, 
int h,
   return surface;
 }
 
+static void end_page_jpeg(cairo_surface_t *surface, char *outFile)
+{
+       unsigned char *p;
+       int width, height, stride, i, j;
+       FILE *f;
+       JpegWriter *writer;
+       unsigned char *row;
+       
+       width = cairo_image_surface_get_width(surface);
+       height = cairo_image_surface_get_height(surface);
+       stride = cairo_image_surface_get_stride(surface);
+       p = cairo_image_surface_get_data(surface);
+       
+  f = fopen(outFile, "w");
+  writer = new JpegWriter();
+  writer->init(f, width, height, 72, 72);
+
+  row = new unsigned char[3 * width];
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j++) {
+      row[3*j] = p[j * 4 + 2];
+      row[3*j+1] = p[j * 4 + 1];
+      row[3*j+2] = p[j * 4];
+    }
+
+    writer->writeRow(&row);
+    p += stride;
+       }
+  writer->close();
+}
+
 static void end_page(cairo_surface_t *surface, char *outFile)
 {
   if (png) {
     cairo_surface_write_to_png(surface, outFile);
+  } else if (jpg) {
+    end_page_jpeg(surface, outFile);
   } else if (ps || pdf || svg) {
     cairo_surface_show_page(surface);
   }
@@ -194,6 +235,7 @@ static int render_page(CairoOutputDev *output_dev, PDFDoc 
*doc,
   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);
@@ -201,6 +243,13 @@ static int render_page(CairoOutputDev *output_dev, PDFDoc 
*doc,
   if (!printing)
     cairo_scale (cr, x_res/72.0, y_res/72.0);
 
+  // JPEGs are non-transparent, so we need a white background
+  if (jpg) {
+    cairo_rectangle(cr, 0, 0, w, h);
+    cairo_set_source_rgb(cr, 1, 1, 1);
+    cairo_fill(cr);
+  }
+  
   text = new TextPage(gFalse);
   if (!printing)
     output_dev->setTextPage (text);
@@ -275,8 +324,8 @@ int main(int argc, char *argv[]) {
     goto err0;
   }
 
-  if (!png && !ps && !pdf && !svg) {
-    fprintf(stderr, "One of -png, -ps, -pdf or -svg must be specified\n");
+  if (!png && !jpg && !ps && !pdf && !svg) {
+    fprintf(stderr, "One of -png, -jpeg, -ps, -pdf or -svg must be 
specified\n");
     goto err0;
   }
 
@@ -363,7 +412,7 @@ int main(int argc, char *argv[]) {
     }
     
     // Enable printing mode for all output types except PNG
-    printing = (png) ? gFalse : gTrue;
+    printing = (png || jpg) ? gFalse : gTrue;
     
     format_output_filename(outFile, outRoot, pg_num_len, pg);
 
-- 
1.7.0.4

_______________________________________________
poppler mailing list
poppler@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to