Dear Poppler developers,

I have the task to render PDF documents and to trace back each output
pixel to the object(s) that were rendered at this place.  To achieve
this, Poppler is a great help, so I'd like to contribute something
back.  Attached is the second smallest patch (see below) I came up
with.

Do you think it makes sense to include this feature in Poppler?

Usage:

A. Use the private poppler API to render a PDF onto a custom OutputDev.

B. Derive that custom OutputDev from SplashOutputDev.

C. Set your tracePixel() callback, which is called for each rendered
   pixel.  It may be part of the same custom OutputDev class.

D. Keep track of which object is rendered right now (overwriting
   drawImage(), etc.), and use that information within tracePixel().

To get the discussion started, these are the things I think I could
have done differently:

1. Currently, tracePixel() is called in addition to the "pipe run".
   However, it could also be called instead of the "pipe run".  This
   would result in an even smaller patch, but it would suppress the
   PDF output while the tracer is run, which could possibly cause side
   effects on anti aliasing and other things.  Also, since I need the
   rendered image as well, I would have to run the renderer twice -
   with and without pixel tracer.

2. The tracePixel() callback only gets the pixel coordinates (x, y),
   which is sufficient for my task.  However, one could also think
   of providing the actual pixel value to that callback.  The drawback
   is the additional complexity of handling different types of pixels.
   (RGB, Mono, etc.)

3. I could have used a more C++-like interface, using templates,
   std::function and other nice stuff.  However, that would not fit
   well in the current coding style of Poppler, thus requiring a lot
   more changes.  On the positive side, this would allow for a
   completely transparent tracing mechanism, where e.g. the compiler
   is able to optimize an empty tracer function completely away.
   Also, that could restructure the current "pipe" mechanism in a way
   that is as flexible as now, but would enable the compiler to inline
   the complete "pipe run" code without any function call.

4. I could have added the whole code for the object tracing to
   Poppler, rather than just the ability to add custom callbacks.
   However, this would be less flexible, and it is probably not a good
   idea to overload the Poppler project with too much specialized code
   that is useful for just one or two applications.


Regards,
Volker

-- 
Volker Grabsch
---<<(())>>---
commit 526ae2f973d6ff7d4453c17101958f89b13c1d02
Author: Volker Grabsch <[email protected]>
Date:   Fri Nov 14 14:54:58 2014 +0100

    Add support for pixel tracer in SplashOutputDev

diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 0eaeb79..ee1d7dd 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -1733,6 +1733,10 @@ void SplashOutputDev::setOverprintMask(GfxColorSpace *colorSpace,
 #endif
 }
 
+void SplashOutputDev::setPixelTracer(SplashPixelTracer *pixelTracer) {
+  splash->setPixelTracer(pixelTracer);
+}
+
 void SplashOutputDev::updateBlendMode(GfxState *state) {
   splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]);
 }
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index efbb865..2f72089 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -52,6 +52,7 @@ class SplashFont;
 class T3FontCache;
 struct T3FontCacheTag;
 struct T3GlyphStack;
+struct SplashPixelTracer;
 struct SplashTransparencyGroup;
 
 //------------------------------------------------------------------------
@@ -361,6 +362,8 @@ public:
 
   void setFreeTypeHinting(GBool enable, GBool enableSlightHinting);
 
+  void setPixelTracer(SplashPixelTracer *pixelTracer);
+
 protected:
   void doUpdateFont(GfxState *state);
 
diff --git a/splash/Splash.cc b/splash/Splash.cc
index fde272a..3500b41 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -163,6 +163,9 @@ struct SplashPipe {
 
   // the "run" function
   void (Splash::*run)(SplashPipe *pipe);
+
+  // the original "run" function if pixel tracer is present
+  void (Splash::*origRun)(SplashPipe *pipe);
 };
 
 SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
@@ -339,6 +342,12 @@ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
 #endif
     }
   }
+
+  // inject pixel tracer if present
+  if (pixelTracer != NULL) {
+      pipe->origRun = pipe->run;
+      pipe->run = &Splash::pipeRunPixelTracer;
+  }
 }
 
 // general case
@@ -1320,6 +1329,12 @@ void Splash::pipeRunAADeviceN8(SplashPipe *pipe) {
 }
 #endif
 
+// run pixel tracer, then call original "run" function
+void Splash::pipeRunPixelTracer(SplashPipe *pipe) {
+  pixelTracer->tracePixel(pipe->x, pipe->y);
+  (this->*pipe->run)(pipe);
+}
+
 inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
   pipe->x = x;
   pipe->y = y;
@@ -1606,6 +1621,7 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
   clearModRegion();
   debugMode = gFalse;
   alpha0Bitmap = NULL;
+  pixelTracer = NULL;
 }
 
 Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
@@ -1634,6 +1650,7 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
   clearModRegion();
   debugMode = gFalse;
   alpha0Bitmap = NULL;
+  pixelTracer = NULL;
 }
 
 Splash::~Splash() {
diff --git a/splash/Splash.h b/splash/Splash.h
index cf98e6c..4b6bb5d 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -81,6 +81,15 @@ enum SplashPipeResultColorCtrl {
 };
 
 //------------------------------------------------------------------------
+
+class SplashPixelTracer {
+public:
+  SplashPixelTracer() {}
+  virtual ~SplashPixelTracer() {}
+  virtual void tracePixel(int x, int y) = 0;
+};
+
+//------------------------------------------------------------------------
 // Splash
 //------------------------------------------------------------------------
 
@@ -280,6 +289,9 @@ public:
   // Draw a gouraud triangle shading.
   GBool gouraudTriangleShadedFill(SplashGouraudColor *shading);
 
+  // Set pixel tracer
+  void setPixelTracer(SplashPixelTracer *pixelTracerA) { pixelTracer = pixelTracerA; }
+
 private:
 
   void pipeInit(SplashPipe *pipe, int x, int y,
@@ -306,6 +318,7 @@ private:
   void pipeRunAACMYK8(SplashPipe *pipe);
   void pipeRunAADeviceN8(SplashPipe *pipe);
 #endif
+  void pipeRunPixelTracer(SplashPipe *pipe);
   void pipeSetXY(SplashPipe *pipe, int x, int y);
   void pipeIncX(SplashPipe *pipe);
   void drawPixel(SplashPipe *pipe, int x, int y, GBool noClip);
@@ -421,6 +434,7 @@ private:
   GBool vectorAntialias;
   GBool inShading;
   GBool debugMode;
+  SplashPixelTracer *pixelTracer;
 };
 
 #endif
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to