diff --git a/cpp/poppler-page-renderer.cpp b/cpp/poppler-page-renderer.cpp
index 1317192..6f9ab94 100644
--- a/cpp/poppler-page-renderer.cpp
+++ b/cpp/poppler-page-renderer.cpp
@@ -157,8 +157,10 @@ void page_renderer::set_render_hints(unsigned int hints)
 image page_renderer::render_page(const page *p,
                                  double xres, double yres,
                                  int x, int y, int w, int h,
-                                 rotation_enum rotate) const
-{
+                                 rotation_enum rotate, 
+                                 void (*progressCallback)(int pageNum, float progressPct, void *userData),
+                                 void *progressCallbackData ) const
+{ 
     if (!p) {
         return image();
     }
@@ -175,11 +177,16 @@ image page_renderer::render_page(const page *p,
     SplashOutputDev splashOutputDev(splashModeXBGR8, 4, gFalse, bgColor, gTrue, text_AA);
     splashOutputDev.setVectorAntialias(d->hints & antialiasing ? gTrue : gFalse);
     splashOutputDev.setFreeTypeHinting(d->hints & text_hinting ? gTrue : gFalse, gFalse);
+
     splashOutputDev.startDoc(pdfdoc);
     pdfdoc->displayPageSlice(&splashOutputDev, pp->index + 1,
                              xres, yres, int(rotate) * 90,
                              gFalse, gTrue, gFalse,
-                             x, y, w, h);
+                             x, y, w, h,
+                             NULL,NULL,
+                             NULL,NULL,
+                             progressCallback, progressCallbackData
+                             );
 
     SplashBitmap *bitmap = splashOutputDev.getBitmap();
     const int bw = bitmap->getWidth();
diff --git a/cpp/poppler-page-renderer.h b/cpp/poppler-page-renderer.h
index 1383865..33fb87b 100644
--- a/cpp/poppler-page-renderer.h
+++ b/cpp/poppler-page-renderer.h
@@ -52,7 +52,9 @@ public:
     image render_page(const page *p,
                       double xres = 72.0, double yres = 72.0,
                       int x = -1, int y = -1, int w = -1, int h = -1,
-                      rotation_enum rotate = rotate_0) const;
+                      rotation_enum rotate = rotate_0,
+                      void (*progressCallback)(int pageNum, float progressPct, void *userData) = NULL,
+                      void *progressCallbackUserData = NULL ) const ;
 
     static bool can_render();
 
diff --git a/poppler/DummyOutputDev.h b/poppler/DummyOutputDev.h
new file mode 100644
index 0000000..96de3ef
--- /dev/null
+++ b/poppler/DummyOutputDev.h
@@ -0,0 +1,20 @@
+
+#ifndef _DUMMYOUTPUTDEV_H
+#define _DUMMYOUTPUTDEV_H
+
+#include "OutputDev.h"
+
+class DummyOutputDev: public OutputDev
+{
+    public:
+
+        GBool interpretType3Chars() { return gTrue; }
+        GBool useDrawChar() { return gTrue; }
+        GBool upsideDown() { return gTrue; }
+
+    private:
+
+};
+
+#endif
+
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 5c9ed35..8891c31 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -572,6 +572,8 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict,
   parser = NULL;
   abortCheckCbk = abortCheckCbkA;
   abortCheckCbkData = abortCheckCbkDataA;
+  progressCallback = NULL;
+  
 
   // set crop box
   if (cropBox) {
@@ -624,6 +626,7 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict,
   parser = NULL;
   abortCheckCbk = abortCheckCbkA;
   abortCheckCbkData = abortCheckCbkDataA;
+  progressCallback = NULL;
 
   // set crop box
   if (cropBox) {
@@ -678,6 +681,9 @@ void Gfx::display(Object *obj, GBool topLevel) {
     return;
   }
   parser = new Parser(xref, new Lexer(xref, obj), gFalse);
+  // on topLevel, reset operationCount to 0
+  if ( topLevel )
+      opCount = 0;
   go(topLevel);
   delete parser;
   parser = NULL;
@@ -853,6 +859,8 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
   }
 
   // do it
+  opCount++;
+  callProgressCallback();  
   (this->*op->func)(argPtr, numArgs);
 }
 
@@ -5368,3 +5376,19 @@ PopplerCache *Gfx::getIccColorSpaceCache()
   return &iccColorSpaceCache;
 }
 #endif
+
+
+void Gfx::setProgressCallback( void (*progressCbk)(int pageNum, float progressPct, void* userData), void* userData, int pageNum, unsigned long totalOperations ) 
+{
+  progressCallbackTotalOperations = totalOperations;
+  progressCallbackUserData = userData;
+  progressCallbackPageNum = pageNum;
+  progressCallback = progressCbk;
+}
+
+void Gfx::callProgressCallback()
+{
+  if ( progressCallback && progressCallbackTotalOperations>0 )
+    progressCallback( progressCallbackPageNum, (float)((double)opCount/progressCallbackTotalOperations), progressCallbackUserData );
+}
+
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index 7c42f14..895be8b 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -197,8 +197,17 @@ public:
   PopplerCache *getIccColorSpaceCache();
 #endif
 
+  /// Return the number of operations performed
+  /// Use with DummyOutputDev to precalculate an operation count
+  unsigned long getOperationCount() { return opCount; }
+  /// Set a progress callback, called once per operation
+  /// totalOperations must be precalculated using a DummyOutputDev 
+  /// and getOperationCount; see Page::displaySlice for example usage
+  void setProgressCallback( void (*progressCbk)(int pageNum, float progressPct, void* userData), void* userData, int pageNum, unsigned long totalOperations ); 
+
 private:
 
+
   PDFDoc *doc;
   XRef *xref;			// the xref table for this PDF file
   Catalog *catalog;		// the Catalog for this PDF file  
@@ -210,6 +219,8 @@ private:
   GfxResources *res;		// resource stack
   int updateLevel;
 
+  unsigned long opCount;        // total opCount since the first call to display() with topLevel=true 
+
   GfxState *state;		// current graphics state
   int stackHeight;		// the height of the current graphics stack
   std::vector<int> stateGuards;   // a stack of state limits; to guard against unmatched pops
@@ -230,6 +241,14 @@ private:
   PopplerCache iccColorSpaceCache;
 #endif
 
+
+  // call the progress callback, or just return if we don't have one
+  void callProgressCallback();
+  void (*progressCallback)(int pageNum, float progressPct, void* userData);
+  void* progressCallbackUserData;
+  int progressCallbackPageNum;
+  unsigned long progressCallbackTotalOperations; 
+
   GBool				// callback to check for an abort
     (*abortCheckCbk)(void *data);
   void *abortCheckCbkData;
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 0d78588..2056367 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -455,32 +455,38 @@ void PDFDoc::displayPage(OutputDev *out, int page,
 			 GBool (*abortCheckCbk)(void *data),
 			 void *abortCheckCbkData,
                          GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
-                         void *annotDisplayDecideCbkData) {
-  if (globalParams->getPrintCommands()) {
+                         void *annotDisplayDecideCbkData, 
+                         void (*progressCbk)(int pageNum, float progressPct, void *userData ),
+                         void *progressCbkUserData ) {
+   if (globalParams->getPrintCommands()) {
     printf("***** page %d *****\n", page);
   }
 
   if (getPage(page))
-    getPage(page)->display(out, hDPI, vDPI,
-				    rotate, useMediaBox, crop, printing,
-				    abortCheckCbk, abortCheckCbkData,
-				    annotDisplayDecideCbk, annotDisplayDecideCbkData);
+    getPage(page)->display(out, hDPI, vDPI, 
+                           rotate, useMediaBox, crop, printing,
+                           abortCheckCbk, abortCheckCbkData, 
+                           annotDisplayDecideCbk, annotDisplayDecideCbkData,
+                           progressCbk, progressCbkUserData );
 
 }
 
 void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
 			  double hDPI, double vDPI, int rotate,
 			  GBool useMediaBox, GBool crop, GBool printing,
-			  GBool (*abortCheckCbk)(void *data),
-			  void *abortCheckCbkData,
+                          GBool (*abortCheckCbk)(void *data),
+                          void *abortCheckCbkData,
                           GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
-                          void *annotDisplayDecideCbkData) {
+                          void *annotDisplayDecideCbkData, 
+                          void (*progressCbk)(int pageNum, float progressPct, void *userData ),
+                          void *progressCbkUserData ) {
   int page;
 
   for (page = firstPage; page <= lastPage; ++page) {
     displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing,
-		abortCheckCbk, abortCheckCbkData,
-                annotDisplayDecideCbk, annotDisplayDecideCbkData);
+                abortCheckCbk, abortCheckCbkData,
+                annotDisplayDecideCbk, annotDisplayDecideCbkData,
+                progressCbk, progressCbkUserData );
   }
 }
 
@@ -491,14 +497,17 @@ void PDFDoc::displayPageSlice(OutputDev *out, int page,
 			      GBool (*abortCheckCbk)(void *data),
 			      void *abortCheckCbkData,
                               GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
-                              void *annotDisplayDecideCbkData) {
+                              void *annotDisplayDecideCbkData, 
+                              void (*progressCbk)(int pageNum, float progressPct, void *userData ),
+                              void *progressCbkUserData ) {
   if (getPage(page))
     getPage(page)->displaySlice(out, hDPI, vDPI,
-					 rotate, useMediaBox, crop,
-					 sliceX, sliceY, sliceW, sliceH,
-					 printing,
-					 abortCheckCbk, abortCheckCbkData,
-					 annotDisplayDecideCbk, annotDisplayDecideCbkData);
+                                rotate, useMediaBox, crop,
+                                sliceX, sliceY, sliceW, sliceH,
+                                printing,
+                                abortCheckCbk, abortCheckCbkData,
+                                annotDisplayDecideCbk, annotDisplayDecideCbkData,
+                                progressCbk, progressCbkUserData );
 }
 
 Links *PDFDoc::getLinks(int page) {
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 4562346..15f31c0 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -141,31 +141,41 @@ public:
 
   // Display a page.
   void displayPage(OutputDev *out, int page,
-		   double hDPI, double vDPI, int rotate,
-		   GBool useMediaBox, GBool crop, GBool printing,
-		   GBool (*abortCheckCbk)(void *data) = NULL,
-		   void *abortCheckCbkData = NULL,
-                   GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
-                   void *annotDisplayDecideCbkData = NULL);
+		  double hDPI, double vDPI, int rotate,
+		  GBool useMediaBox, GBool crop, GBool printing,
+		  GBool (*abortCheckCbk)(void *data) = NULL,
+		  void *abortCheckCbkData = NULL,
+		  GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+		  void *annotDisplayDecideCbkData = NULL,
+		  void (*progressCbk)(int pageNum, float progressPct, void *userData) = NULL,
+		  void *progressCbkData = NULL
+		  );
+
 
   // Display a range of pages.
   void displayPages(OutputDev *out, int firstPage, int lastPage,
-		    double hDPI, double vDPI, int rotate,
-		    GBool useMediaBox, GBool crop, GBool printing,
-		    GBool (*abortCheckCbk)(void *data) = NULL,
-		    void *abortCheckCbkData = NULL,
-                    GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
-                    void *annotDisplayDecideCbkData = NULL);
+		  double hDPI, double vDPI, int rotate,
+		  GBool useMediaBox, GBool crop, GBool printing,
+		  GBool (*abortCheckCbk)(void *data) = NULL,
+		  void *abortCheckCbkData = NULL,
+		  GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+		  void *annotDisplayDecideCbkData = NULL,
+		  void (*progressCbk)(int pageNum, float progressPct, void *userData) = NULL,
+		  void *progressCbkData = NULL
+		  );
 
   // Display part of a page.
   void displayPageSlice(OutputDev *out, int page,
-			double hDPI, double vDPI, int rotate, 
-			GBool useMediaBox, GBool crop, GBool printing,
-			int sliceX, int sliceY, int sliceW, int sliceH,
-			GBool (*abortCheckCbk)(void *data) = NULL,
-			void *abortCheckCbkData = NULL,
-                        GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
-                        void *annotDisplayDecideCbkData = NULL);
+		  double hDPI, double vDPI, int rotate, 
+		  GBool useMediaBox, GBool crop, GBool printing,
+		  int sliceX, int sliceY, int sliceW, int sliceH,
+		  GBool (*abortCheckCbk)(void *data) = NULL,
+		  void *abortCheckCbkData = NULL,
+		  GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+		  void *annotDisplayDecideCbkData = NULL,
+		  void (*progressCbk)(int pageNum, float progressPct, void *userData) = NULL,
+		  void *progressCbkData = NULL
+		  );
 
   // Find a page, given its object ID.  Returns page number, or 0 if
   // not found.
diff --git a/poppler/Page.cc b/poppler/Page.cc
index 8c2065b..110005c 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -47,6 +47,7 @@
 #include "XRef.h"
 #include "Link.h"
 #include "OutputDev.h"
+#include "DummyOutputDev.h"
 #include "Gfx.h"
 #include "GfxState.h"
 #include "Annot.h"
@@ -445,10 +446,14 @@ void Page::display(OutputDev *out, double hDPI, double vDPI,
 		   GBool (*abortCheckCbk)(void *data),
 		   void *abortCheckCbkData,
                    GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
-                   void *annotDisplayDecideCbkData) {
+                   void *annotDisplayDecideCbkData,
+                   void (progressCbk)(int pageNum, float progress, void* userData),
+                   void *progressCbkUserData ) {
   displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, printing,
 	       abortCheckCbk, abortCheckCbkData,
-               annotDisplayDecideCbk, annotDisplayDecideCbkData);
+               annotDisplayDecideCbk, annotDisplayDecideCbkData, 
+               progressCbk, progressCbkUserData
+               );
 }
 
 Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
@@ -498,8 +503,10 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
 			GBool (*abortCheckCbk)(void *data),
 			void *abortCheckCbkData,
                         GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
-                        void *annotDisplayDecideCbkData) {
-  Gfx *gfx;
+                        void *annotDisplayDecideCbkData,
+                        void (*progressCbk)(int pageNum, float progressPct, void* user_data),
+                        void *progressCbkData ) {
+  Gfx *gfx, *dummyGfx;
   Object obj;
   Annots *annotList;
   int i;
@@ -513,12 +520,22 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
   }
 
   gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop,
-		  sliceX, sliceY, sliceW, sliceH,
-		  printing,
-		  abortCheckCbk, abortCheckCbkData);
+      sliceX, sliceY, sliceW, sliceH,
+      printing,
+      abortCheckCbk, abortCheckCbkData);
 
   contents.fetch(xref, &obj);
   if (!obj.isNull()) {
+    if ( progressCbk ) {
+      // create dummy output device to count operations
+      OutputDev* dummyOutputDev = new DummyOutputDev();
+      dummyGfx = createGfx(dummyOutputDev, hDPI, vDPI, rotate, useMediaBox, crop, 
+          sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData);
+      dummyGfx->display(&obj);
+      unsigned long totalOperations = dummyGfx->getOperationCount();
+      // set progress callback on the real gfx object
+      gfx->setProgressCallback( progressCbk, progressCbkData, num/*pageNum*/, totalOperations );
+    }
     gfx->saveState();
     gfx->display(&obj);
     gfx->restoreState();
diff --git a/poppler/Page.h b/poppler/Page.h
index a6098ed..3023b69 100644
--- a/poppler/Page.h
+++ b/poppler/Page.h
@@ -214,22 +214,26 @@ public:
 
   // Display a page.
   void display(OutputDev *out, double hDPI, double vDPI,
-	       int rotate, GBool useMediaBox, GBool crop,
-	       GBool printing,
-	       GBool (*abortCheckCbk)(void *data) = NULL,
-	       void *abortCheckCbkData = NULL,
-               GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
-               void *annotDisplayDecideCbkData = NULL);
+		  int rotate, GBool useMediaBox, GBool crop,
+		  GBool printing,
+		  GBool (*abortCheckCbk)(void *data) = NULL,
+		  void *abortCheckCbkData = NULL,
+		  GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+		  void *annotDisplayDecideCbkData = NULL,
+		  void (*progressCbk)(int pageNum, float progressPct, void* user_data) = NULL,
+		  void *progressCbkData = NULL );
 
   // Display part of a page.
   void displaySlice(OutputDev *out, double hDPI, double vDPI,
-		    int rotate, GBool useMediaBox, GBool crop,
-		    int sliceX, int sliceY, int sliceW, int sliceH,
-		    GBool printing,
-		    GBool (*abortCheckCbk)(void *data) = NULL,
-		    void *abortCheckCbkData = NULL,
-                    GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
-                    void *annotDisplayDecideCbkData = NULL);
+		  int rotate, GBool useMediaBox, GBool crop,
+		  int sliceX, int sliceY, int sliceW, int sliceH,
+		  GBool printing,
+		  GBool (*abortCheckCbk)(void *data) = NULL,
+		  void *abortCheckCbkData = NULL,
+		  GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
+		  void *annotDisplayDecideCbkData = NULL,
+		  void (*progressCbk)(int pageNum, float progressPct, void* user_data) = NULL,
+		  void *progressCbkData = NULL);
 
   void display(Gfx *gfx);
 
