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
signature.asc
Description: OpenPGP digital signature
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
