From 8ba6d1b7b21496793e035472bc961855fae740bb Mon Sep 17 00:00:00 2001 From: John Papale Date: Tue, 27 Oct 2020 19:05:40 +0100 Subject: [PATCH] Made zoom cache behavior configurable with var 'ZoomBehavior' (0 =no cache, 1 =x3 zoom cache, 2 = 2.5/5/10 cache). Cleanup. --- src/core/UBSettings.cpp | 1 + src/core/UBSettings.h | 1 + src/pdf/XPDFRenderer.cpp | 142 +++++++++++++++++++-------------------- src/pdf/XPDFRenderer.h | 37 ++++------ 4 files changed, 83 insertions(+), 98 deletions(-) diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index 80e14677..b83d5f88 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -408,6 +408,7 @@ void UBSettings::init() pdfMargin = new UBSetting(this, "PDF", "Margin", "20"); pdfPageFormat = new UBSetting(this, "PDF", "PageFormat", "A4"); pdfResolution = new UBSetting(this, "PDF", "Resolution", "300"); + pdfZoomBehavior = new UBSetting(this, "PDF", "ZoomBehavior", "1"); podcastFramesPerSecond = new UBSetting(this, "Podcast", "FramesPerSecond", 10); podcastVideoSize = new UBSetting(this, "Podcast", "VideoSize", "Medium"); diff --git a/src/core/UBSettings.h b/src/core/UBSettings.h index c79e4f95..5b287354 100644 --- a/src/core/UBSettings.h +++ b/src/core/UBSettings.h @@ -359,6 +359,7 @@ class UBSettings : public QObject UBSetting* pdfMargin; UBSetting* pdfPageFormat; UBSetting* pdfResolution; + UBSetting* pdfZoomBehavior; UBSetting* podcastFramesPerSecond; UBSetting* podcastVideoSize; diff --git a/src/pdf/XPDFRenderer.cpp b/src/pdf/XPDFRenderer.cpp index e0ee4ac3..410739fc 100644 --- a/src/pdf/XPDFRenderer.cpp +++ b/src/pdf/XPDFRenderer.cpp @@ -37,29 +37,27 @@ #endif #include "core/memcheck.h" +#include "core/UBSettings.h" -#ifdef XPDFRENDERER_CACHE_ZOOM_IMAGE -#ifdef XPDFRENDERER_CACHE_ZOOM_WITH_LOSS -double const XPDFRenderer::sRatioZoomRendering[] = { 3.0 }; -#else //XPDFRENDERER_CACHE_ZOOM_WITH_LOSS -double const XPDFRenderer::sRatioZoomRendering[] = { 2.5, 5, 10.0 }; -#endif //XPDFRENDERER_CACHE_ZOOM_WITH_LOSS -#endif //XPDFRENDERER_CACHE_ZOOM_IMAGE QAtomicInt XPDFRenderer::sInstancesCount = 0; XPDFRenderer::XPDFRenderer(const QString &filename, bool importingFile) : -#ifndef XPDFRENDERER_CACHE_ZOOM_IMAGE - mSplash(nullptr), -#endif //XPDFRENDERER_CACHE_ZOOM_IMAGE - mDocument(0) + mpSplashBitmapHistorical(nullptr), mSplashHistorical(nullptr), mDocument(nullptr) { -#ifdef XPDFRENDERER_CACHE_ZOOM_IMAGE - for (int i = 0; i < NbrZoomCache; i++) - { - m_cache.push_back(TypeCacheData(sRatioZoomRendering[i])); + switch (UBSettings::settings()->pdfZoomBehavior->get().toUInt()) { + case 0: // Render each time (historical initial implementation). + break; + case 1: // Render a single image, degradated quality when zoomed big. + default: + m_pdfZoomCache.push_back(3.0); + break; + case 2: // Render three images, optimal quality all the time. + m_pdfZoomCache.push_back(2.5); + m_pdfZoomCache.push_back(5.0); + m_pdfZoomCache.push_back(10.0); + break; } -#endif //XPDFRENDERER_CACHE_ZOOM_IMAGE Q_UNUSED(importingFile); if (!globalParams) @@ -83,17 +81,18 @@ XPDFRenderer::XPDFRenderer(const QString &filename, bool importingFile) : XPDFRenderer::~XPDFRenderer() { -#ifdef XPDFRENDERER_CACHE_ZOOM_IMAGE - for(int i = 0; i < m_cache.size(); i++) + for(int i = 0; i < m_pdfZoomCache.size(); i++) { - TypeCacheData &cacheData = m_cache[i]; + TypePdfZoomCacheData &cacheData = m_pdfZoomCache[i]; if(cacheData.splash != nullptr){ cacheData.cachedImage = QImage(); // The 'cachedImage' uses a buffer from 'splash'. delete cacheData.splash; cacheData.splash = nullptr; } } -#endif //XPDFRENDERER_CACHE_ZOOM_IMAGE + + if(mSplashHistorical) + delete mSplashHistorical; if (mDocument) { @@ -198,33 +197,17 @@ int XPDFRenderer::pageRotation(int pageNumber) const return 0; } -#ifndef XPDFRENDERER_CACHE_ZOOM_IMAGE -void XPDFRenderer::render(QPainter *p, int pageNumber, const QRectF &bounds) -{ - if (isValid()) - { - qreal xscale = p->worldTransform().m11(); - qreal yscale = p->worldTransform().m22(); - - QImage *pdfImage = createPDFImage(pageNumber, xscale, yscale, bounds); - QTransform savedTransform = p->worldTransform(); - p->resetTransform(); - p->drawImage(QPointF(savedTransform.dx() + mSliceX, savedTransform.dy() + mSliceY), *pdfImage); - p->setWorldTransform(savedTransform); - delete pdfImage; - } -} -QImage* XPDFRenderer::createPDFImage(int pageNumber, qreal xscale, qreal yscale, const QRectF &bounds) +QImage* XPDFRenderer::createPDFImageHistorical(int pageNumber, qreal xscale, qreal yscale, const QRectF &bounds) { if (isValid()) { SplashColor paperColor = {0xFF, 0xFF, 0xFF}; // white - if(mSplash) - delete mSplash; - mSplash = new SplashOutputDev(splashModeRGB8, 1, false, paperColor); + if(mSplashHistorical) + delete mSplashHistorical; + mSplashHistorical = new SplashOutputDev(splashModeRGB8, 1, false, paperColor); #ifdef USE_XPDF - mSplash->startDoc(mDocument->getXRef()); + mSplashHistorical->startDoc(mDocument->getXRef()); #else mSplash->startDoc(mDocument); #endif @@ -237,7 +220,7 @@ QImage* XPDFRenderer::createPDFImage(int pageNumber, qreal xscale, qreal yscale, if (bounds.isNull()) { - mDocument->displayPage(mSplash, pageNumber, this->dpiForRendering * xscale, this->dpiForRendering *yscale, + mDocument->displayPage(mSplashHistorical, pageNumber, this->dpiForRendering * xscale, this->dpiForRendering *yscale, rotation, useMediaBox, crop, printing); } else @@ -247,56 +230,68 @@ QImage* XPDFRenderer::createPDFImage(int pageNumber, qreal xscale, qreal yscale, qreal sliceW = bounds.width() * xscale; qreal sliceH = bounds.height() * yscale; - mDocument->displayPageSlice(mSplash, pageNumber, this->dpiForRendering * xscale, this->dpiForRendering * yscale, + mDocument->displayPageSlice(mSplashHistorical, pageNumber, this->dpiForRendering * xscale, this->dpiForRendering * yscale, rotation, useMediaBox, crop, printing, mSliceX, mSliceY, sliceW, sliceH); } - mpSplashBitmap = mSplash->getBitmap(); + mpSplashBitmapHistorical = mSplashHistorical->getBitmap(); } - return new QImage(mpSplashBitmap->getDataPtr(), mpSplashBitmap->getWidth(), mpSplashBitmap->getHeight(), mpSplashBitmap->getWidth() * 3, QImage::Format_RGB888); + return new QImage(mpSplashBitmapHistorical->getDataPtr(), mpSplashBitmapHistorical->getWidth(), mpSplashBitmapHistorical->getHeight(), mpSplashBitmapHistorical->getWidth() * 3, QImage::Format_RGB888); } -#else - void XPDFRenderer::render(QPainter *p, int pageNumber, const QRectF &bounds) { Q_UNUSED(bounds); if (isValid()) { - qreal xscale = p->worldTransform().m11(); - qreal yscale = p->worldTransform().m22(); - Q_ASSERT(qFuzzyCompare(xscale, yscale)); // Zoom equal in all axes expected. - Q_ASSERT(xscale > 0.0); // Potential Div0 later if this assert fail. - - int zoomIndex = 0; - bool foundIndex = false; - for (; zoomIndex < NbrZoomCache && !foundIndex;) + if (m_pdfZoomCache.size() > 0) { - if (xscale <= m_cache[zoomIndex].ratio) { - foundIndex = true; - } else { - zoomIndex++; + qreal xscale = p->worldTransform().m11(); + qreal yscale = p->worldTransform().m22(); + Q_ASSERT(qFuzzyCompare(xscale, yscale)); // Zoom equal in all axes expected. + Q_ASSERT(xscale > 0.0); // Potential Div0 later if this assert fail. + + int zoomIndex = 0; + bool foundIndex = false; + for (; zoomIndex < m_pdfZoomCache.size() && !foundIndex;) + { + if (xscale <= m_pdfZoomCache[zoomIndex].ratio) { + foundIndex = true; + } else { + zoomIndex++; + } } - } - if (!foundIndex) // Use the previous one. - zoomIndex--; + if (!foundIndex) // Use the previous one. + zoomIndex--; - QImage const &pdfImage = createPDFImage(pageNumber, m_cache[zoomIndex]); - QTransform savedTransform = p->worldTransform(); - double const ratioDifferenceBetweenWorldAndImage = 1.0/m_cache[zoomIndex].ratio; - // The 'pdfImage' is rendered with a quality equal or superior. We adjust the 'transform' to zoom it - // out the required ratio. - QTransform newTransform = savedTransform.scale(ratioDifferenceBetweenWorldAndImage, ratioDifferenceBetweenWorldAndImage); - p->setWorldTransform(newTransform); - p->drawImage(QPointF( mSliceX, mSliceY), pdfImage); + QImage const &pdfImage = createPDFImageCached(pageNumber, m_pdfZoomCache[zoomIndex]); + QTransform savedTransform = p->worldTransform(); - p->setWorldTransform(savedTransform); + double const ratioDifferenceBetweenWorldAndImage = 1.0/m_pdfZoomCache[zoomIndex].ratio; + // The 'pdfImage' is rendered with a quality equal or superior. We adjust the 'transform' to zoom it + // out the required ratio. + QTransform newTransform = savedTransform.scale(ratioDifferenceBetweenWorldAndImage, ratioDifferenceBetweenWorldAndImage); + p->setWorldTransform(newTransform); + p->drawImage(QPointF( mSliceX, mSliceY), pdfImage); + + p->setWorldTransform(savedTransform); + } else { + qreal xscale = p->worldTransform().m11(); + qreal yscale = p->worldTransform().m22(); + + QImage *pdfImage = createPDFImageHistorical(pageNumber, xscale, yscale, bounds); + QTransform savedTransform = p->worldTransform(); + p->resetTransform(); + p->drawImage(QPointF(savedTransform.dx() + mSliceX, savedTransform.dy() + mSliceY), *pdfImage); + p->setWorldTransform(savedTransform); + delete pdfImage; + } } } -QImage& XPDFRenderer::createPDFImage(int pageNumber, TypeCacheData &cacheData) +QImage& XPDFRenderer::createPDFImageCached(int pageNumber, TypePdfZoomCacheData &cacheData) { if (isValid()) { @@ -306,7 +301,7 @@ QImage& XPDFRenderer::createPDFImage(int pageNumber, TypeCacheData &cacheData) { if(cacheData.splash != nullptr) { - cacheData.cachedImage = QImage(); // The 'm_cachedImage' uses a buffer from 'mSplash'. + cacheData.cachedImage = QImage(); // The 'm_pdfZoomCachedImage' uses a buffer from 'mSplash'. delete cacheData.splash; } cacheData.splash = new SplashOutputDev(splashModeRGB8, 1, false, paperColor); @@ -339,4 +334,3 @@ QImage& XPDFRenderer::createPDFImage(int pageNumber, TypeCacheData &cacheData) return cacheData.cachedImage; } -#endif diff --git a/src/pdf/XPDFRenderer.h b/src/pdf/XPDFRenderer.h index fef8b411..61dc323a 100644 --- a/src/pdf/XPDFRenderer.h +++ b/src/pdf/XPDFRenderer.h @@ -51,9 +51,6 @@ class PDFDoc; -#define XPDFRENDERER_CACHE_ZOOM_IMAGE -//#define XPDFRENDERER_CACHE_ZOOM_WITH_LOSS - class XPDFRenderer : public PDFRenderer { Q_OBJECT @@ -77,20 +74,10 @@ class XPDFRenderer : public PDFRenderer private: void init(); -#ifdef XPDFRENDERER_CACHE_ZOOM_IMAGE - - enum { -#ifndef XPDFRENDERER_CACHE_ZOOM_WITH_LOSS - NbrZoomCache = 3 -#else //XPDFRENDERER_CACHE_ZOOM_WITH_LOSS - NbrZoomCache = 1 -#endif //XPDFRENDERER_CACHE_ZOOM_WITH_LOSS - }; - class TypeCacheData { - public: - TypeCacheData(double const a_ratio) : splashBitmap(nullptr), cachedPageNumber(-1), splash(nullptr), ratio(a_ratio) {}; - ~TypeCacheData() {}; + struct TypePdfZoomCacheData { + TypePdfZoomCacheData(double const a_ratio) : splashBitmap(nullptr), cachedPageNumber(-1), splash(nullptr), ratio(a_ratio) {}; + ~TypePdfZoomCacheData() {}; SplashBitmap* splashBitmap; QImage cachedImage; int cachedPageNumber; @@ -98,16 +85,18 @@ class XPDFRenderer : public PDFRenderer double const ratio; }; - QImage &createPDFImage(int pageNumber, TypeCacheData &cacheData); + QImage &createPDFImageCached(int pageNumber, TypePdfZoomCacheData &cacheData); + QImage* createPDFImageHistorical(int pageNumber, qreal xscale, qreal yscale, const QRectF &bounds); - static const double sRatioZoomRendering[NbrZoomCache]; - QVector m_cache; -#else - QImage* createPDFImage(int pageNumber, qreal xscale = 0.5, qreal yscale = 0.5, const QRectF &bounds = QRectF()); + // Used when 'ZoomBehavior == 1 or 2'. + // =1 has only x3 zoom in cache (= loss if user zoom > 3.0). + // =2, has 2.5, 5 and 10 (= no loss, but a bit slower). + QVector m_pdfZoomCache; - SplashBitmap* mpSplashBitmap; - SplashOutputDev* mSplash; -#endif + // Used when 'ZoomBehavior == 0' (no cache). + SplashBitmap* mpSplashBitmapHistorical; + // Used when 'ZoomBehavior == 0' (no cache). + SplashOutputDev* mSplashHistorical; PDFDoc *mDocument; static QAtomicInt sInstancesCount;