Hello again,

The Splash output device internally supports using a NULL paper colour
which means that it will not try to compose with that colour keeping the
original alpha channel depending on the image format used. Since alpha
blending with the paper colour is one of the single most expensive
operations when rendering using Splash and the consuming application can
often use a hardware-accelerated operation via its toolkit, removing
this has significant performance implications.

The attached patch exposes this functionality as a render hint in the
Qt4 and Qt5 frontends and extends the SplashBitmap::convertToXBGR method
to copy Splash's internal separate alpha channel into the fourth
component actually yielding Qt's ABGR32 image format. The partial
copying is still expensive, but only half as expensive as composing with
the paper colour in terms of CPU cycles. The net gain in synthetic
rendering benchmarks and timing of a GUI application was around five
percent. Also it might be desirable for an application to gain access to
the uncomposed image for further custom image composition.

The patch also removes an unnecessary copy from the Qt5 frontend as
QImage is now able to take a clean-up handler which will properly free
Splash's raw bitmap data when the Qt image is destroyed. This improves
the speed of synthetic rendering benchmarks by another four percent.

Therefore for a Qt5-using application that does alpha blending
separately should see an improvement of around eight percent for
rendering using this patch.

Best regards, Adam.

P.S.: I will get back to GooString as soon as I find the time, but as
Albert pointed out, there is just more to gain here.
From 135624f165db4cf75608f8cbb6a7da37a591503d Mon Sep 17 00:00:00 2001
From: Adam Reichold <[email protected]>
Date: Thu, 2 Jul 2015 21:00:16 +0200
Subject: [PATCH 1/4] Make SplashBitmap XBGR transfer alpha channel

Adds an option to SplashBitmap::convertToXBGR and SplashBitmap::getXBGRLine
so that both optionally transfer Splash's internal alpha channel into the
fourth component of the resulting bitmap data.
---
 splash/SplashBitmap.cc | 27 ++++++++++++++++++++++-----
 splash/SplashBitmap.h  |  4 ++--
 2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index e886683..7da373b 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -460,7 +460,7 @@ void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) {
   }
 }
 
-void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line) {
+void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line, bool useAlpha) {
   SplashColor col;
   double c, m, y, k, c1, m1, y1, k1, r, g, b;
 
@@ -503,20 +503,37 @@ void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line) {
     *line++ = dblToByte(clip01(b));
     *line++ = dblToByte(clip01(g));
     *line++ = dblToByte(clip01(r));
-    *line++ = 255;
+    *line++ = useAlpha ? getAlpha(x, yl) : 255;
   }
 }
 
-GBool SplashBitmap::convertToXBGR() {
-  if (mode == splashModeXBGR8)
+GBool SplashBitmap::convertToXBGR(bool useAlpha) {
+  if (mode == splashModeXBGR8) {
+    if (useAlpha) {
+      // Copy the alpha channel into the fourth component so that XBGR becomes ABGR.
+      const SplashColorPtr dbegin = data;
+      const SplashColorPtr dend = data + rowSize * height;
+
+      Guchar *const abegin = alpha;
+      Guchar *const aend = alpha + width * height;
+
+      SplashColorPtr d = dbegin + 3;
+      Guchar *a = abegin;
+
+      for(; d < dend && a < aend; d += 4, a += 1) {
+        *d = *a;
+      }
+    }
+
     return gTrue;
+  }
   
   int newrowSize = width * 4;
   SplashColorPtr newdata = (SplashColorPtr)gmallocn_checkoverflow(newrowSize, height);
   if (newdata != NULL) {
     for (int y = 0; y < height; y++) {
       unsigned char *row = newdata + y * newrowSize;
-      getXBGRLine(y, row);
+      getXBGRLine(y, row, useAlpha);
     }
     if (rowSize < 0) {
       gfree(data + (height - 1) * rowSize);
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index 70509ab..99879fb 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -75,11 +75,11 @@ public:
   SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, const char *compressionString = "");
   SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI);
 
-  GBool convertToXBGR();
+  GBool convertToXBGR(bool useAlpha = false);
 
   void getPixel(int x, int y, SplashColorPtr pixel);
   void getRGBLine(int y, SplashColorPtr line);
-  void getXBGRLine(int y, SplashColorPtr line);
+  void getXBGRLine(int y, SplashColorPtr line, bool useAlpha = false);
 #if SPLASH_CMYK
   void getCMYKLine(int y, SplashColorPtr line);
 #endif
-- 
2.4.5


From 29d0ed18f135339bb567f65b1b3496b3dc5b01b6 Mon Sep 17 00:00:00 2001
From: Adam Reichold <[email protected]>
Date: Thu, 2 Jul 2015 21:02:59 +0200
Subject: [PATCH 2/4] Add KeepAlphaChannel render flag to Qt5 frontend

Adds a new render flag which will indicate that the image return by
Poppler::Page::renderToImage will not be opaque and alpha blended with
paper colour, but retain its actually background transparency.

This improves performance in synthentic rendering benchmarks by almost
five percent and the additional alpha blending that is then done by the
consuming application is often a hardware-accellerated operation.
---
 qt5/src/poppler-page.cc | 6 ++++--
 qt5/src/poppler-qt5.h   | 3 ++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc
index 408099c..07ad9b6 100644
--- a/qt5/src/poppler-page.cc
+++ b/qt5/src/poppler-page.cc
@@ -331,13 +331,15 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
       if (m_page->parentDoc->m_hints & Document::ThinLineShape) thinLineMode = splashThinLineShape;
       if (m_page->parentDoc->m_hints & Document::ThinLineSolid) thinLineMode = splashThinLineSolid;
 
+      const bool keepAlphaChannel = m_page->parentDoc->m_hints & Document::KeepAlphaChannel;
+
       SplashOutputDev * splash_output = new SplashOutputDev(
 #if defined(SPLASH_CMYK)
                       (overprint) ? splashModeDeviceN8 : splashModeXBGR8,
 #else
                       splashModeXBGR8,
 #endif 
-                      4, gFalse, bgColor, gTrue, thinLineMode, overprint);
+                      4, gFalse, keepAlphaChannel ? NULL : bgColor, gTrue, thinLineMode, overprint);
 
       splash_output->setFontAntialias(m_page->parentDoc->m_hints & Document::TextAntialiasing ? gTrue : gFalse);
       splash_output->setVectorAntialias(m_page->parentDoc->m_hints & Document::Antialiasing ? gTrue : gFalse);
@@ -354,7 +356,7 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
       int bw = bitmap->getWidth();
       int bh = bitmap->getHeight();
 
-      if (bitmap->convertToXBGR())
+      if (bitmap->convertToXBGR(keepAlphaChannel))
       {
         SplashColorPtr dataPtr = bitmap->getDataPtr();
 
diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h
index 79c3f74..fa23844 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -891,7 +891,8 @@ delete it;
 	    TextSlightHinting = 0x00000008, ///< Lighter hinting for text when combined with TextHinting \since 0.18
 	    OverprintPreview = 0x00000010,  ///< Overprint preview \since 0.22
 	    ThinLineSolid = 0x00000020,     ///< Enhance thin lines solid \since 0.24
-	    ThinLineShape = 0x00000040      ///< Enhance thin lines shape. Wins over ThinLineSolid \since 0.24
+            ThinLineShape = 0x00000040,     ///< Enhance thin lines shape. Wins over ThinLineSolid \since 0.24
+            KeepAlphaChannel = 0x00000080   ///< Do not compose with the paper color \since 0.34
 	};
 	Q_DECLARE_FLAGS( RenderHints, RenderHint )
 
-- 
2.4.5


From e5f9a68df1b6fc9cb310a1ae6a5211028fdebccc Mon Sep 17 00:00:00 2001
From: Adam Reichold <[email protected]>
Date: Thu, 2 Jul 2015 21:08:38 +0200
Subject: [PATCH 3/4] Improve efficiency of Poppler::Page::renderToImage

Improves the efficiency of rendering into a QImage using
the Splash output device by removing a copy of the raw bitmap data
since Qt5 will properly free this data using a function supplied
during construction, i.e. in this case gfree.

This improves performance in synthentic rendering benchmarks
by approximately four percent and reduces the maximum working set size.
---
 qt5/src/poppler-page.cc | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc
index 07ad9b6..d2fa3dd 100644
--- a/qt5/src/poppler-page.cc
+++ b/qt5/src/poppler-page.cc
@@ -358,7 +358,7 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
 
       if (bitmap->convertToXBGR(keepAlphaChannel))
       {
-        SplashColorPtr dataPtr = bitmap->getDataPtr();
+        SplashColorPtr dataPtr = bitmap->takeData();
 
         if (QSysInfo::BigEndian == QSysInfo::ByteOrder)
         {
@@ -376,9 +376,8 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
             }
         }
 
-        // construct a qimage SHARING the raw bitmap data in memory
-        QImage tmpimg( dataPtr, bw, bh, QImage::Format_ARGB32 );
-        img = tmpimg.copy();
+        // Construct a Qt image holding (and also owning) the raw bitmap data.
+        img = QImage(dataPtr, bw, bh, QImage::Format_ARGB32, gfree, dataPtr);
       }
       delete splash_output;
 #endif
-- 
2.4.5


From 9ac656a014855428af48ce98f4fea8de1e286fdd Mon Sep 17 00:00:00 2001
From: Adam Reichold <[email protected]>
Date: Thu, 2 Jul 2015 21:15:39 +0200
Subject: [PATCH 4/4] Add KeepAlphaChannel render flag to Qt4 frontend

Replicates the Qt5 frontend's KeepAlphaChannel flag providing
the same interface and functionality.
---
 qt4/src/poppler-page.cc | 6 ++++--
 qt4/src/poppler-qt4.h   | 3 ++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc
index 49ad871..55abf8a 100644
--- a/qt4/src/poppler-page.cc
+++ b/qt4/src/poppler-page.cc
@@ -331,13 +331,15 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
       if (m_page->parentDoc->m_hints & Document::ThinLineShape) thinLineMode = splashThinLineShape;
       if (m_page->parentDoc->m_hints & Document::ThinLineSolid) thinLineMode = splashThinLineSolid;
 
+      const bool keepAlphaChannel = m_page->parentDoc->m_hints & Document::KeepAlphaChannel;
+
       SplashOutputDev * splash_output = new SplashOutputDev(
 #if defined(SPLASH_CMYK)
                       (overprint) ? splashModeDeviceN8 : splashModeXBGR8,
 #else
                       splashModeXBGR8,
 #endif 
-                      4, gFalse, bgColor, gTrue, thinLineMode, overprint);
+                      4, gFalse, keepAlphaChannel ? NULL : bgColor, gTrue, thinLineMode, overprint);
 
       splash_output->setFontAntialias(m_page->parentDoc->m_hints & Document::TextAntialiasing ? gTrue : gFalse);
       splash_output->setVectorAntialias(m_page->parentDoc->m_hints & Document::Antialiasing ? gTrue : gFalse);
@@ -354,7 +356,7 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
       int bw = bitmap->getWidth();
       int bh = bitmap->getHeight();
 
-      if (bitmap->convertToXBGR())
+      if (bitmap->convertToXBGR(keepAlphaChannel))
       {
         SplashColorPtr dataPtr = bitmap->getDataPtr();
 
diff --git a/qt4/src/poppler-qt4.h b/qt4/src/poppler-qt4.h
index e5e808d..b4494e3 100644
--- a/qt4/src/poppler-qt4.h
+++ b/qt4/src/poppler-qt4.h
@@ -901,7 +901,8 @@ delete it;
 	    TextSlightHinting = 0x00000008, ///< Lighter hinting for text when combined with TextHinting \since 0.18
 	    OverprintPreview = 0x00000010,  ///< Overprint preview \since 0.22
 	    ThinLineSolid = 0x00000020,     ///< Enhance thin lines solid \since 0.24
-	    ThinLineShape = 0x00000040      ///< Enhance thin lines shape. Wins over ThinLineSolid \since 0.24
+            ThinLineShape = 0x00000040,     ///< Enhance thin lines shape. Wins over ThinLineSolid \since 0.24
+            KeepAlphaChannel = 0x00000080   ///< Do not compose with the paper color \since 0.34
 	};
 	Q_DECLARE_FLAGS( RenderHints, RenderHint )
 
-- 
2.4.5

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to