[poppler] qt5/src
Albert Astals Cid
aacid at kemper.freedesktop.org
Wed Nov 15 09:47:14 UTC 2017
qt5/src/poppler-page.cc | 254 +++++++++++++++++++++++++++++++++---------------
qt5/src/poppler-qt5.h | 78 ++++++++++++++
2 files changed, 254 insertions(+), 78 deletions(-)
New commits:
commit e0302537ec0919d9f3dbf180ebbc6e2653b1049b
Author: Albert Astals Cid <albert.astals.cid at kdab.com>
Date: Wed Nov 15 10:44:14 2017 +0100
qt5: Add API to let the rendering process callback to get a partial rendering
Bug #103372
diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc
index 9dcdaad9..3341f54c 100644
--- a/qt5/src/poppler-page.cc
+++ b/qt5/src/poppler-page.cc
@@ -19,6 +19,7 @@
* Copyright (C) 2016, Hanno Meyer-Thurow <h.mth at web.de>
* Copyright (C) 2017, Oliver Sander <oliver.sander at tu-dresden.de>
* Copyright (C) 2017 Adrian Johnson <ajohnson at redneon.com>
+ * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by the LiMux project of the city of Munich
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -69,6 +70,120 @@
namespace Poppler {
+class Qt5SplashOutputDev : public SplashOutputDev
+{
+public:
+ Qt5SplashOutputDev(SplashColorMode colorMode, int bitmapRowPad,
+ GBool reverseVideo, bool ignorePaperColorA, SplashColorPtr paperColor,
+ GBool bitmapTopDown, SplashThinLineMode thinLineMode,
+ GBool overprintPreview)
+ : SplashOutputDev(colorMode, bitmapRowPad, reverseVideo, paperColor, bitmapTopDown, thinLineMode, overprintPreview)
+ , partialUpdateCallback(nullptr)
+ , shouldDoPartialUpdateCallback(nullptr)
+ , ignorePaperColor(ignorePaperColorA)
+ {
+ }
+
+ void setPartialUpdateCallbackData(Page::RenderToImagePartialUpdateFunc callback, Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, const QVariant &payloadA)
+ {
+ partialUpdateCallback = callback;
+ shouldDoPartialUpdateCallback = shouldDoCallback;
+ payload = payloadA;
+ }
+
+ void dump() override
+ {
+ if (partialUpdateCallback && shouldDoPartialUpdateCallback && shouldDoPartialUpdateCallback(payload)) {
+ partialUpdateCallback(getXBGRImage( false /* takeImageData */), payload);
+ }
+ }
+
+ QImage getXBGRImage(bool takeImageData)
+ {
+ SplashBitmap *bitmap = getBitmap();
+
+ const int bw = bitmap->getWidth();
+ const int bh = bitmap->getHeight();
+ const int brs = bitmap->getRowSize();
+
+ // If we use DeviceN8, convert to XBGR8.
+ // If requested, also transfer Splash's internal alpha channel.
+ const SplashBitmap::ConversionMode mode = ignorePaperColor
+ ? SplashBitmap::conversionAlphaPremultiplied
+ : SplashBitmap::conversionOpaque;
+
+ const QImage::Format format = ignorePaperColor
+ ? QImage::Format_ARGB32_Premultiplied
+ : QImage::Format_RGB32;
+
+ if (bitmap->convertToXBGR(mode)) {
+ SplashColorPtr data = takeImageData ? bitmap->takeData() : bitmap->getDataPtr();
+
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ // Convert byte order from RGBX to XBGR.
+ for (int i = 0; i < bh; ++i) {
+ for (int j = 0; j < bw; ++j) {
+ SplashColorPtr pixel = &data[i * brs + j];
+
+ qSwap(pixel[0], pixel[3]);
+ qSwap(pixel[1], pixel[2]);
+ }
+ }
+ }
+
+ if (takeImageData) {
+ // Construct a Qt image holding (and also owning) the raw bitmap data.
+ return QImage(data, bw, bh, brs, format, gfree, data);
+ } else {
+ return QImage(data, bw, bh, brs, format).copy();
+ }
+ }
+
+ return QImage();
+ }
+
+private:
+ Page::RenderToImagePartialUpdateFunc partialUpdateCallback;
+ Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback;
+ QVariant payload;
+ bool ignorePaperColor;
+};
+
+
+class QImageDumpingArthurOutputDev : public ArthurOutputDev
+{
+public:
+ QImageDumpingArthurOutputDev(QPainter *painter, QImage *i)
+ : ArthurOutputDev(painter)
+ , partialUpdateCallback(nullptr)
+ , shouldDoPartialUpdateCallback(nullptr)
+ , image(i)
+ {
+ }
+
+ void setPartialUpdateCallbackData(Page::RenderToImagePartialUpdateFunc callback, Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, const QVariant &payloadA)
+ {
+ partialUpdateCallback = callback;
+ shouldDoPartialUpdateCallback = shouldDoCallback;
+ payload = payloadA;
+ }
+
+ void dump() override
+ {
+ if (partialUpdateCallback && shouldDoPartialUpdateCallback && shouldDoPartialUpdateCallback(payload)) {
+ partialUpdateCallback(*image, payload);
+ }
+ }
+
+private:
+ Page::RenderToImagePartialUpdateFunc partialUpdateCallback;
+ Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback;
+ QVariant payload;
+ QImage *image;
+};
+
+
+
Link* PageData::convertLinkActionToLink(::LinkAction * a, const QRectF &linkArea)
{
return convertLinkActionToLink(a, parentDoc, linkArea);
@@ -297,8 +412,59 @@ Page::~Page()
delete m_page;
}
+static bool renderToArthur(ArthurOutputDev *arthur_output, QPainter *painter, PageData *page, double xres, double yres, int x, int y, int w, int h, Page::Rotation rotate, Page::PainterFlags flags)
+{
+ const bool savePainter = !(flags & Page:: DontSaveAndRestore);
+ if (savePainter)
+ painter->save();
+ if (page->parentDoc->m_hints & Document::Antialiasing)
+ painter->setRenderHint(QPainter::Antialiasing);
+ if (page->parentDoc->m_hints & Document::TextAntialiasing)
+ painter->setRenderHint(QPainter::TextAntialiasing);
+ painter->translate(x == -1 ? 0 : -x, y == -1 ? 0 : -y);
+
+ arthur_output->startDoc(page->parentDoc->doc->getXRef());
+
+ const GBool hideAnnotations = page->parentDoc->m_hints & Document::HideAnnotations;
+
+ // Callback that filters out everything but form fields
+ auto annotDisplayDecideCbk = [](Annot *annot, void *user_data)
+ {
+ // Hide everything but forms
+ return (annot->getType() == Annot::typeWidget);
+ };
+
+ // A nullptr, but with the type of a function pointer
+ // Needed to make the ternary operator below happy.
+ GBool (*nullCallBack)(Annot *annot, void *user_data) = nullptr;
+
+ page->parentDoc->doc->displayPageSlice(arthur_output,
+ page->index + 1,
+ xres,
+ yres,
+ (int)rotate * 90,
+ false,
+ true,
+ false,
+ x,
+ y,
+ w,
+ h,
+ nullptr,
+ nullptr,
+ (hideAnnotations) ? annotDisplayDecideCbk : nullCallBack);
+ if (savePainter)
+ painter->restore();
+ return true;
+}
+
QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, Rotation rotate) const
{
+ return renderToImage(xres, yres, x, y, w, h, rotate, nullptr, nullptr, QVariant());
+}
+
+QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, Rotation rotate, RenderToImagePartialUpdateFunc partialUpdateCallback, ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback, const QVariant &payload) const
+{
int rotation = (int)rotate * 90;
QImage img;
switch(m_page->parentDoc->m_backend)
@@ -351,14 +517,17 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
const bool ignorePaperColor = m_page->parentDoc->m_hints & Document::IgnorePaperColor;
- SplashOutputDev splash_output(
+ Qt5SplashOutputDev splash_output(
colorMode, 4,
gFalse,
+ ignorePaperColor,
ignorePaperColor ? NULL : bgColor,
gTrue,
thinLineMode,
overprintPreview);
+ splash_output.setPartialUpdateCallbackData(partialUpdateCallback, shouldDoPartialUpdateCallback, payload);
+
splash_output.setFontAntialias(m_page->parentDoc->m_hints & Document::TextAntialiasing ? gTrue : gFalse);
splash_output.setVectorAntialias(m_page->parentDoc->m_hints & Document::Antialiasing ? gTrue : gFalse);
splash_output.setFreeTypeHinting(m_page->parentDoc->m_hints & Document::TextHinting ? gTrue : gFalse,
@@ -385,40 +554,7 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
(hideAnnotations) ? annotDisplayDecideCbk : nullCallBack,
nullptr, gTrue);
- SplashBitmap *bitmap = splash_output.getBitmap();
-
- const int bw = bitmap->getWidth();
- const int bh = bitmap->getHeight();
- const int brs = bitmap->getRowSize();
-
- // If we use DeviceN8, convert to XBGR8.
- // If requested, also transfer Splash's internal alpha channel.
- const SplashBitmap::ConversionMode mode = ignorePaperColor
- ? SplashBitmap::conversionAlphaPremultiplied
- : SplashBitmap::conversionOpaque;
-
- const QImage::Format format = ignorePaperColor
- ? QImage::Format_ARGB32_Premultiplied
- : QImage::Format_RGB32;
-
- if (bitmap->convertToXBGR(mode)) {
- SplashColorPtr data = bitmap->takeData();
-
- if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- // Convert byte order from RGBX to XBGR.
- for (int i = 0; i < bh; ++i) {
- for (int j = 0; j < bw; ++j) {
- SplashColorPtr pixel = &data[i * brs + j];
-
- qSwap(pixel[0], pixel[3]);
- qSwap(pixel[1], pixel[2]);
- }
- }
- }
-
- // Construct a Qt image holding (and also owning) the raw bitmap data.
- img = QImage(data, bw, bh, brs, format, gfree, data);
- }
+ img = splash_output.getXBGRImage( true /* takeImageData */);
#endif
break;
}
@@ -435,7 +571,9 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h,
tmpimg.fill(bgColor);
QPainter painter(&tmpimg);
- renderToPainter(&painter, xres, yres, x, y, w, h, rotate, DontSaveAndRestore);
+ QImageDumpingArthurOutputDev arthur_output(&painter, &tmpimg);
+ arthur_output.setPartialUpdateCallbackData(partialUpdateCallback, shouldDoPartialUpdateCallback, payload);
+ renderToArthur(&arthur_output, &painter, m_page, xres, yres, x, y, w, h, rotate, DontSaveAndRestore);
painter.end();
img = tmpimg;
break;
@@ -456,48 +594,8 @@ bool Page::renderToPainter(QPainter* painter, double xres, double yres, int x, i
return false;
case Poppler::Document::ArthurBackend:
{
- const bool savePainter = !(flags & DontSaveAndRestore);
- if (savePainter)
- painter->save();
- 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());
-
- const GBool hideAnnotations = m_page->parentDoc->m_hints & Document::HideAnnotations;
-
- // Callback that filters out everything but form fields
- auto annotDisplayDecideCbk = [](Annot *annot, void *user_data)
- {
- // Hide everything but forms
- return (annot->getType() == Annot::typeWidget);
- };
-
- // A nullptr, but with the type of a function pointer
- // Needed to make the ternary operator below happy.
- GBool (*nullCallBack)(Annot *annot, void *user_data) = nullptr;
-
- m_page->parentDoc->doc->displayPageSlice(&arthur_output,
- m_page->index + 1,
- xres,
- yres,
- (int)rotate * 90,
- false,
- true,
- false,
- x,
- y,
- w,
- h,
- nullptr,
- nullptr,
- (hideAnnotations) ? annotDisplayDecideCbk : nullCallBack);
- if (savePainter)
- painter->restore();
- return true;
+ ArthurOutputDev arthur_output(painter);
+ return renderToArthur(&arthur_output, painter, m_page, xres, yres, x, y, w, h, rotate, flags);
}
}
return false;
diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h
index fcfe2d31..4d80bedb 100644
--- a/qt5/src/poppler-qt5.h
+++ b/qt5/src/poppler-qt5.h
@@ -17,6 +17,7 @@
* Copyright (C) 2013 Anthony Granger <grangeranthony at gmail.com>
* Copyright (C) 2016 Jakub Alba <jakubalba at gmail.com>
* Copyright (C) 2017 Oliver Sander <oliver.sander at tu-dresden.de>
+ * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by the LiMux project of the city of Munich
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -492,6 +493,83 @@ 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;
+ /**
+ Partial Update renderToImage callback.
+
+ This function type is used for doing partial rendering updates;
+ the first parameter is the image as rendered up to now, the second is the unaltered
+ closure argument which was passed to the renderToImage call.
+
+ \since 0.62
+ */
+ typedef void (*RenderToImagePartialUpdateFunc)(const QImage & /*image*/, const QVariant & /*closure*/);
+
+ /**
+ Partial Update query renderToImage callback.
+
+ This function type is used for query if the partial rendering update should happen;
+ the parameter is the unaltered closure argument which was passed to the renderToImage call.
+
+ \since 0.62
+ */
+ typedef bool (*ShouldRenderToImagePartialQueryFunc)(const QVariant & /*closure*/);
+
+ /**
+ Render the page to a QImage 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
+
+ \param partialUpdateCallback callback that will be called to
+ report a partial rendering update
+
+ \param shouldDoPartialUpdateCallback callback that will be called
+ to ask if a partial rendering update is wanted. This exists
+ because doing a partial rendering update needs to copy the image
+ buffer so if it is not wanted it is better skipped early.
+
+ \param closure opaque structure that will be passed
+ back to partialUpdateCallback and shouldDoPartialUpdateCallback.
+
+ \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.
+
+ \returns a QImage of the page, or a null image on failure.
+
+ \since 0.62
+ */
+ QImage renderToImage(double xres, double yres,
+ int x, int y, int w, int h, Rotation rotate,
+ RenderToImagePartialUpdateFunc partialUpdateCallback,
+ ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback,
+ const QVariant &closure
+ ) const;
+
/**
Render the page to the specified QPainter using the current
\link Document::renderBackend() Document renderer\endlink.
More information about the poppler
mailing list