diff --git qt5/src/poppler-page.cc qt5/src/poppler-page.cc index 4b30d9da..2c411a9a 100644 --- qt5/src/poppler-page.cc +++ qt5/src/poppler-page.cc @@ -346,212 +346,121 @@ static auto annotDisplayDecideCbk = [](Annot *annot, void *user_data) // 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(user_data); return helper->shouldAbortRenderCallback(helper->payload); }; static auto shouldAbortExtractionInternalCallback = [](void *user_data) { TextExtractionAbortHelper *helper = reinterpret_cast(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) - 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); - +static void renderToPage(Qt5OutputDev *outputDev, PageData *page, double xres, double yres, int x, int y, int w, int h, Page::Rotation rotate, GBool copyXRef) { + outputDev->startDoc(page->parentDoc->doc); const GBool hideAnnotations = page->parentDoc->m_hints & Document::HideAnnotations; - - OutputDevCallbackHelper *abortHelper = arthur_output; - page->parentDoc->doc->displayPageSlice(arthur_output, + OutputDevCallbackHelper *abortHelper = outputDev->callbackHelper(); + page->parentDoc->doc->displayPageSlice(outputDev->outputDev(), page->index + 1, xres, yres, (int)rotate * 90, false, true, false, x, y, w, h, abortHelper->shouldAbortRenderCallback ? shouldAbortRenderInternalCallback : nullAbortCallBack, abortHelper, - (hideAnnotations) ? annotDisplayDecideCbk : nullAnnotCallBack); - if (savePainter) - painter->restore(); - return true; + (hideAnnotations) ? annotDisplayDecideCbk : nullAnnotCallBack, + nullptr, + copyXRef); } 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 { 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) { case Poppler::Document::SplashBackend: { #if defined(HAVE_SPLASH) - SplashColor bgColor; - GBool overprintPreview = gFalse; -#ifdef SPLASH_CMYK - overprintPreview = m_page->parentDoc->m_hints & Document::OverprintPreview ? gTrue : gFalse; - if (overprintPreview) - { - Guchar c, m, y, k; - - c = 255 - m_page->parentDoc->paperColor.blue(); - m = 255 - m_page->parentDoc->paperColor.red(); - y = 255 - m_page->parentDoc->paperColor.green(); - k = c; - if (m < k) { - k = m; - } - if (y < k) { - k = y; - } - bgColor[0] = c - k; - bgColor[1] = m - k; - bgColor[2] = y - k; - bgColor[3] = k; - for (int i = 4; i < SPOT_NCOMPS + 4; i++) { - bgColor[i] = 0; - } - } - else -#endif - { - bgColor[0] = m_page->parentDoc->paperColor.blue(); - bgColor[1] = m_page->parentDoc->paperColor.green(); - bgColor[2] = m_page->parentDoc->paperColor.red(); - } - - SplashColorMode colorMode = splashModeXBGR8; -#ifdef SPLASH_CMYK - if (overprintPreview) colorMode = splashModeDeviceN8; -#endif - - SplashThinLineMode thinLineMode = splashThinLineDefault; - if (m_page->parentDoc->m_hints & Document::ThinLineShape) thinLineMode = splashThinLineShape; - if (m_page->parentDoc->m_hints & Document::ThinLineSolid) thinLineMode = splashThinLineSolid; - - const bool ignorePaperColor = m_page->parentDoc->m_hints & Document::IgnorePaperColor; - - Qt5SplashOutputDev splash_output( - colorMode, 4, - gFalse, - ignorePaperColor, - ignorePaperColor ? nullptr : bgColor, - gTrue, - thinLineMode, - overprintPreview); - + SplashRenderSetup renderSetup(m_page->parentDoc->m_hints, m_page->parentDoc->paperColor); + Qt5SplashOutputDev splash_output(renderSetup); 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); - splash_output.setFreeTypeHinting(m_page->parentDoc->m_hints & Document::TextHinting ? gTrue : gFalse, - m_page->parentDoc->m_hints & Document::TextSlightHinting ? gTrue : gFalse); - - splash_output.startDoc(m_page->parentDoc->doc); - - const GBool hideAnnotations = m_page->parentDoc->m_hints & Document::HideAnnotations; - - 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, - shouldAbortRenderCallback ? shouldAbortRenderInternalCallback : nullAbortCallBack, abortHelper, - (hideAnnotations) ? annotDisplayDecideCbk : nullAnnotCallBack, - nullptr, gTrue); - + renderToPage(&splash_output, m_page, xres, yres, x, y, w, h, rotate, gTrue); img = splash_output.getXBGRImage( true /* takeImageData */); #endif break; } case Poppler::Document::ArthurBackend: { - QSize size = pageSize(); - QImage tmpimg(w == -1 ? qRound( size.width() * xres / 72.0 ) : w, h == -1 ? qRound( size.height() * yres / 72.0 ) : h, QImage::Format_ARGB32); - - QColor bgColor(m_page->parentDoc->paperColor.red(), - m_page->parentDoc->paperColor.green(), - m_page->parentDoc->paperColor.blue(), - m_page->parentDoc->paperColor.alpha()); - - tmpimg.fill(bgColor); - - QPainter painter(&tmpimg); - QImageDumpingArthurOutputDev arthur_output(&painter, &tmpimg); + ImageArthurRenderSetup renderSetup(x, y, w, h, xres, yres, pageSize(), DontSaveAndRestore, m_page->parentDoc->paperColor, m_page->parentDoc->m_hints); + QImageDumpingArthurOutputDev arthur_output(renderSetup); 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; + renderToPage(&arthur_output, m_page, xres, yres, x, y, w, h, rotate, gFalse); + img = arthur_output.getImage(); break; } } if (shouldAbortRenderCallback && shouldAbortRenderCallback(payload)) return QImage(); return img; } bool Page::renderToPainter(QPainter* painter, double xres, double yres, int x, int y, int w, int h, Rotation rotate, PainterFlags flags) const { if (!painter) return false; switch(m_page->parentDoc->m_backend) { case Poppler::Document::SplashBackend: return false; case Poppler::Document::ArthurBackend: { - QImageDumpingArthurOutputDev arthur_output(painter, nullptr); - return renderToArthur(&arthur_output, painter, m_page, xres, yres, x, y, w, h, rotate, flags); + ClientArthurRenderSetup renderSetup(x, y, painter, m_page->parentDoc->m_hints, flags); + QImageDumpingArthurOutputDev arthur_output(renderSetup); + renderToPage(&arthur_output, m_page, xres, yres, x, y, w, h, rotate, gFalse); + return true; } } return false; } QImage Page::thumbnail() const { unsigned char* data = nullptr; int w = 0; int h = 0; int rowstride = 0; GBool r = m_page->page->loadThumb(&data, &w, &h, &rowstride); QImage ret; if (r) { // first construct a temporary image with the data got, // then force a copy of it so we can free the raw thumbnail data ret = QImage(data, w, h, rowstride, QImage::Format_RGB888).copy(); gfree(data); } diff --git qt5/src/poppler-private.cc qt5/src/poppler-private.cc index b3628b41..69b150d7 100644 --- qt5/src/poppler-private.cc +++ qt5/src/poppler-private.cc @@ -282,80 +282,208 @@ namespace Debug { if ( name.isEmpty() ) continue; QDomElement item = docSyn->createElement( name ); parent->appendChild( item ); // 2. find the page the link refers to const ::LinkAction * a = outlineItem->getAction(); linkActionToTocItem( a, this, &item ); item.setAttribute( QStringLiteral("Open"), QVariant( (bool)outlineItem->isOpen() ).toString() ); // 3. recursively descend over children outlineItem->open(); const GooList * children = outlineItem->getKids(); if ( children ) addTocChildren( docSyn, &item, children ); } } - void OutputDevCallbackHelper::setCallbacks(Page::RenderToImagePartialUpdateFunc callback, Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA) - { + ArthurRenderSetup::ArthurRenderSetup(QPainter* painter) + : p_painter(painter), m_savePainter(false) { + } + + QPainter* ArthurRenderSetup::painter() { + return p_painter; + } + + QImage* ArthurRenderSetup::destImage() { + return nullptr; + } + + ArthurRenderSetup::~ArthurRenderSetup() { + } + + void ArthurRenderSetup::setupPainter(int docHints, int pageFlags, int x, int y) { + m_savePainter = !(pageFlags & Poppler::Page:: DontSaveAndRestore); + if (m_savePainter) + p_painter->save(); + if (docHints & Poppler::Document::Antialiasing) + p_painter->setRenderHint(QPainter::Antialiasing); + if (docHints & Poppler::Document::TextAntialiasing) + p_painter->setRenderHint(QPainter::TextAntialiasing); + p_painter->translate(x == -1 ? 0 : -x, y == -1 ? 0 : -y); + } + + void ArthurRenderSetup::restore() { + if (m_savePainter) + p_painter->restore(); + } + + ClientArthurRenderSetup::ClientArthurRenderSetup(int x, int y, QPainter* painter, int docHints, int pageFlags) + : ArthurRenderSetup(painter) { + setupPainter(docHints, pageFlags, x, y); + } + + ClientArthurRenderSetup::~ClientArthurRenderSetup() { + restore(); + } + + ImageArthurRenderSetup::ImageArthurRenderSetup(int x, int y, int w, int h, double xres, double yres, QSize pageSize, int pageFlags, QColor& docPaperColor, int docHints) + : ArthurRenderSetup(&m_painter) + , m_image(scale(pageSize, xres, yres, w, h), QImage::Format_ARGB32) + , m_painter(&m_image) { + m_image.fill(docPaperColor); + setupPainter(docHints, pageFlags, x, y); + } + + QImage* ImageArthurRenderSetup::destImage() { + return &m_image; + } + + ImageArthurRenderSetup::~ImageArthurRenderSetup() { + restore(); + m_painter.end(); + } + + QSize ImageArthurRenderSetup::scale(QSize pageSize, double xres, double yres, int w, int h) const { + return QSize(w == -1 ? qRound( pageSize.width() * xres / 72.0 ) : w, + h == -1 ? qRound( pageSize.height() * yres / 72.0) : h ); + } + + void OutputDevCallbackHelper::setCallbacks(Page::RenderToImagePartialUpdateFunc callback, + Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, + Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA) { partialUpdateCallback = callback; shouldDoPartialUpdateCallback = shouldDoCallback; shouldAbortRenderCallback = shouldAbortCallback; payload = payloadA; } - QImageDumpingArthurOutputDev::QImageDumpingArthurOutputDev(QPainter *painter, QImage *i) - : ArthurOutputDev(painter) - , image(i) - { + SplashRenderSetup::SplashRenderSetup(const int docHints, QColor docPaperColor) + : bitmapRowPad(4) + , reverseVideo(gFalse) + , ignorePaperColorA(docHints & Poppler::Document::IgnorePaperColor) + , bitmapTopDown(gTrue) + , overprintPreview(gFalse) { + #ifdef SPLASH_CMYK + overprintPreview = docHints & Document::OverprintPreview ? gTrue : gFalse; + if (overprintPreview) + { + Guchar c, m, y, k; + + c = 255 - docPaperColor.blue(); + m = 255 - docPaperColor.red(); + y = 255 - docPaperColor.green(); + k = c; + if (m < k) { + k = m; + } + if (y < k) { + k = y; + } + bgColor[0] = c - k; + bgColor[1] = m - k; + bgColor[2] = y - k; + bgColor[3] = k; + for (int i = 4; i < SPOT_NCOMPS + 4; i++) { + bgColor[i] = 0; + } + } + else + #endif + { + bgColor[0] = docPaperColor.blue(); + bgColor[1] = docPaperColor.green(); + bgColor[2] = docPaperColor.red(); + } + + colorMode = splashModeXBGR8; + #ifdef SPLASH_CMYK + if (overprintPreview) colorMode = splashModeDeviceN8; + #endif + + thinLineMode = splashThinLineDefault; + if (docHints & Poppler::Document::ThinLineShape) + thinLineMode = splashThinLineShape; + if (docHints & Poppler::Document::ThinLineSolid) + thinLineMode = splashThinLineSolid; + + paperColor = ignorePaperColorA ? nullptr : bgColor; + + textAntialiasing = docHints & Poppler::Document::TextAntialiasing ? gTrue : gFalse; + vectorAntialias = docHints & Poppler::Document::Antialiasing ? gTrue : gFalse; + freeTypeHintingEnable = docHints & Poppler::Document::TextHinting ? gTrue : gFalse; + freeTypeHintingEnableSlightHintingA = docHints & Poppler::Document::TextSlightHinting ? gTrue : gFalse; } - void QImageDumpingArthurOutputDev::dump() - { + QImageDumpingArthurOutputDev::QImageDumpingArthurOutputDev(ArthurRenderSetup& renderSetup) + : ArthurOutputDev(renderSetup.painter()), m_renderSetup(renderSetup) { + } + + void QImageDumpingArthurOutputDev::dump() { if (partialUpdateCallback && shouldDoPartialUpdateCallback && shouldDoPartialUpdateCallback(payload)) { - partialUpdateCallback(*image, payload); + partialUpdateCallback(*m_renderSetup.destImage(), payload); + } + } + + QImage QImageDumpingArthurOutputDev::getImage() const { + QImage* image = m_renderSetup.destImage(); + if (image) { + return *image; } + return QImage(); + } + + void QImageDumpingArthurOutputDev::startDoc(PDFDoc *docA) { + ArthurOutputDev::startDoc(docA); } #if defined(HAVE_SPLASH) - Qt5SplashOutputDev::Qt5SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, - GBool reverseVideoA, bool ignorePaperColorA, SplashColorPtr paperColorA, - GBool bitmapTopDownA, SplashThinLineMode thinLineMode, - GBool overprintPreviewA) - : SplashOutputDev(colorModeA, bitmapRowPadA, reverseVideoA, paperColorA, bitmapTopDownA, thinLineMode, overprintPreviewA) - , ignorePaperColor(ignorePaperColorA) - { + Qt5SplashOutputDev::Qt5SplashOutputDev(const SplashRenderSetup& settings) + : SplashOutputDev(settings.colorMode, settings.bitmapRowPad, settings.reverseVideo + , settings.paperColor, settings.bitmapTopDown + , settings.thinLineMode, settings.overprintPreview) + , ignorePaperColor(settings.ignorePaperColorA) { + setFontAntialias(settings.textAntialiasing); + setVectorAntialias(settings.vectorAntialias); + setFreeTypeHinting(settings.freeTypeHintingEnable, settings.freeTypeHintingEnableSlightHintingA); } - void Qt5SplashOutputDev::dump() - { + void Qt5SplashOutputDev::dump() { if (partialUpdateCallback && shouldDoPartialUpdateCallback && shouldDoPartialUpdateCallback(payload)) { - partialUpdateCallback(getXBGRImage( false /* takeImageData */), payload); + partialUpdateCallback(getXBGRImage(false), payload); } } - QImage Qt5SplashOutputDev::getXBGRImage(bool takeImageData) - { + QImage Qt5SplashOutputDev::getXBGRImage(bool takeImageData) { SplashBitmap *b = getBitmap(); const int bw = b->getWidth(); const int bh = b->getHeight(); const int brs = b->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 (b->convertToXBGR(mode)) { SplashColorPtr data = takeImageData ? b->takeData() : b->getDataPtr(); if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { diff --git qt5/src/poppler-private.h qt5/src/poppler-private.h index 58031be1..6b7007ba 100644 --- qt5/src/poppler-private.h +++ qt5/src/poppler-private.h @@ -215,62 +215,148 @@ namespace Poppler { QRectF bBox; TextBox *nextWord; QVector charBBoxes; // the boundingRect of each character bool hasSpaceAfter; }; class FormFieldData { public: FormFieldData(DocumentData *_doc, ::Page *p, ::FormWidget *w) : doc(_doc), page(p), fm(w) { } DocumentData *doc; ::Page *page; ::FormWidget *fm; QRectF box; }; + class ArthurRenderSetup { + public: + ArthurRenderSetup(QPainter* painter); + + QPainter* painter(); + + virtual QImage* destImage(); + + virtual ~ArthurRenderSetup(); + + protected: + void setupPainter(int docHints, int pageFlags, int x, int y); + + void restore(); + + private: + QPainter* p_painter; + bool m_savePainter; + }; + + class ClientArthurRenderSetup : public ArthurRenderSetup { + public: + ClientArthurRenderSetup(int x, int y, QPainter* painter, int docHints, int pageFlags); + + ~ClientArthurRenderSetup(); + }; + + class ImageArthurRenderSetup : public ArthurRenderSetup { + public: + ImageArthurRenderSetup(int x, int y, int w, int h, double xres, double yres, QSize pageSize, + int pageFlags, QColor& docPaperColor, int docHints); + + QImage* destImage() override; + + ~ImageArthurRenderSetup(); + + private: + QSize scale(QSize pageSize, double xres, double yres, int w, int h) const; + + QImage m_image; + QPainter m_painter; + }; + + class SplashRenderSetup { + public: + SplashRenderSetup(const int docHints, QColor docPaperColor); + + SplashColorMode colorMode; + int bitmapRowPad; + GBool reverseVideo; + const bool ignorePaperColorA; + SplashColorPtr paperColor; + GBool bitmapTopDown; + SplashThinLineMode thinLineMode; + GBool overprintPreview; + SplashColor bgColor; + GBool textAntialiasing; + GBool vectorAntialias; + GBool freeTypeHintingEnable; + GBool freeTypeHintingEnableSlightHintingA; + }; + class OutputDevCallbackHelper { public: - void setCallbacks(Page::RenderToImagePartialUpdateFunc callback, Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA); + void setCallbacks(Page::RenderToImagePartialUpdateFunc callback, + Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, + Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA); Page::RenderToImagePartialUpdateFunc partialUpdateCallback = nullptr; Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback = nullptr; Page::ShouldAbortQueryFunc shouldAbortRenderCallback = nullptr; QVariant payload; }; - class QImageDumpingArthurOutputDev : public ArthurOutputDev, public OutputDevCallbackHelper + class Qt5OutputDev { + public: + virtual void startDoc(PDFDoc *docA) = 0; + + virtual OutputDev* outputDev() = 0; + + virtual OutputDevCallbackHelper* callbackHelper() = 0; + + virtual ~Qt5OutputDev() {} + }; + + class QImageDumpingArthurOutputDev : public ArthurOutputDev, public OutputDevCallbackHelper, public Qt5OutputDev { public: - QImageDumpingArthurOutputDev(QPainter *painter, QImage *i); + QImageDumpingArthurOutputDev(ArthurRenderSetup& renderSetup); void dump() override; + QImage getImage() const; + + void startDoc(PDFDoc *docA) override; + + OutputDev* outputDev() override { return this; } + + OutputDevCallbackHelper* callbackHelper() override { return this; } + private: - QImage *image; + ArthurRenderSetup& m_renderSetup; }; #if defined(HAVE_SPLASH) - class Qt5SplashOutputDev : public SplashOutputDev, public OutputDevCallbackHelper + class Qt5SplashOutputDev : public SplashOutputDev, public OutputDevCallbackHelper, public Qt5OutputDev { public: - Qt5SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, - GBool reverseVideoA, bool ignorePaperColorA, SplashColorPtr paperColorA, - GBool bitmapTopDownA, SplashThinLineMode thinLineMode, - GBool overprintPreviewA); + Qt5SplashOutputDev(const SplashRenderSetup& settings); void dump() override; QImage getXBGRImage(bool takeImageData); + void startDoc(PDFDoc *docA) override { SplashOutputDev::startDoc(docA); }; + + OutputDev* outputDev() override { return this; } + + OutputDevCallbackHelper* callbackHelper() override { return this; } + private: bool ignorePaperColor; }; #endif } #endif