Made zoom cache behavior configurable with var 'ZoomBehavior' (0 =no cache, 1 =x3 zoom cache, 2 = 2.5/5/10 cache). Cleanup.

preferencesAboutTextFull
John Papale 4 years ago
parent c860e0b0b7
commit 8ba6d1b7b2
  1. 1
      src/core/UBSettings.cpp
  2. 1
      src/core/UBSettings.h
  3. 142
      src/pdf/XPDFRenderer.cpp
  4. 37
      src/pdf/XPDFRenderer.h

@ -408,6 +408,7 @@ void UBSettings::init()
pdfMargin = new UBSetting(this, "PDF", "Margin", "20"); pdfMargin = new UBSetting(this, "PDF", "Margin", "20");
pdfPageFormat = new UBSetting(this, "PDF", "PageFormat", "A4"); pdfPageFormat = new UBSetting(this, "PDF", "PageFormat", "A4");
pdfResolution = new UBSetting(this, "PDF", "Resolution", "300"); pdfResolution = new UBSetting(this, "PDF", "Resolution", "300");
pdfZoomBehavior = new UBSetting(this, "PDF", "ZoomBehavior", "1");
podcastFramesPerSecond = new UBSetting(this, "Podcast", "FramesPerSecond", 10); podcastFramesPerSecond = new UBSetting(this, "Podcast", "FramesPerSecond", 10);
podcastVideoSize = new UBSetting(this, "Podcast", "VideoSize", "Medium"); podcastVideoSize = new UBSetting(this, "Podcast", "VideoSize", "Medium");

@ -359,6 +359,7 @@ class UBSettings : public QObject
UBSetting* pdfMargin; UBSetting* pdfMargin;
UBSetting* pdfPageFormat; UBSetting* pdfPageFormat;
UBSetting* pdfResolution; UBSetting* pdfResolution;
UBSetting* pdfZoomBehavior;
UBSetting* podcastFramesPerSecond; UBSetting* podcastFramesPerSecond;
UBSetting* podcastVideoSize; UBSetting* podcastVideoSize;

@ -37,29 +37,27 @@
#endif #endif
#include "core/memcheck.h" #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; QAtomicInt XPDFRenderer::sInstancesCount = 0;
XPDFRenderer::XPDFRenderer(const QString &filename, bool importingFile) : XPDFRenderer::XPDFRenderer(const QString &filename, bool importingFile) :
#ifndef XPDFRENDERER_CACHE_ZOOM_IMAGE mpSplashBitmapHistorical(nullptr), mSplashHistorical(nullptr), mDocument(nullptr)
mSplash(nullptr),
#endif //XPDFRENDERER_CACHE_ZOOM_IMAGE
mDocument(0)
{ {
#ifdef XPDFRENDERER_CACHE_ZOOM_IMAGE switch (UBSettings::settings()->pdfZoomBehavior->get().toUInt()) {
for (int i = 0; i < NbrZoomCache; i++) case 0: // Render each time (historical initial implementation).
{ break;
m_cache.push_back(TypeCacheData(sRatioZoomRendering[i])); 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); Q_UNUSED(importingFile);
if (!globalParams) if (!globalParams)
@ -83,17 +81,18 @@ XPDFRenderer::XPDFRenderer(const QString &filename, bool importingFile) :
XPDFRenderer::~XPDFRenderer() XPDFRenderer::~XPDFRenderer()
{ {
#ifdef XPDFRENDERER_CACHE_ZOOM_IMAGE for(int i = 0; i < m_pdfZoomCache.size(); i++)
for(int i = 0; i < m_cache.size(); i++)
{ {
TypeCacheData &cacheData = m_cache[i]; TypePdfZoomCacheData &cacheData = m_pdfZoomCache[i];
if(cacheData.splash != nullptr){ if(cacheData.splash != nullptr){
cacheData.cachedImage = QImage(); // The 'cachedImage' uses a buffer from 'splash'. cacheData.cachedImage = QImage(); // The 'cachedImage' uses a buffer from 'splash'.
delete cacheData.splash; delete cacheData.splash;
cacheData.splash = nullptr; cacheData.splash = nullptr;
} }
} }
#endif //XPDFRENDERER_CACHE_ZOOM_IMAGE
if(mSplashHistorical)
delete mSplashHistorical;
if (mDocument) if (mDocument)
{ {
@ -198,33 +197,17 @@ int XPDFRenderer::pageRotation(int pageNumber) const
return 0; 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()) if (isValid())
{ {
SplashColor paperColor = {0xFF, 0xFF, 0xFF}; // white SplashColor paperColor = {0xFF, 0xFF, 0xFF}; // white
if(mSplash) if(mSplashHistorical)
delete mSplash; delete mSplashHistorical;
mSplash = new SplashOutputDev(splashModeRGB8, 1, false, paperColor); mSplashHistorical = new SplashOutputDev(splashModeRGB8, 1, false, paperColor);
#ifdef USE_XPDF #ifdef USE_XPDF
mSplash->startDoc(mDocument->getXRef()); mSplashHistorical->startDoc(mDocument->getXRef());
#else #else
mSplash->startDoc(mDocument); mSplash->startDoc(mDocument);
#endif #endif
@ -237,7 +220,7 @@ QImage* XPDFRenderer::createPDFImage(int pageNumber, qreal xscale, qreal yscale,
if (bounds.isNull()) 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); rotation, useMediaBox, crop, printing);
} }
else else
@ -247,56 +230,68 @@ QImage* XPDFRenderer::createPDFImage(int pageNumber, qreal xscale, qreal yscale,
qreal sliceW = bounds.width() * xscale; qreal sliceW = bounds.width() * xscale;
qreal sliceH = bounds.height() * yscale; 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); 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) void XPDFRenderer::render(QPainter *p, int pageNumber, const QRectF &bounds)
{ {
Q_UNUSED(bounds); Q_UNUSED(bounds);
if (isValid()) if (isValid())
{ {
qreal xscale = p->worldTransform().m11(); if (m_pdfZoomCache.size() > 0)
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 (xscale <= m_cache[zoomIndex].ratio) { qreal xscale = p->worldTransform().m11();
foundIndex = true; qreal yscale = p->worldTransform().m22();
} else { Q_ASSERT(qFuzzyCompare(xscale, yscale)); // Zoom equal in all axes expected.
zoomIndex++; 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. if (!foundIndex) // Use the previous one.
zoomIndex--; zoomIndex--;
QImage const &pdfImage = createPDFImage(pageNumber, m_cache[zoomIndex]);
QTransform savedTransform = p->worldTransform();
double const ratioDifferenceBetweenWorldAndImage = 1.0/m_cache[zoomIndex].ratio; QImage const &pdfImage = createPDFImageCached(pageNumber, m_pdfZoomCache[zoomIndex]);
// The 'pdfImage' is rendered with a quality equal or superior. We adjust the 'transform' to zoom it QTransform savedTransform = p->worldTransform();
// out the required ratio.
QTransform newTransform = savedTransform.scale(ratioDifferenceBetweenWorldAndImage, ratioDifferenceBetweenWorldAndImage);
p->setWorldTransform(newTransform);
p->drawImage(QPointF( mSliceX, mSliceY), pdfImage);
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()) if (isValid())
{ {
@ -306,7 +301,7 @@ QImage& XPDFRenderer::createPDFImage(int pageNumber, TypeCacheData &cacheData)
{ {
if(cacheData.splash != nullptr) 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; delete cacheData.splash;
} }
cacheData.splash = new SplashOutputDev(splashModeRGB8, 1, false, paperColor); cacheData.splash = new SplashOutputDev(splashModeRGB8, 1, false, paperColor);
@ -339,4 +334,3 @@ QImage& XPDFRenderer::createPDFImage(int pageNumber, TypeCacheData &cacheData)
return cacheData.cachedImage; return cacheData.cachedImage;
} }
#endif

@ -51,9 +51,6 @@
class PDFDoc; class PDFDoc;
#define XPDFRENDERER_CACHE_ZOOM_IMAGE
//#define XPDFRENDERER_CACHE_ZOOM_WITH_LOSS
class XPDFRenderer : public PDFRenderer class XPDFRenderer : public PDFRenderer
{ {
Q_OBJECT Q_OBJECT
@ -77,20 +74,10 @@ class XPDFRenderer : public PDFRenderer
private: private:
void init(); 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 { struct TypePdfZoomCacheData {
public: TypePdfZoomCacheData(double const a_ratio) : splashBitmap(nullptr), cachedPageNumber(-1), splash(nullptr), ratio(a_ratio) {};
TypeCacheData(double const a_ratio) : splashBitmap(nullptr), cachedPageNumber(-1), splash(nullptr), ratio(a_ratio) {}; ~TypePdfZoomCacheData() {};
~TypeCacheData() {};
SplashBitmap* splashBitmap; SplashBitmap* splashBitmap;
QImage cachedImage; QImage cachedImage;
int cachedPageNumber; int cachedPageNumber;
@ -98,16 +85,18 @@ class XPDFRenderer : public PDFRenderer
double const ratio; 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]; // Used when 'ZoomBehavior == 1 or 2'.
QVector<TypeCacheData> m_cache; // =1 has only x3 zoom in cache (= loss if user zoom > 3.0).
#else // =2, has 2.5, 5 and 10 (= no loss, but a bit slower).
QImage* createPDFImage(int pageNumber, qreal xscale = 0.5, qreal yscale = 0.5, const QRectF &bounds = QRectF()); QVector<TypePdfZoomCacheData> m_pdfZoomCache;
SplashBitmap* mpSplashBitmap; // Used when 'ZoomBehavior == 0' (no cache).
SplashOutputDev* mSplash; SplashBitmap* mpSplashBitmapHistorical;
#endif // Used when 'ZoomBehavior == 0' (no cache).
SplashOutputDev* mSplashHistorical;
PDFDoc *mDocument; PDFDoc *mDocument;
static QAtomicInt sInstancesCount; static QAtomicInt sInstancesCount;

Loading…
Cancel
Save