[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