Hi,
I'm currently using Poppler for a score player application, and since
the synthesizer is already using all my memory and CPU, I wanted to
render the PDF using the GPU.

I wonder why it seems nobody cares about the Arthur backend ?

The first patch contains two easy fixes for Arthur :
- font rendering (transforming the glyph path and not only the glyph origin).
- image rendering (alpha was set to zero).

The second patch expose the QPainter interface directly through a
renderToPainter method which use an existing painter instead of
creating an image.
This allows to directly render the PDF using OpenGL, and since the
painting is fast, there is no need to cache prerendered pages. so it's
using less CPU and less memory.

in case you want to try the QGraphicsView OpenGL PDF renderer:
http://gitorious.org/qt-pdfviewer (only needs Qt and Poppler, the
other deps are optionnal)
diff --git a/poppler/ArthurOutputDev.cc b/poppler/ArthurOutputDev.cc
index 7573f3f..26b91b5 100644
--- a/poppler/ArthurOutputDev.cc
+++ b/poppler/ArthurOutputDev.cc
@@ -559,6 +559,7 @@ void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
 			       CharCode code, int nBytes, Unicode *u, int uLen) {
 #ifdef HAVE_SPLASH
   double x1, y1;
+  double x2, y2;
 //   SplashPath *path;
   int render;
 
@@ -577,39 +578,36 @@ void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
 
   x -= originX;
   y -= originY;
-  state->transform(x, y, &x1, &y1);
+  //state->transform(x, y, &x1, &y1);
 
   // fill
   if (!(render & 1)) {
-    int x0, y0, xFrac, yFrac;
-
-    x0 = static_cast<int>(floor(x1));
-    xFrac = splashFloor((x1 - x0) * splashFontFraction);
-    y0 = static_cast<int>(floor(y1));
-    yFrac = splashFloor((y1 - y0) * splashFontFraction);
     SplashPath * fontPath;
     fontPath = m_font->getGlyphPath(code);
     if (fontPath) {
       QPainterPath qPath;
       qPath.setFillRule(Qt::WindingFill);
       for (int i = 0; i < fontPath->length; ++i) {
-	if (fontPath->flags[i] & splashPathFirst) {
-	  qPath.moveTo(fontPath->pts[i].x+x0, fontPath->pts[i].y+y0);
-	} else if (fontPath->flags[i] & splashPathCurve) {
-	  qPath.quadTo(fontPath->pts[i].x+x0, fontPath->pts[i].y+y0,
-		       fontPath->pts[i+1].x+x0, fontPath->pts[i+1].y+y0);
-	  ++i;
-	}
-// FIXME fix this
-// 	else if (fontPath->flags[i] & splashPathArcCW) {
-// 	  qDebug() << "Need to implement arc";
-// 	}
-	else {
-	  qPath.lineTo(fontPath->pts[i].x+x0, fontPath->pts[i].y+y0);
-	}
-	if (fontPath->flags[i] & splashPathLast) {
-	  qPath.closeSubpath();
-	}
+        if (fontPath->flags[i] & splashPathFirst) {
+            state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
+            qPath.moveTo(x1,y1);
+        } else if (fontPath->flags[i] & splashPathCurve) {
+            state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
+            state->transform(fontPath->pts[i+1].x+x, -fontPath->pts[i+1].y+y, &x2, &y2);
+            qPath.quadTo(x1,y1,x2,y2);
+            ++i;
+        }
+        // FIXME fix this
+        // 	else if (fontPath->flags[i] & splashPathArcCW) {
+        // 	  qDebug() << "Need to implement arc";
+        // 	}
+        else {
+            state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
+            qPath.lineTo(x1,y1);
+        }
+        if (fontPath->flags[i] & splashPathLast) {
+            qPath.closeSubpath();
+        }
       }
       m_painter->save();
       GfxRGB rgb;
@@ -772,8 +770,6 @@ void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   QMatrix matrix;
   int is_identity_transform;
   
-  buffer = (unsigned char *)gmallocn3(width, height, 4);
-
   /* TODO: Do we want to cache these? */
   imgStr = new ImageStream(str, width,
 			   colorMap->getNumPixelComps(),
@@ -787,35 +783,32 @@ void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
 		  ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB);
 
   if (maskColors) {
+    m_image = new QImage(width, height, QImage::Format_ARGB32);
     for (y = 0; y < height; y++) {
-      dest = (unsigned int *) (buffer + y * 4 * width);
+      dest = (unsigned int *)m_image->scanLine(y);
       pix = imgStr->getLine();
       colorMap->getRGBLine (pix, dest, width);
 
       for (x = 0; x < width; x++) {
-	for (i = 0; i < colorMap->getNumPixelComps(); ++i) {
-	  
-	  if (pix[i] < maskColors[2*i] * 255||
-	      pix[i] > maskColors[2*i+1] * 255) {
-	    *dest = *dest | 0xff000000;
-	    break;
-	  }
-	}
-	pix += colorMap->getNumPixelComps();
-	dest++;
+        for (i = 0; i < colorMap->getNumPixelComps(); ++i) {
+            if (pix[i] < maskColors[2*i] * 255||
+                pix[i] > maskColors[2*i+1] * 255) {
+                *dest = *dest | 0xff000000;
+                break;
+            }
+        }
+        pix += colorMap->getNumPixelComps();
+        dest++;
       }
     }
-
-    m_image = new QImage(buffer, width, height, QImage::Format_ARGB32);
   }
   else {
+    m_image = new QImage(width, height, QImage::Format_RGB32);
     for (y = 0; y < height; y++) {
-      dest = (unsigned int *) (buffer + y * 4 * width);
-      pix = imgStr->getLine();
-      colorMap->getRGBLine (pix, dest, width);
+        dest = (unsigned int *)m_image->scanLine(y);
+        colorMap->getRGBLine (imgStr->getLine(), dest, width);
+        for (x = 0; x < width; x++) { *dest = *dest | 0xff000000; dest++; }
     }
-
-    m_image = new QImage(buffer, width, height, QImage::Format_RGB32);
   }
 
   if (m_image == NULL || m_image->isNull()) {
@@ -830,7 +823,6 @@ void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   m_painter->drawImage( QPoint(0,0), *m_image );
   delete m_image;
   m_image = 0;
-  free (buffer);
   delete imgStr;
 
 }
diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc
index ae67b11..5cd2cef 100644
--- a/qt4/src/poppler-page.cc
+++ b/qt4/src/poppler-page.cc
@@ -277,6 +277,39 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
   return img;
 }
 
+void Page::renderToPainter(QPainter* painter, double xres, double yres, int x, int y, int w, int h, Rotation rotate) const
+{
+  int rotation = (int)rotate * 90;
+  switch(m_page->parentDoc->m_backend)
+  {
+    case Poppler::Document::ArthurBackend:
+    {
+      QSize size = pageSize();
+
+      if (m_page->parentDoc->m_hints & Document::Antialiasing)
+          painter->setRenderHint(QPainter::Antialiasing);
+      if (m_page->parentDoc->m_hints & Document::TextAntialiasing)
+          painter->setRenderHint(QPainter::TextAntialiasing);
+      painter->translate(x == -1 ? 0 : -x, y == -1 ? 0 : -y);
+      ArthurOutputDev arthur_output(painter);
+      arthur_output.startDoc(m_page->parentDoc->doc->getXRef());
+      m_page->parentDoc->doc->displayPageSlice(&arthur_output,
+                                                 m_page->index + 1,
+                                                 xres,
+                                                 yres,
+                                                 rotation,
+                                                 false,
+                                                 true,
+                                                 false,
+                                                 x,
+                                                 y,
+                                                 w,
+                                                 h);
+      break;
+    }
+  }
+}
+
 QImage Page::thumbnail() const
 {
   unsigned char* data = 0;
diff --git a/qt4/src/poppler-qt4.h b/qt4/src/poppler-qt4.h
index 117dc43..f4ffd66 100644
--- a/qt4/src/poppler-qt4.h
+++ b/qt4/src/poppler-qt4.h
@@ -428,6 +428,46 @@ delete it;
         */
 	QImage renderToImage(double xres=72.0, double yres=72.0, int x=-1, int y=-1, int w=-1, int h=-1, Rotation rotate = Rotate0) const;
 
+        /**
+           Render the page to a QPainter using the current
+           \link Document::renderBackend() Document renderer\endlink.
+
+           If \p x = \p y = \p w = \p h = -1, the method will automatically
+           compute the size of the image from the horizontal and vertical
+           resolutions specified in \p xres and \p yres. Otherwise, the
+           method renders only a part of the page, specified by the
+           parameters (\p x, \p y, \p w, \p h) in pixel coordinates. The returned
+           QImage then has size (\p w, \p h), independent of the page
+           size.
+
+           \param x specifies the left x-coordinate of the box, in
+           pixels.
+
+           \param y specifies the top y-coordinate of the box, in
+           pixels.
+
+           \param w specifies the width of the box, in pixels.
+
+           \param h specifies the height of the box, in pixels.
+
+           \param xres horizontal resolution of the graphics device,
+           in dots per inch
+
+           \param yres vertical resolution of the graphics device, in
+           dots per inch
+
+           \param rotate how to rotate the page
+
+           \warning The parameter (\p x, \p y, \p w, \p h) are not
+           well-tested. Unusual or meaningless parameters may lead to
+           rather unexpected results.
+
+           \warning This method is only supported for Arthur and Cairo Qt backends
+
+           \since 0.6
+        */
+        void renderToPainter(QPainter* painter, double xres=72.0, double yres=72.0, int x=-1, int y=-1, int w=-1, int h=-1, Rotation rotate = Rotate0) const;
+
 	/**
 	   Get the page thumbnail if it exists.
 
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to