qt5/src/poppler-page.cc | 148 ++++++++++++++++++++++++++++-------------------- qt5/src/poppler-qt5.h | 98 +++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 61 deletions(-)
New commits: commit b1016f574ac63fa269ca5125827895220e1df883 Author: Albert Astals Cid <albert.astals....@kdab.com> Date: Thu Feb 1 22:46:33 2018 +0100 Qt5: Add cancellation support to renderToImage and textList diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc index 174d5857..f4c88de3 100644 --- a/qt5/src/poppler-page.cc +++ b/qt5/src/poppler-page.cc @@ -19,7 +19,7 @@ * Copyright (C) 2016, Hanno Meyer-Thurow <h....@web.de> * Copyright (C) 2017, Oliver Sander <oliver.san...@tu-dresden.de> * Copyright (C) 2017 Adrian Johnson <ajohn...@redneon.com> - * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, <i...@kdab.com>. Work sponsored by the LiMux project of the city of Munich + * Copyright (C) 2017, 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <i...@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 @@ -70,27 +70,48 @@ namespace Poppler { -class Qt5SplashOutputDev : public SplashOutputDev +class TextExtractionAbortHelper { 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) + TextExtractionAbortHelper(Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA) { + shouldAbortExtractionCallback = shouldAbortCallback; + payload = payloadA; } - void setPartialUpdateCallbackData(Page::RenderToImagePartialUpdateFunc callback, Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, const QVariant &payloadA) + Page::ShouldAbortQueryFunc shouldAbortExtractionCallback = nullptr; + QVariant payload; +}; + +class OutputDevCallbackHelper +{ +public: + void setCallbacks(Page::RenderToImagePartialUpdateFunc callback, Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA) { partialUpdateCallback = callback; shouldDoPartialUpdateCallback = shouldDoCallback; + shouldAbortRenderCallback = shouldAbortCallback; payload = payloadA; } + Page::RenderToImagePartialUpdateFunc partialUpdateCallback = nullptr; + Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback = nullptr; + Page::ShouldAbortQueryFunc shouldAbortRenderCallback = nullptr; + QVariant payload; +}; + +class Qt5SplashOutputDev : public SplashOutputDev, public OutputDevCallbackHelper +{ +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) + , ignorePaperColor(ignorePaperColorA) + { + } + void dump() override { if (partialUpdateCallback && shouldDoPartialUpdateCallback && shouldDoPartialUpdateCallback(payload)) { @@ -143,31 +164,19 @@ public: } private: - Page::RenderToImagePartialUpdateFunc partialUpdateCallback; - Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback; - QVariant payload; bool ignorePaperColor; }; -class QImageDumpingArthurOutputDev : public ArthurOutputDev +class QImageDumpingArthurOutputDev : public ArthurOutputDev, public OutputDevCallbackHelper { 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)) { @@ -176,9 +185,6 @@ public: } private: - Page::RenderToImagePartialUpdateFunc partialUpdateCallback; - Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback; - QVariant payload; QImage *image; }; @@ -412,7 +418,34 @@ 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) +// Callback that filters out everything but form fields +static 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 happy. +static GBool (*nullAnnotCallBack)(Annot *annot, void *user_data) = nullptr; + +static auto shouldAbortRenderInternalCallback = [](void *user_data) +{ + OutputDevCallbackHelper *helper = reinterpret_cast<OutputDevCallbackHelper*>(user_data); + return helper->shouldAbortRenderCallback(helper->payload); +}; + +static auto shouldAbortExtractionInternalCallback = [](void *user_data) +{ + TextExtractionAbortHelper *helper = reinterpret_cast<TextExtractionAbortHelper*>(user_data); + return helper->shouldAbortExtractionCallback(helper->payload); +}; + +// A nullptr, but with the type of a function pointer +// Needed to make the ternary operator happy. +static GBool (*nullAbortCallBack)(void *user_data) = nullptr; + +static bool renderToArthur(QImageDumpingArthurOutputDev *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) @@ -427,17 +460,7 @@ static bool renderToArthur(ArthurOutputDev *arthur_output, QPainter *painter, Pa 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; - + OutputDevCallbackHelper *abortHelper = arthur_output; page->parentDoc->doc->displayPageSlice(arthur_output, page->index + 1, xres, @@ -450,9 +473,9 @@ static bool renderToArthur(ArthurOutputDev *arthur_output, QPainter *painter, Pa y, w, h, - nullptr, - nullptr, - (hideAnnotations) ? annotDisplayDecideCbk : nullCallBack); + abortHelper->shouldAbortRenderCallback ? shouldAbortRenderInternalCallback : nullAbortCallBack, + abortHelper, + (hideAnnotations) ? annotDisplayDecideCbk : nullAnnotCallBack); if (savePainter) painter->restore(); return true; @@ -465,6 +488,11 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, 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 { + return renderToImage(xres, yres, x, y, w, h, rotate, partialUpdateCallback, shouldDoPartialUpdateCallback, nullptr, payload); +} + +QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, Rotation rotate, RenderToImagePartialUpdateFunc partialUpdateCallback, ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback, ShouldAbortQueryFunc shouldAbortRenderCallback, const QVariant &payload) const +{ int rotation = (int)rotate * 90; QImage img; switch(m_page->parentDoc->m_backend) @@ -526,7 +554,7 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, thinLineMode, overprintPreview); - splash_output.setPartialUpdateCallbackData(partialUpdateCallback, shouldDoPartialUpdateCallback, payload); + splash_output.setCallbacks(partialUpdateCallback, shouldDoPartialUpdateCallback, shouldAbortRenderCallback, 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); @@ -537,21 +565,11 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, 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; - + OutputDevCallbackHelper *abortHelper = &splash_output; m_page->parentDoc->doc->displayPageSlice(&splash_output, m_page->index + 1, xres, yres, rotation, false, true, false, x, y, w, h, - nullptr, nullptr, - (hideAnnotations) ? annotDisplayDecideCbk : nullCallBack, + shouldAbortRenderCallback ? shouldAbortRenderInternalCallback : nullAbortCallBack, abortHelper, + (hideAnnotations) ? annotDisplayDecideCbk : nullAnnotCallBack, nullptr, gTrue); img = splash_output.getXBGRImage( true /* takeImageData */); @@ -572,7 +590,7 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, QPainter painter(&tmpimg); QImageDumpingArthurOutputDev arthur_output(&painter, &tmpimg); - arthur_output.setPartialUpdateCallbackData(partialUpdateCallback, shouldDoPartialUpdateCallback, payload); + arthur_output.setCallbacks(partialUpdateCallback, shouldDoPartialUpdateCallback, shouldAbortRenderCallback, payload); renderToArthur(&arthur_output, &painter, m_page, xres, yres, x, y, w, h, rotate, DontSaveAndRestore); painter.end(); img = tmpimg; @@ -580,6 +598,9 @@ QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, } } + if (shouldAbortRenderCallback && shouldAbortRenderCallback(payload)) + return QImage(); + return img; } @@ -594,7 +615,7 @@ bool Page::renderToPainter(QPainter* painter, double xres, double yres, int x, i return false; case Poppler::Document::ArthurBackend: { - ArthurOutputDev arthur_output(painter); + QImageDumpingArthurOutputDev arthur_output(painter, nullptr); return renderToArthur(&arthur_output, painter, m_page, xres, yres, x, y, w, h, rotate, flags); } } @@ -713,6 +734,11 @@ QList<QRectF> Page::search(const QString &text, SearchFlags flags, Rotation rota QList<TextBox*> Page::textList(Rotation rotate) const { + return textList(rotate, nullptr, QVariant()); +} + +QList<TextBox*> Page::textList(Rotation rotate, ShouldAbortQueryFunc shouldAbortExtractionCallback, const QVariant &closure) const +{ TextOutputDev *output_dev; QList<TextBox*> output_list; @@ -721,13 +747,15 @@ QList<TextBox*> Page::textList(Rotation rotate) const int rotation = (int)rotate * 90; + TextExtractionAbortHelper abortHelper(shouldAbortExtractionCallback, closure); m_page->parentDoc->doc->displayPageSlice(output_dev, m_page->index + 1, 72, 72, rotation, false, false, false, -1, -1, -1, -1, - nullptr, nullptr, nullptr, nullptr, gTrue); + shouldAbortExtractionCallback ? shouldAbortExtractionInternalCallback : nullAbortCallBack, &abortHelper, + nullptr, nullptr, gTrue); TextWordList *word_list = output_dev->makeWordList(); - if (!word_list) { + if (!word_list || (shouldAbortExtractionCallback && shouldAbortExtractionCallback(closure))) { delete output_dev; return output_list; } diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h index 2c30e5ec..3adbf02f 100644 --- a/qt5/src/poppler-qt5.h +++ b/qt5/src/poppler-qt5.h @@ -17,7 +17,7 @@ * Copyright (C) 2013 Anthony Granger <grangeranth...@gmail.com> * Copyright (C) 2016 Jakub Alba <jakuba...@gmail.com> * Copyright (C) 2017 Oliver Sander <oliver.san...@tu-dresden.de> - * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, <i...@kdab.com>. Work sponsored by the LiMux project of the city of Munich + * Copyright (C) 2017, 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <i...@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 @@ -571,6 +571,76 @@ delete it; const QVariant &closure ) const; + /** + Abort query function callback. + + This function type is used for query if the current rendering/text extraction should be cancelled. + + \since 0.63 + */ + typedef bool (*ShouldAbortQueryFunc)(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 shouldAbortRenderCallback callback that will be called + to ask if the rendering should be cancelled. + + \param closure opaque structure that will be passed + back to partialUpdateCallback, shouldDoPartialUpdateCallback + and shouldAbortRenderCallback. + + \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.63 + */ + QImage renderToImage(double xres, double yres, + int x, int y, int w, int h, Rotation rotate, + RenderToImagePartialUpdateFunc partialUpdateCallback, + ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback, + ShouldAbortQueryFunc shouldAbortRenderCallback, + const QVariant &closure + ) const; + /** Render the page to the specified QPainter using the current \link Document::renderBackend() Document renderer\endlink. @@ -745,6 +815,32 @@ delete it; QList<TextBox*> textList(Rotation rotate = Rotate0) const; /** + Returns a list of text of the page + + This method returns a QList of TextBoxes that contain all + the text of the page, with roughly one text word of text + per TextBox item. + + For text written in western languages (left-to-right and + up-to-down), the QList contains the text in the proper + order. + + \param shouldAbortExtractionCallback callback that will be called + to ask if the text extraction should be cancelled. + + \param closure opaque structure that will be passed + back to shouldAbortExtractionCallback. + + \note The caller owns the text boxes and they should + be deleted when no longer required. + + \warning This method is not tested with Asian scripts + + // \since 0.63 + */ + QList<TextBox*> textList(Rotation rotate, ShouldAbortQueryFunc shouldAbortExtractionCallback, const QVariant &closure) const; + + /** \return The dimensions (cropbox) of the page, in points (i.e. 1/72th of an inch) */ QSizeF pageSizeF() const; _______________________________________________ poppler mailing list poppler@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/poppler