Merge remote-tracking branch 'remotes/origin/branches/issue123'

This commit is contained in:
Jakub Melka 2024-02-25 16:08:24 +01:00
commit 6c5b8b08a5
52 changed files with 1676 additions and 873 deletions

View File

@ -48,7 +48,7 @@ jobs:
- name: 'VCPKG: Install project dependencies'
run: |
./vcpkg install tbb openssl lcms zlib openjpeg freetype ijg-libjpeg libpng
./vcpkg install tbb openssl lcms zlib openjpeg freetype ijg-libjpeg libpng blend2d
working-directory: vcpkg
- name: Install Qt

View File

@ -36,7 +36,7 @@ jobs:
- name: 'VCPKG: Install project dependencies'
run: |
./vcpkg install tbb openssl lcms zlib openjpeg freetype ijg-libjpeg libpng
./vcpkg install tbb openssl lcms zlib openjpeg freetype ijg-libjpeg libpng blend2d
working-directory: vcpkg
- name: Install Qt
@ -101,7 +101,7 @@ jobs:
- name: 'VCPKG: Install project dependencies'
run: |
.\vcpkg install tbb openssl lcms zlib openjpeg freetype ijg-libjpeg libpng --triplet x64-windows
.\vcpkg install tbb openssl lcms zlib openjpeg freetype ijg-libjpeg libpng blend2d --triplet x64-windows
working-directory: vcpkg
- name: Install Qt

View File

@ -33,7 +33,6 @@ if(WIN32 AND MSVC)
option(PDF4QT_INSTALL_PREPARE_WIX_INSTALLER "Prepare Wix installer for Windows" ON)
endif()
option(PDF4QT_ENABLE_OPENGL "Enable OpenGL" ON)
option(PDF4QT_BUILD_ONLY_CORE_LIBRARY "Build only core library" OFF)
set(PDF4QT_QT_ROOT "" CACHE PATH "Qt root directory")
@ -49,18 +48,8 @@ include(GNUInstallDirs)
if(PDF4QT_BUILD_ONLY_CORE_LIBRARY)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Svg Xml)
if(PDF4QT_ENABLE_OPENGL)
add_compile_definitions(PDF4QT_ENABLE_OPENGL)
find_package(Qt6 REQUIRED COMPONENTS OpenGL)
endif()
else()
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Svg Xml PrintSupport TextToSpeech Test)
if(PDF4QT_ENABLE_OPENGL)
add_compile_definitions(PDF4QT_ENABLE_OPENGL)
find_package(Qt6 REQUIRED COMPONENTS OpenGL OpenGLWidgets)
endif()
endif()
qt_standard_project_setup()
@ -72,6 +61,7 @@ find_package(Freetype REQUIRED)
find_package(OpenJPEG CONFIG REQUIRED)
find_package(JPEG REQUIRED)
find_package(PNG REQUIRED)
find_package(blend2d CONFIG REQUIRED)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
@ -178,7 +168,7 @@ if(PDF4QT_INSTALL_DEPENDENCIES AND NOT PDF4QT_BUILD_ONLY_CORE_LIBRARY)
install(DIRECTORY ${PDF4QT_QT_ROOT}/bin/
RUNTIME DESTINATION ${PDF4QT_INSTALL_LIB_DIR}/
FILES_MATCHING
REGEX "(Qt6Core|Qt6Gui|Qt6PrintSupport|Qt6Svg|Qt6TextToSpeech|Qt6Widgets|Qt6Xml|Qt6OpenGL|Qt6OpenGLWidgets|Qt6Multimedia|Qt6Network)\\..*"
REGEX "(Qt6Core|Qt6Gui|Qt6PrintSupport|Qt6Svg|Qt6TextToSpeech|Qt6Widgets|Qt6Xml|Qt6Multimedia|Qt6Network)\\..*"
PATTERN "Debug" EXCLUDE
)

View File

@ -35,10 +35,6 @@ add_executable(Pdf4QtDocDiff
icon.rc
)
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(Pdf4QtDocDiff PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(Pdf4QtDocDiff PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(Pdf4QtDocDiff PROPERTIES

View File

@ -24,7 +24,6 @@
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true);
QApplication application(argc, argv);
QCoreApplication::setOrganizationName("MelkaJ");

View File

@ -82,7 +82,7 @@ MainWindow::MainWindow(QWidget* parent) :
ui->documentFrame->setLayout(new QVBoxLayout);
m_cmsManager = new pdf::PDFCMSManager(this);
m_pdfWidget = new pdf::PDFWidget(m_cmsManager, pdf::RendererEngine::Software, 1, ui->documentFrame);
m_pdfWidget = new pdf::PDFWidget(m_cmsManager, pdf::RendererEngine::QPainter, ui->documentFrame);
m_pdfWidget->getDrawWidgetProxy()->setProgress(m_progress);
ui->documentFrame->layout()->addWidget(m_pdfWidget);
m_pdfWidget->getDrawWidgetProxy()->registerDrawInterface(&m_drawInterface);

View File

@ -24,7 +24,6 @@
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true);
QApplication application(argc, argv);
QCoreApplication::setOrganizationName("MelkaJ");

View File

@ -35,9 +35,7 @@ PageItemDelegate::PageItemDelegate(PageItemModel* model, QObject* parent) :
m_rasterizer(nullptr)
{
m_rasterizer = new pdf::PDFRasterizer(this);
QSurfaceFormat format;
format.setSamples(16);
m_rasterizer->reset(false, format);
m_rasterizer->reset(pdf::RendererEngine::Blend2D_SingleThread);
}
PageItemDelegate::~PageItemDelegate()

View File

@ -146,6 +146,8 @@ add_library(Pdf4QtLibCore SHARED
cmaps.qrc
sources/pdfcertificatestore.h
sources/pdfcertificatestore.cpp
sources/pdfblpainter.h
sources/pdfblpainter.cpp
)
include(GenerateExportHeader)
@ -163,10 +165,6 @@ target_link_libraries(Pdf4QtLibCore PRIVATE Freetype::Freetype)
target_link_libraries(Pdf4QtLibCore PRIVATE openjp2)
target_link_libraries(Pdf4QtLibCore PRIVATE JPEG::JPEG)
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(Pdf4QtLibCore PRIVATE Qt6::OpenGL)
endif()
if(LINUX_GCC)
target_link_libraries(Pdf4QtLibCore PUBLIC TBB::tbb)
endif()
@ -178,6 +176,8 @@ endif()
target_include_directories(Pdf4QtLibCore INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/sources)
target_include_directories(Pdf4QtLibCore PUBLIC ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR})
target_link_libraries(Pdf4QtLibCore PRIVATE blend2d::blend2d)
set_target_properties(Pdf4QtLibCore PROPERTIES
VERSION ${PDF4QT_VERSION}
SOVERSION ${PDF4QT_VERSION}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
// Copyright (C) 2024 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFBLPAINTER_H
#define PDFBLPAINTER_H
#include "pdfglobal.h"
#include <QImage>
#include <QPaintDevice>
namespace pdf
{
class PDFBLPaintEngine;
class PDF4QTLIBCORESHARED_EXPORT PDFBLPaintDevice : public QPaintDevice
{
public:
PDFBLPaintDevice(QImage& offscreenBuffer, bool isMultithreaded);
virtual ~PDFBLPaintDevice() override;
virtual int devType() const override;
virtual QPaintEngine* paintEngine() const override;
static uint32_t getVersion();
protected:
virtual int metric(PaintDeviceMetric metric) const override;
private:
QImage& m_offscreenBuffer;
PDFBLPaintEngine* m_paintEngine;
};
} // namespace pdf
#endif // PDFBLPAINTER_H

View File

@ -2685,4 +2685,16 @@ CharacterInfos PDFRealizedType3FontImpl::getCharacterInfos() const
return result;
}
QByteArray PDFSystemFont::getFontData(const QByteArray& fontName)
{
const PDFSystemFontInfoStorage* storage = PDFSystemFontInfoStorage::getInstance();
CIDSystemInfo systemInfo;
PDFRenderErrorReporterDummy reporter;
FontDescriptor descriptor;
descriptor.fontName = fontName;
return storage->loadFont(&systemInfo, &descriptor, StandardFontType::Invalid, &reporter);
}
} // namespace pdf

View File

@ -698,6 +698,12 @@ private:
std::map<QByteArray, QByteArray> m_cmaps;
};
class PDF4QTLIBCORESHARED_EXPORT PDFSystemFont
{
public:
static QByteArray getFontData(const QByteArray& fontName);
};
} // namespace pdf
#endif // PDFFONT_H

View File

@ -187,8 +187,9 @@ private:
enum class RendererEngine
{
Software,
OpenGL
Blend2D_MultiThread,
Blend2D_SingleThread,
QPainter,
};
enum class RenderingIntent

View File

@ -18,6 +18,7 @@
#include "pdfpainter.h"
#include "pdfpattern.h"
#include "pdfcms.h"
#include "pdfpainterutils.h"
#include <QPainter>
#include <QCryptographicHash>

View File

@ -1,4 +1,4 @@
// Copyright (C) 2021-2022 Jakub Melka
// Copyright (C) 2021-2024 Jakub Melka
//
// This file is part of PDF4QT.
//
@ -17,6 +17,7 @@
#include "pdfpainterutils.h"
#include <QPainterPath>
#include <QFontMetrics>
#include "pdfdbgheap.h"
@ -63,4 +64,5 @@ QRect PDFPainterHelper::drawBubble(QPainter* painter, QPoint point, QColor color
return rectangle;
}
} // namespace pdf

View File

@ -22,6 +22,7 @@
#include "pdfcolorspaces.h"
#include "pdfexecutionpolicy.h"
#include "pdfconstants.h"
#include "pdfpainterutils.h"
#include <QMutex>
#include <QPainter>

View File

@ -21,19 +21,12 @@
#include "pdfexecutionpolicy.h"
#include "pdfprogress.h"
#include "pdfannotation.h"
#include "pdfblpainter.h"
#include <QDir>
#include <QElapsedTimer>
#include <QtMath>
#ifdef PDF4QT_ENABLE_OPENGL
#include <QOpenGLContext>
#include <QOffscreenSurface>
#include <QOpenGLPaintDevice>
#include <QOpenGLFramebufferObject>
#include <QOpenGLFunctions>
#endif
#include "pdfdbgheap.h"
namespace pdf
@ -227,54 +220,19 @@ void PDFRenderer::compile(PDFPrecompiledPage* precompiledPage, size_t pageIndex)
PDFRasterizer::PDFRasterizer(QObject* parent) :
BaseClass(parent),
#ifdef PDF4QT_ENABLE_OPENGL
m_features(),
m_surfaceFormat(),
m_surface(nullptr),
m_context(nullptr),
m_fbo(nullptr)
#else
m_features()
#endif
m_rendererEngine(RendererEngine::Blend2D_SingleThread)
{
}
PDFRasterizer::~PDFRasterizer()
{
#ifdef PDF4QT_ENABLE_OPENGL
releaseOpenGL();
#endif
}
void PDFRasterizer::reset(bool useOpenGL, const QSurfaceFormat& surfaceFormat)
void PDFRasterizer::reset(RendererEngine rendererEngine)
{
if (!PDFRendererInfo::isHardwareAccelerationSupported())
{
m_features.setFlag(FailedOpenGL, true);
m_features.setFlag(ValidOpenGL, false);
}
#ifdef PDF4QT_ENABLE_OPENGL
if (useOpenGL != m_features.testFlag(UseOpenGL) || surfaceFormat != m_surfaceFormat)
{
// In either case, we must reset OpenGL
releaseOpenGL();
m_features.setFlag(UseOpenGL, useOpenGL);
m_surfaceFormat = surfaceFormat;
// We create new OpenGL renderer, but only if it hasn't failed (we do not try
// again to create new OpenGL renderer.
if (m_features.testFlag(UseOpenGL) && !m_features.testFlag(FailedOpenGL))
{
initializeOpenGL();
}
}
#else
Q_UNUSED(surfaceFormat);
m_features.setFlag(UseOpenGL, useOpenGL);
#endif
m_rendererEngine = rendererEngine;
}
QImage PDFRasterizer::render(PDFInteger pageIndex,
@ -285,70 +243,28 @@ QImage PDFRasterizer::render(PDFInteger pageIndex,
const PDFAnnotationManager* annotationManager,
PageRotation extraRotation)
{
QImage image;
QImage image(size, QImage::Format_ARGB32_Premultiplied);
QTransform matrix = PDFRenderer::createPagePointToDevicePointMatrix(page, QRect(QPoint(0, 0), size), extraRotation);
#ifdef PDF4QT_ENABLE_OPENGL
if (m_features.testFlag(UseOpenGL) && m_features.testFlag(ValidOpenGL))
if (m_rendererEngine == RendererEngine::Blend2D_MultiThread ||
m_rendererEngine == RendererEngine::Blend2D_SingleThread)
{
// We have valid OpenGL context, try to select it and possibly create framebuffer object
// for target image (to paint it using paint device).
Q_ASSERT(m_surface && m_context);
if (m_context->makeCurrent(m_surface))
PDFBLPaintDevice blPaintDevice(image, false);
QPainter painter(&blPaintDevice);
compiledPage->draw(&painter, page->getCropBox(), matrix, features, 1.0);
if (annotationManager)
{
if (!m_fbo || m_fbo->width() != size.width() || m_fbo->height() != size.height())
{
// Delete old framebuffer object
delete m_fbo;
// Create a new framebuffer object
QOpenGLFramebufferObjectFormat format;
format.setSamples(m_surfaceFormat.samples());
m_fbo = new QOpenGLFramebufferObject(size.width(), size.height(), format);
}
Q_ASSERT(m_fbo);
if (m_fbo->isValid() && m_fbo->bind())
{
// Now, we have bind the buffer. Due to bug in Qt's OpenGL drawing subsystem,
// we must render it two times, otherwise painter paths will be sometimes
// replaced by filled rectangles.
for (int i = 0; i < 2; ++i)
{
QOpenGLPaintDevice device(size);
QPainter painter(&device);
painter.fillRect(QRect(QPoint(0, 0), size), compiledPage->getPaperColor());
compiledPage->draw(&painter, page->getCropBox(), matrix, features, 1.0);
if (annotationManager)
{
QList<PDFRenderError> errors;
PDFTextLayoutGetter textLayoutGetter(nullptr, pageIndex);
annotationManager->drawPage(&painter, pageIndex, compiledPage, textLayoutGetter, matrix, errors);
}
}
m_fbo->release();
image = m_fbo->toImage();
}
else
{
m_features.setFlag(FailedOpenGL, true);
m_features.setFlag(ValidOpenGL, false);
}
m_context->doneCurrent();
QList<PDFRenderError> errors;
PDFTextLayoutGetter textLayoutGetter(nullptr, pageIndex);
annotationManager->drawPage(&painter, pageIndex, compiledPage, textLayoutGetter, matrix, errors);
}
}
#endif
if (image.isNull())
else
{
// If we can't use OpenGL, or user doesn't want to use OpenGL, then fallback
// to standard software rasterizer.
image = QImage(size, QImage::Format_ARGB32_Premultiplied);
// Use standard software rasterizer.
image.fill(Qt::white);
QPainter painter(&image);
@ -362,13 +278,6 @@ QImage PDFRasterizer::render(PDFInteger pageIndex,
}
}
// Jakub Melka: Convert the image into format Format_ARGB32_Premultiplied for fast drawing.
// If this format is used, then no image conversion is performed while drawing.
if (image.format() != QImage::Format_ARGB32_Premultiplied)
{
image.convertTo(QImage::Format_ARGB32_Premultiplied);
}
// Calculate image DPI
QSizeF rotatedSizeInMeters = page->getRotatedMediaBoxMM().size() / 1000.0;
QSizeF rotatedSizeInPixels = image.size();
@ -380,87 +289,6 @@ QImage PDFRasterizer::render(PDFInteger pageIndex,
return image;
}
#ifdef PDF4QT_ENABLE_OPENGL
void PDFRasterizer::initializeOpenGL()
{
Q_ASSERT(!m_surface);
Q_ASSERT(!m_context);
Q_ASSERT(!m_fbo);
m_features.setFlag(ValidOpenGL, false);
m_features.setFlag(FailedOpenGL, false);
// Create context
m_context = new QOpenGLContext(this);
m_context->setFormat(m_surfaceFormat);
if (!m_context->create())
{
m_features.setFlag(FailedOpenGL, true);
delete m_context;
m_context = nullptr;
}
// Create surface
m_surface = new QOffscreenSurface(nullptr, this);
m_surface->setFormat(m_surfaceFormat);
m_surface->create();
if (!m_surface->isValid())
{
m_features.setFlag(FailedOpenGL, true);
delete m_context;
delete m_surface;
m_context = nullptr;
m_surface = nullptr;
}
// Check, if we can make it current
if (m_context->makeCurrent(m_surface))
{
m_features.setFlag(ValidOpenGL, true);
m_context->doneCurrent();
}
else
{
m_features.setFlag(FailedOpenGL, true);
releaseOpenGL();
}
}
#endif
#ifdef PDF4QT_ENABLE_OPENGL
void PDFRasterizer::releaseOpenGL()
{
if (m_surface)
{
Q_ASSERT(m_context);
// Delete framebuffer
if (m_fbo)
{
m_context->makeCurrent(m_surface);
delete m_fbo;
m_fbo = nullptr;
m_context->doneCurrent();
}
// Delete OpenGL context
delete m_context;
m_context = nullptr;
// Delete surface
m_surface->destroy();
delete m_surface;
m_surface = nullptr;
// Set flag, that we do not have valid OpenGL
m_features.setFlag(ValidOpenGL, false);
}
}
#endif
PDFRasterizer* PDFRasterizerPool::acquire()
{
m_semaphore.acquire();
@ -978,8 +806,7 @@ PDFRasterizerPool::PDFRasterizerPool(const PDFDocument* document,
PDFRenderer::Features features,
const PDFMeshQualitySettings& meshQualitySettings,
int rasterizerCount,
bool useOpenGL,
const QSurfaceFormat& surfaceFormat,
RendererEngine rendererEngine,
QObject* parent) :
BaseClass(parent),
m_document(document),
@ -994,96 +821,8 @@ PDFRasterizerPool::PDFRasterizerPool(const PDFDocument* document,
for (int i = 0; i < rasterizerCount; ++i)
{
m_rasterizers.push_back(new PDFRasterizer(this));
m_rasterizers.back()->reset(useOpenGL, surfaceFormat);
m_rasterizers.back()->reset(rendererEngine);
}
}
PDFCachedItem<PDFRendererInfo::Info> PDFRendererInfo::s_info;
const PDFRendererInfo::Info& PDFRendererInfo::getHardwareAccelerationSupportedInfo()
{
auto getInfo = []()
{
Info info;
#ifdef PDF4QT_ENABLE_OPENGL
QOffscreenSurface surface;
surface.create();
if (!surface.isValid())
{
info.renderer = PDFTranslationContext::tr("GDI Generic");
info.version = PDFTranslationContext::tr("1.1");
info.vendor = PDFTranslationContext::tr("System");
return info;
}
QOpenGLContext context;
if (!context.create())
{
info.renderer = PDFTranslationContext::tr("GDI Generic");
info.version = PDFTranslationContext::tr("1.1");
info.vendor = PDFTranslationContext::tr("System");
surface.destroy();
return info;
}
if (!context.makeCurrent(&surface))
{
info.renderer = PDFTranslationContext::tr("GDI Generic");
info.version = PDFTranslationContext::tr("1.1");
info.vendor = PDFTranslationContext::tr("System");
surface.destroy();
return info;
}
const char* versionStr = reinterpret_cast<const char*>(context.functions()->glGetString(GL_VERSION));
const char* vendorStr = reinterpret_cast<const char*>(context.functions()->glGetString(GL_VENDOR));
const char* rendererStr = reinterpret_cast<const char*>(context.functions()->glGetString(GL_RENDERER));
QString versionString = QString::fromLocal8Bit(versionStr, std::strlen(versionStr));
QString vendorString = QString::fromLocal8Bit(vendorStr, std::strlen(vendorStr));
QString rendererString = QString::fromLocal8Bit(rendererStr, std::strlen(rendererStr));
context.doneCurrent();
surface.destroy();
versionString = versionString.trimmed();
int spaceIndex = versionString.indexOf(QChar(QChar::Space));
if (spaceIndex != -1)
{
versionString = versionString.left(spaceIndex);
}
info.vendor = vendorString;
info.renderer = rendererString;
info.version = versionString;
QStringList versionStrSplitted = versionString.split('.', Qt::KeepEmptyParts);
if (versionStrSplitted.size() >= 2)
{
info.majorOpenGLVersion = versionStrSplitted[0].toInt();
info.minorOpenGLVersion = versionStrSplitted[1].toInt();
}
#endif
return info;
};
return s_info.get(getInfo);
}
bool PDFRendererInfo::isHardwareAccelerationSupported()
{
#ifdef PDF4QT_ENABLE_OPENGL
const Info& info = getHardwareAccelerationSupportedInfo();
return std::make_pair(info.majorOpenGLVersion, info.minorOpenGLVersion) >= std::make_pair(REQUIRED_OPENGL_MAJOR_VERSION, REQUIRED_OPENGL_MINOR_VERSION);
#else
return false;
#endif
}
} // namespace pdf

View File

@ -28,13 +28,9 @@
#include <QMutex>
#include <QSemaphore>
#include <QImageWriter>
#include <QSurfaceFormat>
#include <QImage>
class QPainter;
class QOpenGLContext;
class QOffscreenSurface;
class QOpenGLFramebufferObject;
namespace pdf
{
@ -46,30 +42,6 @@ class PDFPrecompiledPage;
class PDFAnnotationManager;
class PDFOptionalContentActivity;
class PDF4QTLIBCORESHARED_EXPORT PDFRendererInfo
{
public:
PDFRendererInfo() = delete;
struct Info
{
QString vendor;
QString renderer;
QString version;
int majorOpenGLVersion = 0;
int minorOpenGLVersion = 0;
};
static const Info& getHardwareAccelerationSupportedInfo();
static bool isHardwareAccelerationSupported();
static constexpr int REQUIRED_OPENGL_MAJOR_VERSION = 3;
static constexpr int REQUIRED_OPENGL_MINOR_VERSION = 2;
private:
static PDFCachedItem<Info> s_info;
};
/// Renders the PDF page on the painter, or onto an image.
class PDF4QTLIBCORESHARED_EXPORT PDFRenderer
{
@ -165,9 +137,7 @@ private:
PDFMeshQualitySettings m_meshQualitySettings;
};
/// Renders PDF pages to bitmap images (QImage). It can use OpenGL for painting,
/// if it is enabled, if this is the case, offscreen rendering to framebuffer
/// is used.
/// Renders PDF pages to bitmap images (QImage).
/// \note Construct this object only in main GUI thread
class PDF4QTLIBCORESHARED_EXPORT PDFRasterizer : public QObject
{
@ -180,22 +150,9 @@ public:
explicit PDFRasterizer(QObject* parent);
virtual ~PDFRasterizer() override;
/// Resets the renderer. This function must be called from main GUI thread,
/// it cannot be called from deferred threads, because it can create hidden
/// window (offscreen surface). If hardware renderer is required, and
/// none is available, then software renderer is used.
/// \param useOpenGL Use OpenGL for rendering (ignored if not available)
/// \param surfaceFormat Surface format to render
void reset(bool useOpenGL, const QSurfaceFormat& surfaceFormat);
enum Feature
{
UseOpenGL = 0x0001, ///< Use OpenGL for rendering
ValidOpenGL = 0x0002, ///< OpenGL is initialized and valid
FailedOpenGL = 0x0004, ///< OpenGL creation has failed
};
Q_DECLARE_FLAGS(Features, Feature)
/// Resets the renderer.
/// \param rendererEngine Renderer engine type
void reset(RendererEngine rendererEngine);
/// Renders page to the image of given size. If some error occurs, then
/// empty image is returned. Warning: this function can modify this object,
@ -217,18 +174,7 @@ public:
PageRotation extraRotation);
private:
#ifdef PDF4QT_ENABLE_OPENGL
void initializeOpenGL();
void releaseOpenGL();
#endif
Features m_features;
#ifdef PDF4QT_ENABLE_OPENGL
QSurfaceFormat m_surfaceFormat;
QOffscreenSurface* m_surface;
QOpenGLContext* m_context;
QOpenGLFramebufferObject* m_fbo;
#endif
RendererEngine m_rendererEngine;
};
/// Simple structure for storing rendered page images
@ -267,8 +213,7 @@ public:
/// \param features Renderer features
/// \param meshQualitySettings Mesh quality settings
/// \param rasterizerCount Number of rasterizers
/// \param useOpenGL Use OpenGL for rendering?
/// \param surfaceFormat Surface format
/// \param rendererEngine Renderer engine
/// \param parent Parent object
explicit PDFRasterizerPool(const PDFDocument* document,
PDFFontCache* fontCache,
@ -277,8 +222,7 @@ public:
PDFRenderer::Features features,
const PDFMeshQualitySettings& meshQualitySettings,
int rasterizerCount,
bool useOpenGL,
const QSurfaceFormat& surfaceFormat,
RendererEngine rendererEngine,
QObject* parent);
/// Acquire rasterizer. This function is thread safe.

View File

@ -17,6 +17,7 @@
#include "pdfutils.h"
#include "pdfexception.h"
#include "pdfblpainter.h"
#include <QtGlobal>
#include <QtMath>
@ -315,6 +316,18 @@ std::vector<PDFDependentLibraryInfo> PDFDependentLibraryInfo::getLibraryInfo()
zlibInfo.url = tr("https://zlib.net/");
result.emplace_back(qMove(zlibInfo));
// blend2d
const uint32_t blend2dVersion = PDFBLPaintDevice::getVersion();
const int blend2dMajor = (blend2dVersion >> 16) & 0xFF;
const int blend2dMinor = (blend2dVersion >> 8) & 0xFF;
const int blend2dPatch = (blend2dVersion) & 0xFF;
PDFDependentLibraryInfo blend2dInfo;
blend2dInfo.library = tr("Blend2D");
blend2dInfo.license = tr("zlib specific");
blend2dInfo.version = QString("%1.%2.%3").arg(blend2dMajor).arg(blend2dMinor).arg(blend2dPatch);
blend2dInfo.url = tr("https://blend2d.com/");
result.emplace_back(qMove(blend2dInfo));
return result;
}

View File

@ -74,10 +74,6 @@ GENERATE_EXPORT_HEADER(Pdf4QtLibWidgets
PDF4QTLIBWIDGETSSHARED_EXPORT
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}/pdf4qtlibwidgets_export.h")
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(Pdf4QtLibWidgets PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(Pdf4QtLibWidgets PRIVATE Pdf4QtLibCore Qt6::Core Qt6::Gui Qt6::Xml Qt6::Svg Qt6::Widgets)
if(LINUX_GCC)
@ -88,6 +84,8 @@ if(MINGW)
target_link_libraries(Pdf4QtLibWidgets PRIVATE Secur32 Mscms Gdi32 User32 crypt32)
endif()
target_link_libraries(Pdf4QtLibWidgets PRIVATE blend2d::blend2d)
target_include_directories(Pdf4QtLibWidgets INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/sources)
target_include_directories(Pdf4QtLibWidgets PUBLIC ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR})

View File

@ -24,6 +24,7 @@
#include "pdfannotation.h"
#include "pdfdrawwidget.h"
#include "pdfwidgetannotation.h"
#include "pdfpainterutils.h"
#include <QTimer>
#include <QPainter>
@ -469,7 +470,7 @@ PDFDrawWidgetProxy::PDFDrawWidgetProxy(QObject* parent) :
m_rasterizer(new PDFRasterizer(this)),
m_progress(nullptr),
m_cacheClearTimer(new QTimer(this)),
m_useOpenGL(false)
m_rendererEngine(RendererEngine::Blend2D_MultiThread)
{
m_controller = new PDFDrawSpaceController(this);
connect(m_controller, &PDFDrawSpaceController::drawSpaceChanged, this, &PDFDrawWidgetProxy::update);
@ -1403,11 +1404,10 @@ bool PDFDrawWidgetProxy::isBlockMode() const
return false;
}
void PDFDrawWidgetProxy::updateRenderer(bool useOpenGL, const QSurfaceFormat& surfaceFormat)
void PDFDrawWidgetProxy::updateRenderer(RendererEngine rendererEngine)
{
m_useOpenGL = useOpenGL;
m_surfaceFormat = surfaceFormat;
m_rasterizer->reset(useOpenGL && ENABLE_OPENGL_FOR_THUMBNAILS, surfaceFormat);
m_rendererEngine = rendererEngine;
m_rasterizer->reset(m_rendererEngine);
}
void PDFDrawWidgetProxy::prefetchPages(PDFInteger pageIndex)

View File

@ -317,9 +317,8 @@ public:
/// Updates renderer (in current implementation, renderer for page thumbnails)
/// using given parameters.
/// \param useOpenGL Use OpenGL for rendering?
/// \param surfaceFormat Surface format for OpenGL rendering
void updateRenderer(bool useOpenGL, const QSurfaceFormat& surfaceFormat);
/// \param rendererEngine Renderer engine
void updateRenderer(RendererEngine rendererEngine);
/// Prefetches (prerenders) pages after page with pageIndex, i.e., prepares
/// for non-flickering scroll operation.
@ -338,8 +337,7 @@ public:
void setProgress(PDFProgress* progress) { m_progress = progress; }
PDFAsynchronousTextLayoutCompiler* getTextLayoutCompiler() const { return m_textLayoutCompiler; }
PDFWidget* getWidget() const { return m_widget; }
bool isUsingOpenGL() const { return m_useOpenGL; }
const QSurfaceFormat& getSurfaceFormat() const { return m_surfaceFormat; }
RendererEngine getRendererEngine() const { return m_rendererEngine; }
PageRotation getPageRotation() const { return m_controller->getPageRotation(); }
void setFeatures(PDFRenderer::Features features);
@ -461,8 +459,6 @@ private:
constexpr inline T bound(T value) { return qBound(min, value, max); }
};
static constexpr bool ENABLE_OPENGL_FOR_THUMBNAILS = false;
/// Flag, disables the update
bool m_updateDisabled;
@ -536,11 +532,8 @@ private:
/// Additional drawing interfaces
std::set<IDocumentDrawInterface*> m_drawInterfaces;
/// Use OpenGL for rendering?
bool m_useOpenGL;
/// Surface format for OpenGL
QSurfaceFormat m_surfaceFormat;
/// Renderer engine
RendererEngine m_rendererEngine;
/// Page group info for rendering. Group of pages
/// can be rendered with transparency or without paper

View File

@ -22,6 +22,7 @@
#include "pdfannotation.h"
#include "pdfwidgetannotation.h"
#include "pdfwidgetformmanager.h"
#include "pdfblpainter.h"
#include <QPainter>
#include <QGridLayout>
@ -35,7 +36,7 @@
namespace pdf
{
PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int samplesCount, QWidget* parent) :
PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, QWidget* parent) :
QWidget(parent),
m_cmsManager(cmsManager),
m_toolManager(nullptr),
@ -44,9 +45,10 @@ PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int
m_drawWidget(nullptr),
m_horizontalScrollBar(nullptr),
m_verticalScrollBar(nullptr),
m_proxy(nullptr)
m_proxy(nullptr),
m_rendererEngine(engine)
{
m_drawWidget = createDrawWidget(getEffectiveRenderer(engine), samplesCount);
m_drawWidget = new PDFDrawWidget(this, this);
m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this);
m_verticalScrollBar = new QScrollBar(Qt::Vertical, this);
@ -62,10 +64,10 @@ PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int
m_proxy = new PDFDrawWidgetProxy(this);
m_proxy->init(this);
m_proxy->updateRenderer(m_rendererEngine);
connect(m_proxy, &PDFDrawWidgetProxy::renderingError, this, &PDFWidget::onRenderingError);
connect(m_proxy, &PDFDrawWidgetProxy::repaintNeeded, m_drawWidget->getWidget(), QOverload<>::of(&QWidget::update));
connect(m_proxy, &PDFDrawWidgetProxy::pageImageChanged, this, &PDFWidget::onPageImageChanged);
updateRendererImpl();
}
PDFWidget::~PDFWidget()
@ -90,39 +92,10 @@ void PDFWidget::setDocument(const PDFModifiedDocument& document)
m_drawWidget->getWidget()->update();
}
void PDFWidget::updateRenderer(RendererEngine engine, int samplesCount)
void PDFWidget::updateRenderer(RendererEngine engine)
{
engine = getEffectiveRenderer(engine);
PDFOpenGLDrawWidget* openglDrawWidget = qobject_cast<PDFOpenGLDrawWidget*>(m_drawWidget->getWidget());
PDFDrawWidget* softwareDrawWidget = qobject_cast<PDFDrawWidget*>(m_drawWidget->getWidget());
// Do we need to change renderer?
if ((openglDrawWidget && engine != RendererEngine::OpenGL) || (softwareDrawWidget && engine != RendererEngine::Software))
{
QGridLayout* layout = qobject_cast<QGridLayout*>(this->layout());
layout->removeWidget(m_drawWidget->getWidget());
delete m_drawWidget->getWidget();
m_drawWidget = createDrawWidget(engine, samplesCount);
layout->addWidget(m_drawWidget->getWidget(), 0, 0);
setFocusProxy(m_drawWidget->getWidget());
connect(m_proxy, &PDFDrawWidgetProxy::repaintNeeded, m_drawWidget->getWidget(), QOverload<>::of(&QWidget::update));
}
#ifdef PDF4QT_ENABLE_OPENGL
else if (openglDrawWidget)
{
// Just check the samples count
QSurfaceFormat format = openglDrawWidget->format();
if (format.samples() != samplesCount)
{
format.setSamples(samplesCount);
openglDrawWidget->setFormat(format);
}
}
#endif
updateRendererImpl();
m_rendererEngine = engine;
m_proxy->updateRenderer(m_rendererEngine);
}
void PDFWidget::updateCacheLimits(int compiledPageCacheLimit, int thumbnailsCacheLimit, int fontCacheLimit, int instancedFontCacheLimit)
@ -142,16 +115,6 @@ int PDFWidget::getPageRenderingErrorCount() const
return count;
}
void PDFWidget::updateRendererImpl()
{
#ifdef PDF4QT_ENABLE_OPENGL
PDFOpenGLDrawWidget* openglDrawWidget = qobject_cast<PDFOpenGLDrawWidget*>(m_drawWidget->getWidget());
m_proxy->updateRenderer(openglDrawWidget != nullptr, openglDrawWidget ? openglDrawWidget->format() : QSurfaceFormat::defaultFormat());
#else
m_proxy->updateRenderer(false, QSurfaceFormat::defaultFormat());
#endif
}
void PDFWidget::onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors)
{
// Empty list of error should not be reported!
@ -182,29 +145,6 @@ void PDFWidget::onPageImageChanged(bool all, const std::vector<PDFInteger>& page
}
}
IDrawWidget* PDFWidget::createDrawWidget(RendererEngine rendererEngine, int samplesCount)
{
switch (rendererEngine)
{
case RendererEngine::Software:
return new PDFDrawWidget(this, this);
case RendererEngine::OpenGL:
#ifdef PDF4QT_ENABLE_OPENGL
return new PDFOpenGLDrawWidget(this, samplesCount, this);
#else
Q_UNUSED(samplesCount);
return new PDFDrawWidget(this, this);
#endif
default:
Q_ASSERT(false);
break;
}
return nullptr;
}
void PDFWidget::removeInputInterface(IDrawWidgetInputInterface* inputInterface)
{
auto it = std::find(m_inputInterfaces.begin(), m_inputInterfaces.end(), inputInterface);
@ -223,16 +163,6 @@ void PDFWidget::addInputInterface(IDrawWidgetInputInterface* inputInterface)
}
}
RendererEngine PDFWidget::getEffectiveRenderer(RendererEngine rendererEngine)
{
if (rendererEngine == RendererEngine::OpenGL && !pdf::PDFRendererInfo::isHardwareAccelerationSupported())
{
return RendererEngine::Software;
}
return rendererEngine;
}
PDFWidgetFormManager* PDFWidget::getFormManager() const
{
return m_formManager;
@ -259,43 +189,38 @@ void PDFWidget::setAnnotationManager(PDFWidgetAnnotationManager* annotationManag
addInputInterface(m_annotationManager);
}
template<typename BaseWidget>
PDFDrawWidgetBase<BaseWidget>::PDFDrawWidgetBase(PDFWidget* widget, QWidget* parent) :
BaseWidget(parent),
PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) :
BaseClass(parent),
m_widget(widget),
m_mouseOperation(MouseOperation::None)
{
this->setFocusPolicy(Qt::StrongFocus);
this->setMouseTracking(true);
QObject::connect(&m_autoScrollTimer, &QTimer::timeout, this, &PDFDrawWidgetBase::onAutoScrollTimeout);
QObject::connect(&m_autoScrollTimer, &QTimer::timeout, this, &PDFDrawWidget::onAutoScrollTimeout);
}
template<typename BaseWidget>
std::vector<PDFInteger> PDFDrawWidgetBase<BaseWidget>::getCurrentPages() const
std::vector<PDFInteger> PDFDrawWidget::getCurrentPages() const
{
return this->m_widget->getDrawWidgetProxy()->getPagesIntersectingRect(this->rect());
}
template<typename BaseWidget>
QSize PDFDrawWidgetBase<BaseWidget>::minimumSizeHint() const
QSize PDFDrawWidget::minimumSizeHint() const
{
return QSize(200, 200);
}
template<typename BaseWidget>
bool PDFDrawWidgetBase<BaseWidget>::event(QEvent* event)
bool PDFDrawWidget::event(QEvent* event)
{
if (event->type() == QEvent::ShortcutOverride)
{
return processEvent<QKeyEvent, &IDrawWidgetInputInterface::shortcutOverrideEvent>(static_cast<QKeyEvent*>(event));
}
return BaseWidget::event(event);
return BaseClass::event(event);
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::performMouseOperation(QPoint currentMousePosition)
void PDFDrawWidget::performMouseOperation(QPoint currentMousePosition)
{
switch (m_mouseOperation)
{
@ -323,9 +248,8 @@ void PDFDrawWidgetBase<BaseWidget>::performMouseOperation(QPoint currentMousePos
}
}
template<typename BaseWidget>
template<typename Event, void (IDrawWidgetInputInterface::* Function)(QWidget*, Event*)>
bool PDFDrawWidgetBase<BaseWidget>::processEvent(Event* event)
bool PDFDrawWidget::processEvent(Event* event)
{
QString tooltip;
for (IDrawWidgetInputInterface* inputInterface : m_widget->getInputInterfaces())
@ -351,8 +275,7 @@ bool PDFDrawWidgetBase<BaseWidget>::processEvent(Event* event)
return false;
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::keyPressEvent(QKeyEvent* event)
void PDFDrawWidget::keyPressEvent(QKeyEvent* event)
{
event->ignore();
@ -388,8 +311,7 @@ void PDFDrawWidgetBase<BaseWidget>::keyPressEvent(QKeyEvent* event)
updateCursor();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::keyReleaseEvent(QKeyEvent* event)
void PDFDrawWidget::keyReleaseEvent(QKeyEvent* event)
{
event->ignore();
@ -401,8 +323,7 @@ void PDFDrawWidgetBase<BaseWidget>::keyReleaseEvent(QKeyEvent* event)
event->accept();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::mousePressEvent(QMouseEvent* event)
void PDFDrawWidget::mousePressEvent(QMouseEvent* event)
{
event->ignore();
@ -442,8 +363,7 @@ void PDFDrawWidgetBase<BaseWidget>::mousePressEvent(QMouseEvent* event)
event->accept();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::mouseDoubleClickEvent(QMouseEvent* event)
void PDFDrawWidget::mouseDoubleClickEvent(QMouseEvent* event)
{
event->ignore();
@ -453,8 +373,7 @@ void PDFDrawWidgetBase<BaseWidget>::mouseDoubleClickEvent(QMouseEvent* event)
}
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::mouseReleaseEvent(QMouseEvent* event)
void PDFDrawWidget::mouseReleaseEvent(QMouseEvent* event)
{
event->ignore();
@ -491,8 +410,7 @@ void PDFDrawWidgetBase<BaseWidget>::mouseReleaseEvent(QMouseEvent* event)
event->accept();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::mouseMoveEvent(QMouseEvent* event)
void PDFDrawWidget::mouseMoveEvent(QMouseEvent* event)
{
event->ignore();
@ -506,8 +424,7 @@ void PDFDrawWidgetBase<BaseWidget>::mouseMoveEvent(QMouseEvent* event)
event->accept();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::updateCursor()
void PDFDrawWidget::updateCursor()
{
std::optional<QCursor> cursor;
@ -554,8 +471,7 @@ void PDFDrawWidgetBase<BaseWidget>::updateCursor()
}
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::onAutoScrollTimeout()
void PDFDrawWidget::onAutoScrollTimeout()
{
if (m_mouseOperation != MouseOperation::AutoScroll)
{
@ -579,8 +495,7 @@ void PDFDrawWidgetBase<BaseWidget>::onAutoScrollTimeout()
proxy->scrollByPixels(QPoint(scrollX, scrollY));
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::wheelEvent(QWheelEvent* event)
void PDFDrawWidget::wheelEvent(QWheelEvent* event)
{
event->ignore();
@ -659,62 +574,59 @@ void PDFDrawWidgetBase<BaseWidget>::wheelEvent(QWheelEvent* event)
event->accept();
}
#ifdef PDF4QT_ENABLE_OPENGL
PDFOpenGLDrawWidget::PDFOpenGLDrawWidget(PDFWidget* widget, int samplesCount, QWidget* parent) :
BaseClass(widget, parent)
{
QSurfaceFormat format = this->format();
format.setProfile(QSurfaceFormat::CoreProfile);
format.setSamples(samplesCount);
format.setColorSpace(QColorSpace(QColorSpace::SRgb));
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
setFormat(format);
}
PDFOpenGLDrawWidget::~PDFOpenGLDrawWidget()
{
}
void PDFOpenGLDrawWidget::resizeGL(int w, int h)
{
QOpenGLWidget::resizeGL(w, h);
getPDFWidget()->getDrawWidgetProxy()->update();
}
void PDFOpenGLDrawWidget::initializeGL()
{
QOpenGLWidget::initializeGL();
}
void PDFOpenGLDrawWidget::paintGL()
{
if (this->isValid())
{
QPainter painter(this);
getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
}
}
#endif
PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) :
BaseClass(widget, parent)
{
}
PDFDrawWidget::~PDFDrawWidget()
{
}
void PDFDrawWidget::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
QPainter painter(this);
getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
RendererEngine rendererEngine = getPDFWidget()->getDrawWidgetProxy()->getRendererEngine();
switch (rendererEngine)
{
case RendererEngine::Blend2D_MultiThread:
case RendererEngine::Blend2D_SingleThread:
{
QRect rect = this->rect();
qreal devicePixelRatio = devicePixelRatioF();
m_blend2DframeBuffer.setDevicePixelRatio(devicePixelRatio);
qreal dpmX = logicalDpiX() / 0.0254;
qreal dpmY = logicalDpiY() / 0.0254;
m_blend2DframeBuffer.setDotsPerMeterX(qCeil(dpmX));
m_blend2DframeBuffer.setDotsPerMeterY(qCeil(dpmY));
QSize requiredSize = rect.size() * devicePixelRatio;
if (m_blend2DframeBuffer.size() != requiredSize)
{
m_blend2DframeBuffer = QImage(requiredSize, QImage::Format_ARGB32_Premultiplied);
}
const bool multithreaded = rendererEngine == RendererEngine::Blend2D_MultiThread;
PDFBLPaintDevice blPaintDevice(m_blend2DframeBuffer, multithreaded);
QPainter blPainter;
if (blPainter.begin(&blPaintDevice))
{
getPDFWidget()->getDrawWidgetProxy()->draw(&blPainter, rect);
blPainter.end();
}
QPainter painter(this);
painter.drawImage(QPoint(0, 0), m_blend2DframeBuffer);
break;
}
case RendererEngine::QPainter:
{
QPainter painter(this);
getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
m_blend2DframeBuffer = QImage();
break;
}
default:
Q_ASSERT(false);
break;
}
}
void PDFDrawWidget::resizeEvent(QResizeEvent* event)
@ -724,9 +636,4 @@ void PDFDrawWidget::resizeEvent(QResizeEvent* event)
getPDFWidget()->getDrawWidgetProxy()->update();
}
#ifdef PDF4QT_ENABLE_OPENGL
template class PDFDrawWidgetBase<QOpenGLWidget>;
#endif
template class PDFDrawWidgetBase<QWidget>;
} // namespace pdf

View File

@ -27,10 +27,6 @@
#include <QTimer>
#include <QElapsedTimer>
#ifdef PDF4QT_ENABLE_OPENGL
#include <QOpenGLWidget>
#endif
namespace pdf
{
class PDFDocument;
@ -65,8 +61,7 @@ public:
/// Constructs new PDFWidget.
/// \param cmsManager Color management system manager
/// \param engine Rendering engine type
/// \param samplesCount Samples count for rendering engine MSAA antialiasing
explicit PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int samplesCount, QWidget* parent);
explicit PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, QWidget* parent);
virtual ~PDFWidget() override;
virtual bool focusNextPrevChild(bool next) override;
@ -81,8 +76,7 @@ public:
/// Update rendering engine according the settings
/// \param engine Engine type
/// \param samplesCount Samples count for rendering engine MSAA antialiasing
void updateRenderer(RendererEngine engine, int samplesCount);
void updateRenderer(RendererEngine engine);
/// Updates cache limits
/// \param compiledPageCacheLimit Compiled page cache limit [bytes]
@ -115,14 +109,9 @@ signals:
void pageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount);
private:
RendererEngine getEffectiveRenderer(RendererEngine rendererEngine);
void updateRendererImpl();
void onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors);
void onPageImageChanged(bool all, const std::vector<PDFInteger>& pages);
IDrawWidget* createDrawWidget(RendererEngine rendererEngine, int samplesCount);
const PDFCMSManager* m_cmsManager;
PDFToolManager* m_toolManager;
PDFWidgetAnnotationManager* m_annotationManager;
@ -133,14 +122,19 @@ private:
PDFDrawWidgetProxy* m_proxy;
PageRenderingErrors m_pageRenderingErrors;
std::vector<IDrawWidgetInputInterface*> m_inputInterfaces;
RendererEngine m_rendererEngine;
};
template<typename BaseWidget>
class PDFDrawWidgetBase : public BaseWidget, public IDrawWidget
class PDFDrawWidget : public QWidget, public IDrawWidget
{
Q_OBJECT
private:
using BaseClass = QWidget;
public:
explicit PDFDrawWidgetBase(PDFWidget* widget, QWidget* parent);
virtual ~PDFDrawWidgetBase() override = default;
explicit PDFDrawWidget(PDFWidget* widget, QWidget* parent);
virtual ~PDFDrawWidget() override = default;
/// Returns page indices, which are currently displayed in the widget
virtual std::vector<PDFInteger> getCurrentPages() const override;
@ -158,6 +152,8 @@ protected:
virtual void mouseReleaseEvent(QMouseEvent* event) override;
virtual void mouseMoveEvent(QMouseEvent* event) override;
virtual void wheelEvent(QWheelEvent* event) override;
virtual void paintEvent(QPaintEvent* event) override;
virtual void resizeEvent(QResizeEvent* event) override;
PDFWidget* getPDFWidget() const { return m_widget; }
@ -186,50 +182,9 @@ private:
QTimer m_autoScrollTimer;
QPointF m_autoScrollOffset;
QElapsedTimer m_autoScrollLastElapsedTimer;
QImage m_blend2DframeBuffer;
};
class PDFDrawWidget : public PDFDrawWidgetBase<QWidget>
{
Q_OBJECT
private:
using BaseClass = PDFDrawWidgetBase<QWidget>;
public:
explicit PDFDrawWidget(PDFWidget* widget, QWidget* parent);
virtual ~PDFDrawWidget() override;
protected:
virtual void paintEvent(QPaintEvent* event) override;
virtual void resizeEvent(QResizeEvent* event) override;
};
#ifdef PDF4QT_ENABLE_OPENGL
class PDFOpenGLDrawWidget : public PDFDrawWidgetBase<QOpenGLWidget>
{
Q_OBJECT
private:
using BaseClass = PDFDrawWidgetBase<QOpenGLWidget>;
public:
explicit PDFOpenGLDrawWidget(PDFWidget* widget, int samplesCount, QWidget* parent);
virtual ~PDFOpenGLDrawWidget() override;
protected:
virtual void resizeGL(int w, int h) override;
virtual void initializeGL() override;
virtual void paintGL() override;
};
#else
using PDFOpenGLDrawWidget = PDFDrawWidget;
#endif
#ifdef PDF4QT_ENABLE_OPENGL
extern template class PDFDrawWidgetBase<QOpenGLWidget>;
#endif
extern template class PDFDrawWidgetBase<QWidget>;
} // namespace pdf
#endif // PDFDRAWWIDGET_H

View File

@ -1197,7 +1197,7 @@ void PDFMagnifierTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
if (m_mousePos != mousePos)
{
m_mousePos = mousePos;
getProxy()->repaintNeeded();
Q_EMIT getProxy()->repaintNeeded();
}
}

View File

@ -86,10 +86,6 @@ GENERATE_EXPORT_HEADER(Pdf4QtViewer
PDF4QTVIEWERLIBSHARED_EXPORT
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}/pdf4qtviewer_export.h")
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(Pdf4QtViewer PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(Pdf4QtViewer PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets Qt6::PrintSupport Qt6::TextToSpeech Qt6::Xml Qt6::Svg)
target_include_directories(Pdf4QtViewer INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(Pdf4QtViewer PUBLIC ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR})

View File

@ -150,6 +150,7 @@ std::vector<QAction*> PDFActionManager::getRenderingOptionActions() const
RenderOptionTextAntialiasing,
RenderOptionSmoothPictures,
RenderOptionIgnoreOptionalContentSettings,
RenderOptionDisplayRenderTimes,
RenderOptionDisplayAnnotations,
RenderOptionInvertColors,
RenderOptionGrayscale,
@ -157,8 +158,7 @@ std::vector<QAction*> PDFActionManager::getRenderingOptionActions() const
RenderOptionHighContrast,
RenderOptionCustomColors,
RenderOptionShowTextBlocks,
RenderOptionShowTextLines
});
RenderOptionShowTextLines});
}
std::vector<QAction*> PDFActionManager::getActions() const
@ -266,6 +266,7 @@ void PDFActionManager::initActions(QSize iconSize, bool initializeStampActions)
setUserData(RenderOptionTextAntialiasing, pdf::PDFRenderer::TextAntialiasing);
setUserData(RenderOptionSmoothPictures, pdf::PDFRenderer::SmoothImages);
setUserData(RenderOptionIgnoreOptionalContentSettings, pdf::PDFRenderer::IgnoreOptionalContent);
setUserData(RenderOptionDisplayRenderTimes, pdf::PDFRenderer::DisplayTimes);
setUserData(RenderOptionDisplayAnnotations, pdf::PDFRenderer::DisplayAnnotations);
setUserData(RenderOptionInvertColors, pdf::PDFRenderer::ColorAdjust_Invert);
setUserData(RenderOptionGrayscale, pdf::PDFRenderer::ColorAdjust_Grayscale);
@ -624,7 +625,7 @@ void PDFProgramController::initialize(Features features,
readSettings(Settings(GeneralSettings | PluginsSettings | RecentFileSettings | CertificateSettings));
m_pdfWidget = new pdf::PDFWidget(m_CMSManager, m_settings->getRendererEngine(), m_settings->isMultisampleAntialiasingEnabled() ? m_settings->getRendererSamples() : -1, m_mainWindow);
m_pdfWidget = new pdf::PDFWidget(m_CMSManager, m_settings->getRendererEngine(), m_mainWindow);
m_pdfWidget->setObjectName("pdfWidget");
m_pdfWidget->updateCacheLimits(m_settings->getCompiledPageCacheLimit() * 1024, m_settings->getThumbnailsCacheLimit(), m_settings->getFontCacheLimit(), m_settings->getInstancedFontCacheLimit());
m_pdfWidget->getDrawWidgetProxy()->setProgress(m_progress);
@ -1697,7 +1698,7 @@ void PDFProgramController::updateActionsAvailability()
void PDFProgramController::onViewerSettingsChanged()
{
m_pdfWidget->updateRenderer(m_settings->getRendererEngine(), m_settings->isMultisampleAntialiasingEnabled() ? m_settings->getRendererSamples() : -1);
m_pdfWidget->updateRenderer(m_settings->getRendererEngine());
m_pdfWidget->updateCacheLimits(m_settings->getCompiledPageCacheLimit() * 1024, m_settings->getThumbnailsCacheLimit(), m_settings->getFontCacheLimit(), m_settings->getInstancedFontCacheLimit());
m_pdfWidget->getDrawWidgetProxy()->setFeatures(m_settings->getFeatures());
m_pdfWidget->getDrawWidgetProxy()->setPreferredMeshResolutionRatio(m_settings->getPreferredMeshResolutionRatio());
@ -2298,24 +2299,6 @@ void PDFProgramController::resetSettings()
}
}
void PDFProgramController::checkHardwareOpenGLAvailability()
{
if (m_settings->getRendererEngine() == pdf::RendererEngine::OpenGL &&
!pdf::PDFRendererInfo::isHardwareAccelerationSupported())
{
#ifdef PDF4QT_ENABLE_OPENGL
pdf::PDFRendererInfo::Info info = pdf::PDFRendererInfo::getHardwareAccelerationSupportedInfo();
QMessageBox::warning(m_mainWindow, tr("Warning"),
tr("Hardware acceleration is not supported on this device. "
"OpenGL version at least 3.2 is required. Software rendering is used instead. "
"Available OpenGL is %1 using %2. You can turn off hardware acceleration "
"in 'Tools' menu using 'Options' item to stop displaying this message.").arg(info.version, info.renderer));
#else
QMessageBox::warning(m_mainWindow, tr("Warning"), tr("Hardware acceleration is not enabled in this build."));
#endif
}
}
void PDFProgramController::onActionOptionsTriggered()
{
PDFViewerSettingsDialog::OtherSettings otherSettings;

View File

@ -161,6 +161,7 @@ public:
RenderOptionTextAntialiasing,
RenderOptionSmoothPictures,
RenderOptionIgnoreOptionalContentSettings,
RenderOptionDisplayRenderTimes,
RenderOptionDisplayAnnotations,
RenderOptionInvertColors,
RenderOptionGrayscale,
@ -297,8 +298,6 @@ public:
void writeSettings();
void resetSettings();
void checkHardwareOpenGLAvailability();
void performPrint();
void performSave();
void performSaveAs();

View File

@ -299,7 +299,7 @@ void PDFRenderToImagesDialog::on_buttonBox_clicked(QAbstractButton* button)
m_cms = m_proxy->getCMSManager()->getCurrentCMS();
m_rasterizerPool = new pdf::PDFRasterizerPool(m_document, m_proxy->getFontCache(), m_proxy->getCMSManager(),
m_optionalContentActivity, m_proxy->getFeatures(), m_proxy->getMeshQualitySettings(),
pdf::PDFRasterizerPool::getDefaultRasterizerCount(), m_proxy->isUsingOpenGL(), m_proxy->getSurfaceFormat(), this);
pdf::PDFRasterizerPool::getDefaultRasterizerCount(), m_proxy->getRendererEngine(), this);
connect(m_rasterizerPool, &pdf::PDFRasterizerPool::renderError, this, &PDFRenderToImagesDialog::onRenderError);
auto process = [this]()

View File

@ -160,6 +160,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
m_actionManager->setAction(PDFActionManager::RenderOptionTextAntialiasing, ui->actionRenderOptionTextAntialiasing);
m_actionManager->setAction(PDFActionManager::RenderOptionSmoothPictures, ui->actionRenderOptionSmoothPictures);
m_actionManager->setAction(PDFActionManager::RenderOptionIgnoreOptionalContentSettings, ui->actionRenderOptionIgnoreOptionalContentSettings);
m_actionManager->setAction(PDFActionManager::RenderOptionDisplayRenderTimes, ui->actionRenderOptionDisplayRenderTimes);
m_actionManager->setAction(PDFActionManager::RenderOptionDisplayAnnotations, ui->actionRenderOptionDisplayAnnotations);
m_actionManager->setAction(PDFActionManager::RenderOptionInvertColors, ui->actionColorInvert);
m_actionManager->setAction(PDFActionManager::RenderOptionGrayscale, ui->actionColorGrayscale);
@ -543,7 +544,6 @@ void PDFViewerMainWindow::showEvent(QShowEvent* event)
{
QMainWindow::showEvent(event);
m_progressTaskbarIndicator->setWindow(windowHandle());
QTimer::singleShot(0, this, [this] { m_programController->checkHardwareOpenGLAvailability(); });
}
void PDFViewerMainWindow::dragEnterEvent(QDragEnterEvent* event)

View File

@ -90,6 +90,7 @@
<addaction name="actionRenderOptionSmoothPictures"/>
<addaction name="actionRenderOptionIgnoreOptionalContentSettings"/>
<addaction name="actionRenderOptionDisplayAnnotations"/>
<addaction name="actionRenderOptionDisplayRenderTimes"/>
</widget>
<addaction name="menuPage_Layout"/>
<addaction name="menuRendering_Options"/>
@ -1153,6 +1154,17 @@
<string>If checked, bookmarks for main document chapters are generated automatically.</string>
</property>
</action>
<action name="actionRenderOptionDisplayRenderTimes">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Display Render Times</string>
</property>
<property name="menuRole">
<enum>QAction::NoRole</enum>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -130,6 +130,7 @@ PDFViewerMainWindowLite::PDFViewerMainWindowLite(QWidget* parent) :
m_actionManager->setAction(PDFActionManager::RenderOptionTextAntialiasing, ui->actionRenderOptionTextAntialiasing);
m_actionManager->setAction(PDFActionManager::RenderOptionSmoothPictures, ui->actionRenderOptionSmoothPictures);
m_actionManager->setAction(PDFActionManager::RenderOptionIgnoreOptionalContentSettings, ui->actionRenderOptionIgnoreOptionalContentSettings);
m_actionManager->setAction(PDFActionManager::RenderOptionDisplayRenderTimes, ui->actionRenderOptionDisplayRenderTimes);
m_actionManager->setAction(PDFActionManager::RenderOptionDisplayAnnotations, ui->actionRenderOptionDisplayAnnotations);
m_actionManager->setAction(PDFActionManager::RenderOptionInvertColors, ui->actionColorInvert);
m_actionManager->setAction(PDFActionManager::RenderOptionGrayscale, ui->actionColorGrayscale);
@ -432,7 +433,6 @@ void PDFViewerMainWindowLite::showEvent(QShowEvent* event)
{
QMainWindow::showEvent(event);
m_progressTaskbarIndicator->setWindow(windowHandle());
QTimer::singleShot(0, this, [this] { m_programController->checkHardwareOpenGLAvailability(); });
}
void PDFViewerMainWindowLite::dragEnterEvent(QDragEnterEvent* event)

View File

@ -42,7 +42,7 @@
<property name="title">
<string>Go To</string>
</property>
<widget class="QMenu" name="menuBookmarkSettings">
<widget class="QMenu" name="menuBookmarkSettings">
<property name="title">
<string>Bookmark Settings</string>
</property>
@ -56,7 +56,6 @@
<addaction name="actionGoToNextPage"/>
<addaction name="actionGoToPreviousLine"/>
<addaction name="actionGoToNextLine"/>
<addaction name="separator"/>
<addaction name="actionBookmarkPage"/>
<addaction name="actionGotoPreviousBookmark"/>
@ -87,6 +86,7 @@
<addaction name="actionRenderOptionSmoothPictures"/>
<addaction name="actionRenderOptionIgnoreOptionalContentSettings"/>
<addaction name="actionRenderOptionDisplayAnnotations"/>
<addaction name="actionRenderOptionDisplayRenderTimes"/>
</widget>
<addaction name="menuPage_Layout"/>
<addaction name="menuRendering_Options"/>
@ -368,65 +368,65 @@
</property>
</action>
<action name="actionColorInvert">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | Inverted</string>
</property>
</action>
<action name="actionColorGrayscale">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | Grayscale</string>
</property>
</action>
<action name="actionColorHighContrast">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | High Contrast</string>
</property>
</action>
<action name="actionColorBitonal">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | Monochromatic</string>
</property>
</action>
<action name="actionColorCustom">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | Custom</string>
</property>
</action>
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | Inverted</string>
</property>
</action>
<action name="actionColorGrayscale">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | Grayscale</string>
</property>
</action>
<action name="actionColorHighContrast">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | High Contrast</string>
</property>
</action>
<action name="actionColorBitonal">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | Monochromatic</string>
</property>
</action>
<action name="actionColorCustom">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/invert-colors.svg</normaloff>:/resources/invert-colors.svg</iconset>
</property>
<property name="text">
<string>Color | Custom</string>
</property>
</action>
<action name="actionRotateRight">
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
@ -557,7 +557,6 @@
<string>Become a Sponsor</string>
</property>
</action>
<action name="actionBookmarkPage">
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
@ -651,6 +650,17 @@
<string>If checked, bookmarks for main document chapters are generated automatically.</string>
</property>
</action>
<action name="actionRenderOptionDisplayRenderTimes">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Display Render Times</string>
</property>
<property name="menuRole">
<enum>QAction::NoRole</enum>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -43,9 +43,7 @@ void PDFViewerSettings::readSettings(QSettings& settings, const pdf::PDFCMSSetti
settings.beginGroup("ViewerSettings");
m_settings.m_directory = settings.value("defaultDirectory", QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).toString();
m_settings.m_features = static_cast<pdf::PDFRenderer::Features>(settings.value("rendererFeaturesv2", static_cast<int>(pdf::PDFRenderer::getDefaultFeatures())).toInt());
m_settings.m_rendererEngine = static_cast<pdf::RendererEngine>(settings.value("renderingEngine", static_cast<int>(pdf::RendererEngine::OpenGL)).toInt());
m_settings.m_multisampleAntialiasing = settings.value("msaa", defaultSettings.m_multisampleAntialiasing).toBool();
m_settings.m_rendererSamples = settings.value("rendererSamples", defaultSettings.m_rendererSamples).toInt();
m_settings.m_rendererEngine = static_cast<pdf::RendererEngine>(settings.value("renderingEngine", static_cast<int>(pdf::RendererEngine::Blend2D_MultiThread)).toInt());
m_settings.m_prefetchPages = settings.value("prefetchPages", defaultSettings.m_prefetchPages).toBool();
m_settings.m_preferredMeshResolutionRatio = settings.value("preferredMeshResolutionRatio", defaultSettings.m_preferredMeshResolutionRatio).toDouble();
m_settings.m_minimalMeshResolutionRatio = settings.value("minimalMeshResolutionRatio", defaultSettings.m_minimalMeshResolutionRatio).toDouble();
@ -119,8 +117,6 @@ void PDFViewerSettings::writeSettings(QSettings& settings)
settings.setValue("defaultDirectory", m_settings.m_directory);
settings.setValue("rendererFeaturesv2", static_cast<int>(m_settings.m_features));
settings.setValue("renderingEngine", static_cast<int>(m_settings.m_rendererEngine));
settings.setValue("msaa", m_settings.m_multisampleAntialiasing);
settings.setValue("rendererSamples", m_settings.m_rendererSamples);
settings.setValue("prefetchPages", m_settings.m_prefetchPages);
settings.setValue("preferredMeshResolutionRatio", m_settings.m_preferredMeshResolutionRatio);
settings.setValue("minimalMeshResolutionRatio", m_settings.m_minimalMeshResolutionRatio);
@ -228,20 +224,6 @@ void PDFViewerSettings::setRendererEngine(pdf::RendererEngine rendererEngine)
}
}
int PDFViewerSettings::getRendererSamples() const
{
return m_settings.m_rendererSamples;
}
void PDFViewerSettings::setRendererSamples(int rendererSamples)
{
if (m_settings.m_rendererSamples != rendererSamples)
{
m_settings.m_rendererSamples = rendererSamples;
Q_EMIT settingsChanged();
}
}
void PDFViewerSettings::setPreferredMeshResolutionRatio(pdf::PDFReal preferredMeshResolutionRatio)
{
if (m_settings.m_preferredMeshResolutionRatio != preferredMeshResolutionRatio)
@ -271,9 +253,7 @@ void PDFViewerSettings::setColorTolerance(pdf::PDFReal colorTolerance)
PDFViewerSettings::Settings::Settings() :
m_features(pdf::PDFRenderer::getDefaultFeatures()),
m_rendererEngine(pdf::RendererEngine::OpenGL),
m_multisampleAntialiasing(true),
m_rendererSamples(16),
m_rendererEngine(pdf::RendererEngine::Blend2D_MultiThread),
m_prefetchPages(true),
m_preferredMeshResolutionRatio(0.02),
m_minimalMeshResolutionRatio(0.005),

View File

@ -52,8 +52,6 @@ public:
pdf::PDFRenderer::Features m_features;
QString m_directory;
pdf::RendererEngine m_rendererEngine;
bool m_multisampleAntialiasing;
int m_rendererSamples;
bool m_prefetchPages;
pdf::PDFReal m_preferredMeshResolutionRatio;
pdf::PDFReal m_minimalMeshResolutionRatio;
@ -113,11 +111,7 @@ public:
pdf::RendererEngine getRendererEngine() const;
void setRendererEngine(pdf::RendererEngine rendererEngine);
int getRendererSamples() const;
void setRendererSamples(int rendererSamples);
bool isPagePrefetchingEnabled() const { return m_settings.m_prefetchPages; }
bool isMultisampleAntialiasingEnabled() const { return m_settings.m_multisampleAntialiasing; }
pdf::PDFReal getPreferredMeshResolutionRatio() const { return m_settings.m_preferredMeshResolutionRatio; }
void setPreferredMeshResolutionRatio(pdf::PDFReal preferredMeshResolutionRatio);

View File

@ -102,13 +102,9 @@ PDFViewerSettingsDialog::PDFViewerSettingsDialog(const PDFViewerSettings::Settin
font.setPointSize(font.pointSize() * 1.5);
ui->optionsPagesWidget->setFont(font);
ui->renderingEngineComboBox->addItem(tr("Software"), static_cast<int>(pdf::RendererEngine::Software));
ui->renderingEngineComboBox->addItem(tr("Hardware accelerated (OpenGL)"), static_cast<int>(pdf::RendererEngine::OpenGL));
for (int i : { 1, 2, 4, 8, 16 })
{
ui->multisampleAntialiasingSamplesCountComboBox->addItem(QString::number(i), i);
}
ui->renderingEngineComboBox->addItem(tr("Software | QPainter"), static_cast<int>(pdf::RendererEngine::QPainter));
ui->renderingEngineComboBox->addItem(tr("Software | Blend2D | Parallel"), static_cast<int>(pdf::RendererEngine::Blend2D_MultiThread));
ui->renderingEngineComboBox->addItem(tr("Software | Blend2D | Sequential"), static_cast<int>(pdf::RendererEngine::Blend2D_SingleThread));
ui->multithreadingComboBox->addItem(tr("Single thread"), static_cast<int>(pdf::PDFExecutionPolicy::Strategy::SingleThreaded));
ui->multithreadingComboBox->addItem(tr("Multithreading (load balanced)"), static_cast<int>(pdf::PDFExecutionPolicy::Strategy::PageMultithreaded));
@ -279,29 +275,6 @@ void PDFViewerSettingsDialog::loadData()
ui->renderingEngineComboBox->setCurrentIndex(ui->renderingEngineComboBox->findData(static_cast<int>(m_settings.m_rendererEngine)));
// Engine
if (m_settings.m_rendererEngine == pdf::RendererEngine::OpenGL)
{
ui->multisampleAntialiasingCheckBox->setEnabled(true);
ui->multisampleAntialiasingCheckBox->setChecked(m_settings.m_multisampleAntialiasing);
if (m_settings.m_multisampleAntialiasing)
{
ui->multisampleAntialiasingSamplesCountComboBox->setEnabled(true);
ui->multisampleAntialiasingSamplesCountComboBox->setCurrentIndex(ui->multisampleAntialiasingSamplesCountComboBox->findData(m_settings.m_rendererSamples));
}
else
{
ui->multisampleAntialiasingSamplesCountComboBox->setEnabled(false);
ui->multisampleAntialiasingSamplesCountComboBox->setCurrentIndex(-1);
}
}
else
{
ui->multisampleAntialiasingCheckBox->setEnabled(false);
ui->multisampleAntialiasingCheckBox->setChecked(false);
ui->multisampleAntialiasingSamplesCountComboBox->setEnabled(false);
ui->multisampleAntialiasingSamplesCountComboBox->setCurrentIndex(-1);
}
ui->prefetchPagesCheckBox->setChecked(m_settings.m_prefetchPages);
ui->multithreadingComboBox->setCurrentIndex(ui->multithreadingComboBox->findData(static_cast<int>(m_settings.m_multithreadingStrategy)));
@ -432,14 +405,6 @@ void PDFViewerSettingsDialog::saveData()
{
m_settings.m_rendererEngine = static_cast<pdf::RendererEngine>(ui->renderingEngineComboBox->currentData().toInt());
}
else if (sender == ui->multisampleAntialiasingCheckBox)
{
m_settings.m_multisampleAntialiasing = ui->multisampleAntialiasingCheckBox->isChecked();
}
else if (sender == ui->multisampleAntialiasingSamplesCountComboBox)
{
m_settings.m_rendererSamples = ui->multisampleAntialiasingSamplesCountComboBox->currentData().toInt();
}
else if (sender == ui->prefetchPagesCheckBox)
{
m_settings.m_prefetchPages = ui->prefetchPagesCheckBox->isChecked();

View File

@ -35,7 +35,7 @@
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>6</number>
<number>0</number>
</property>
<widget class="QWidget" name="enginePage">
<layout class="QVBoxLayout" name="enginePageLayout">
@ -59,47 +59,16 @@
<layout class="QVBoxLayout" name="engineSettingsGroupBoxLayout">
<item>
<layout class="QGridLayout" name="engineSettingsGridLayout">
<item row="1" column="1">
<widget class="QCheckBox" name="multisampleAntialiasingCheckBox">
<item row="2" column="0">
<widget class="QLabel" name="multithreadingLabel">
<property name="text">
<string>Enable</string>
<string>Multithreading strategy</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="renderingEngineComboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="multisampleAntialiasingLabel">
<property name="text">
<string>Multisample antialiasing (MSAA)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="multisampleAntialiasingSamplesCountComboBox"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="prefetchPagesLabel">
<property name="text">
<string>Prefetch pages</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="multisampleAntiailasingSamplesLabel">
<property name="text">
<string>MSAA Samples count</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="prefetchPagesCheckBox">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="renderingEngineLabel">
<property name="text">
@ -107,22 +76,29 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="multithreadingLabel">
<item row="1" column="0">
<widget class="QLabel" name="prefetchPagesLabel">
<property name="text">
<string>Multithreading strategy</string>
<string>Prefetch pages</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="2" column="1">
<widget class="QComboBox" name="multithreadingComboBox"/>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="prefetchPagesCheckBox">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="engineInfoLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Choose a rendering method based on your needs. Although &lt;span style=&quot; font-weight:600;&quot;&gt;Software Rendering&lt;/span&gt; is slower than the hardware-accelerated &lt;span style=&quot; font-weight:600;&quot;&gt;OpenGL Rendering&lt;/span&gt;, it can be utilized when OpenGL is not available on your platform. The default (and recommended) method is OpenGL Rendering. &lt;/p&gt;&lt;p&gt;OpenGL rendering employs &lt;span style=&quot; font-weight:600;&quot;&gt;Multisample Antialiasing (MSAA)&lt;/span&gt;, ensuring high-quality image rendering. You have the option to enable or disable this feature. However, disabling it might lead to inferior image quality. The Samples Count sets the number of samples per pixel used to determine pixel color. It can be set to 1, 2, 4, 8, or 16. Most modern GPUs support at least a value of 8. If your GPU doesn't support the desired sample count, lower this value. &lt;/p&gt;&lt;p&gt;The &lt;span style=&quot; font-weight:600;&quot;&gt;Prefetch Pages&lt;/span&gt; feature pre-renders pages adjacent to the currently viewed pages, minimizing flickering during scrolling. Prefetched pages are stored in the page cache. &lt;/p&gt;&lt;p&gt;The &lt;span style=&quot; font-weight:600;&quot;&gt;Multithreading Strategy&lt;/span&gt; determines how the program will utilize CPU cores. With the &lt;span style=&quot; font-weight:600;&quot;&gt;Single Thread&lt;/span&gt; strategy, only one CPU core is used for rendering a page. This results in longer processing times, but each page is independently compiled/drawn in its own thread. Alternatively, there are two multithreading strategies: Load Balanced and Maximum Threads. Load Balanced only parallelizes pages without processing individual page content. In contrast, the Maximum Threads strategy spawns as many threads as possible for operations to achieve optimal performance. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select a rendering method tailored to your application's requirements. Software Rendering, utilizing QPainter, is a versatile choice that guarantees compatibility across all platforms. It's particularly useful in scenarios where direct access to hardware acceleration isn't crucial. QPainter, part of the Qt framework, excels in rendering 2D graphics with support for various painting styles, image processing, and intricate graphical transformations, making it an excellent tool for applications that require detailed and sophisticated 2D graphics without relying on hardware acceleration.&lt;/p&gt;&lt;p&gt;On the other hand, for applications that demand high-performance rendering, leveraging the Blend2D library offers a compelling alternative. Blend2D is a high-performance 2D vector graphics engine that utilizes multi-threading to accelerate the rendering process. It does not rely on QPainter or hardware acceleration but instead offers a software-based rendering solution optimized for speed and quality. Blend2D's advanced anti-aliasing techniques ensure crisp and clear image quality, making it suitable for applications where rendering performance and image quality are paramount.&lt;/p&gt;&lt;p&gt;The Prefetch Pages feature is a strategy that can be applied regardless of the rendering method chosen. By pre-rendering pages adjacent to the currently viewed content, this approach minimizes flickering and enhances the smoothness of transitions during scrolling, improving the overall user experience.&lt;/p&gt;&lt;p&gt;When it comes to optimizing the rendering process, the choice of multithreading strategy plays a crucial role. A Single Thread strategy, where rendering tasks are executed sequentially on a single CPU core, might be preferable in environments where simplicity and predictability are key. For more demanding applications, employing a Multi-threading strategy can significantly improve rendering times. Strategies like Load Balanced distribute the workload evenly across CPU cores without delving into content-specific processing, offering a good performance boost. The Maximum Threads strategy takes full advantage of available CPU resources by allocating as many threads as possible to the rendering tasks, achieving optimal performance and minimizing rendering times.&lt;/p&gt;&lt;p&gt;This delineation between using QPainter for software rendering and Blend2D for high-performance, multi-threaded rendering allows developers to choose the most appropriate rendering pathway based on their specific performance requirements and the graphical complexity of their application.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>

View File

@ -24,7 +24,6 @@
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true);
QApplication application(argc, argv);
QCoreApplication::setOrganizationName("MelkaJ");

View File

@ -23,10 +23,6 @@ add_library(AudioBookPlugin SHARED
icons.qrc
)
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(AudioBookPlugin PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(AudioBookPlugin PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
if(MINGW)

View File

@ -23,10 +23,6 @@ add_library(DimensionsPlugin SHARED
icons.qrc
)
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(DimensionsPlugin PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(DimensionsPlugin PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(DimensionsPlugin PROPERTIES

View File

@ -29,10 +29,6 @@ add_library(ObjectInspectorPlugin SHARED
icons.qrc
)
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(ObjectInspectorPlugin PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(ObjectInspectorPlugin PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(ObjectInspectorPlugin PROPERTIES

View File

@ -25,10 +25,6 @@ add_library(OutputPreviewPlugin SHARED
icons.qrc
)
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(OutputPreviewPlugin PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(OutputPreviewPlugin PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(OutputPreviewPlugin PROPERTIES

View File

@ -22,10 +22,6 @@ add_library(RedactPlugin SHARED
icons.qrc
)
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(RedactPlugin PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(RedactPlugin PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(RedactPlugin PROPERTIES

View File

@ -22,10 +22,6 @@ add_library(SignaturePlugin SHARED
icons.qrc
)
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(SignaturePlugin PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(SignaturePlugin PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
target_link_libraries(SignaturePlugin PRIVATE OpenSSL::SSL OpenSSL::Crypto)

View File

@ -22,10 +22,6 @@ add_library(SoftProofingPlugin SHARED
icons.qrc
)
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(SoftProofingPlugin PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(SoftProofingPlugin PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(SoftProofingPlugin PROPERTIES

View File

@ -30,7 +30,6 @@ int main(int argc, char *argv[])
#endif
QApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true);
QApplication application(argc, argv);
QCoreApplication::setOrganizationName("MelkaJ");

View File

@ -24,7 +24,6 @@
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
QGuiApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity, true);
QCoreApplication::setOrganizationName("MelkaJ");
QCoreApplication::setApplicationName("PdfTool");
QCoreApplication::setApplicationVersion(pdf::PDF_LIBRARY_VERSION);

View File

@ -847,12 +847,12 @@ PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser
}
}
QString textValue = parser->value("render-hw-accel");
QString textValue = parser->value("render-software");
bool ok = false;
bool value = textValue.toInt(&ok);
if (ok)
{
options.renderUseHardwareRendering = value;
options.renderUseSoftwareRendering = value;
}
else
{

View File

@ -135,7 +135,7 @@ struct PDFToolOptions
// For option 'RenderFlags'
pdf::PDFRenderer::Features renderFeatures = pdf::PDFRenderer::getDefaultFeatures();
bool renderUseHardwareRendering = true;
bool renderUseSoftwareRendering = true;
bool renderShowPageStatistics = false;
int renderMSAAsamples = 4;
int renderRasterizerCount = pdf::PDFRasterizerPool::getDefaultRasterizerCount();

View File

@ -180,21 +180,11 @@ int PDFToolRenderBase::execute(const PDFToolOptions& options)
fontCache.setDocument(md);
fontCache.setCacheShrinkEnabled(nullptr, false);
QSurfaceFormat surfaceFormat;
if (options.renderUseHardwareRendering)
{
surfaceFormat = QSurfaceFormat::defaultFormat();
surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
surfaceFormat.setSamples(options.renderMSAAsamples);
surfaceFormat.setColorSpace(QColorSpace(QColorSpace::SRgb));
surfaceFormat.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
}
m_pageInfo.resize(document.getCatalog()->getPageCount());
pdf::PDFRasterizerPool rasterizerPool(&document, &fontCache, &cmsManager,
&optionalContentActivity, options.renderFeatures, meshQualitySettings,
pdf::PDFRasterizerPool::getCorrectedRasterizerCount(options.renderRasterizerCount),
options.renderUseHardwareRendering, surfaceFormat, nullptr);
options.renderUseSoftwareRendering ? pdf::RendererEngine::QPainter : pdf::RendererEngine::Blend2D_SingleThread, nullptr);
auto onRenderError = [this](pdf::PDFInteger pageIndex, pdf::PDFRenderError error)
{

View File

@ -1,5 +1,5 @@
{
"name": "pdf4qt",
"version-string": "1.3.6",
"dependencies": [ "tbb", "openssl", "lcms", "zlib", "openjpeg", "freetype", "ijg-libjpeg", "libpng" ]
"version-string": "1.3.7",
"dependencies": [ "tbb", "openssl", "lcms", "zlib", "openjpeg", "freetype", "ijg-libjpeg", "libpng", "blend2d" ]
}