diff --git a/CMakeLists.txt b/CMakeLists.txt index f806ba1..980b4b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/Pdf4QtDocDiff/CMakeLists.txt b/Pdf4QtDocDiff/CMakeLists.txt index 7a14906..90792a6 100644 --- a/Pdf4QtDocDiff/CMakeLists.txt +++ b/Pdf4QtDocDiff/CMakeLists.txt @@ -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 diff --git a/Pdf4QtDocDiff/main.cpp b/Pdf4QtDocDiff/main.cpp index 1726712..c34f817 100644 --- a/Pdf4QtDocDiff/main.cpp +++ b/Pdf4QtDocDiff/main.cpp @@ -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"); diff --git a/Pdf4QtDocPageOrganizer/main.cpp b/Pdf4QtDocPageOrganizer/main.cpp index 9992c16..e670171 100644 --- a/Pdf4QtDocPageOrganizer/main.cpp +++ b/Pdf4QtDocPageOrganizer/main.cpp @@ -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"); diff --git a/Pdf4QtDocPageOrganizer/pageitemdelegate.cpp b/Pdf4QtDocPageOrganizer/pageitemdelegate.cpp index c74d813..5ea0afa 100644 --- a/Pdf4QtDocPageOrganizer/pageitemdelegate.cpp +++ b/Pdf4QtDocPageOrganizer/pageitemdelegate.cpp @@ -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); } PageItemDelegate::~PageItemDelegate() diff --git a/Pdf4QtLibCore/CMakeLists.txt b/Pdf4QtLibCore/CMakeLists.txt index e060d8d..cc1bd92 100644 --- a/Pdf4QtLibCore/CMakeLists.txt +++ b/Pdf4QtLibCore/CMakeLists.txt @@ -163,10 +163,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 +174,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} diff --git a/Pdf4QtLibCore/sources/pdfannotation.cpp b/Pdf4QtLibCore/sources/pdfannotation.cpp index 8034779..d213c3e 100644 --- a/Pdf4QtLibCore/sources/pdfannotation.cpp +++ b/Pdf4QtLibCore/sources/pdfannotation.cpp @@ -1482,6 +1482,17 @@ void PDFAnnotationManager::drawPage(QPainter* painter, } } +void PDFAnnotationManager::drawPage(BLContext& context, PDFInteger pageIndex, const PDFPrecompiledPage* compiledPage, PDFTextLayoutGetter& layoutGetter, const QTransform& pagePointToDevicePointMatrix, QList& errors) const +{ + // TODO: Implement it + Q_UNUSED(context); + Q_UNUSED(pageIndex); + Q_UNUSED(compiledPage); + Q_UNUSED(layoutGetter); + Q_UNUSED(pagePointToDevicePointMatrix); + Q_UNUSED(errors); +} + void PDFAnnotationManager::drawAnnotation(const PageAnnotation& annotation, const QTransform& pagePointToDevicePointMatrix, const PDFPage* page, diff --git a/Pdf4QtLibCore/sources/pdfannotation.h b/Pdf4QtLibCore/sources/pdfannotation.h index 8e58568..1955d97 100644 --- a/Pdf4QtLibCore/sources/pdfannotation.h +++ b/Pdf4QtLibCore/sources/pdfannotation.h @@ -40,6 +40,8 @@ class QKeyEvent; class QMouseEvent; class QWheelEvent; +class BLContext; + namespace pdf { class PDFWidget; @@ -1466,6 +1468,13 @@ public: const QTransform& pagePointToDevicePointMatrix, QList& errors) const; + virtual void drawPage(BLContext& context, + PDFInteger pageIndex, + const PDFPrecompiledPage* compiledPage, + PDFTextLayoutGetter& layoutGetter, + const QTransform& pagePointToDevicePointMatrix, + QList& errors) const; + /// Set document /// \param document New document virtual void setDocument(const PDFModifiedDocument& document); diff --git a/Pdf4QtLibCore/sources/pdfglobal.h b/Pdf4QtLibCore/sources/pdfglobal.h index 6bf0a1d..9c36cdd 100644 --- a/Pdf4QtLibCore/sources/pdfglobal.h +++ b/Pdf4QtLibCore/sources/pdfglobal.h @@ -187,8 +187,8 @@ private: enum class RendererEngine { - Software, - OpenGL + Blend2D, + QPainter, }; enum class RenderingIntent diff --git a/Pdf4QtLibCore/sources/pdfpainter.cpp b/Pdf4QtLibCore/sources/pdfpainter.cpp index 0ab432f..314722f 100644 --- a/Pdf4QtLibCore/sources/pdfpainter.cpp +++ b/Pdf4QtLibCore/sources/pdfpainter.cpp @@ -18,11 +18,14 @@ #include "pdfpainter.h" #include "pdfpattern.h" #include "pdfcms.h" +#include "pdfpainterutils.h" #include #include #include +#include + #include "pdfdbgheap.h" namespace pdf @@ -620,6 +623,135 @@ void PDFPrecompiledPage::draw(QPainter* painter, painter->restore(); } +void PDFPrecompiledPage::draw(BLContext& painter, + const QRectF& cropBox, + const QTransform& pagePointToDevicePointMatrix, + PDFRenderer::Features features, + PDFReal opacity) const +{ + Q_ASSERT(painter); + Q_ASSERT(pagePointToDevicePointMatrix.isInvertible()); + + painter.save(); + painter.setMatrix(BLMatrix2D()); + painter.setGlobalAlpha(opacity); + + if (features.testFlag(PDFRenderer::ClipToCropBox) && cropBox.isValid()) + { + QRectF mappedCropBox = pagePointToDevicePointMatrix.mapRect(cropBox); + BLRect clipRect = PDFPainterHelper::getBLRect(mappedCropBox); + painter.clipToRect(clipRect); + } + + // Process all instructions + for (const Instruction& instruction : m_instructions) + { + switch (instruction.type) + { + case InstructionType::DrawPath: + { + const PathPaintData& data = m_paths[instruction.dataIndex]; + BLPath path = PDFPainterHelper::getBLPath(data.path); + + PDFPainterHelper::setBLPen(painter, data.pen); + PDFPainterHelper::setBLBrush(painter, data.brush); + + if (data.brush.style() != Qt::NoBrush) + { + painter.fillPath(path); + } + + if (data.pen.style() != Qt::NoPen) + { + painter.strokePath(path); + } + break; + } + + case InstructionType::DrawImage: + { + const ImageData& data = m_images[instruction.dataIndex]; + QImage image = data.image; + + if (image.format() != QImage::Format_ARGB32_Premultiplied) + { + image.convertTo(QImage::Format_ARGB32_Premultiplied); + } + + painter.save(); + + BLImage blImage; + blImage.createFromData(image.width(), image.height(), BL_FORMAT_PRGB32, image.bits(), image.bytesPerLine()); + + BLMatrix2D imageTransform(1.0 / image.width(), 0, 0, 1.0 / image.height(), 0, 0); + BLMatrix2D worldTransform = imageTransform; + worldTransform.postTransform(painter.userMatrix()); + + // Jakub Melka: Because Qt uses opposite axis direction than PDF, then we must transform the y-axis + // to the opposite (so the image is then unchanged) + worldTransform.translate(0, image.height()); + worldTransform.scale(1, -1); + + painter.setMatrix(worldTransform); + painter.blitImage(BLPointI(0, 0), blImage); + painter.restore(); + break; + } + + case InstructionType::DrawMesh: + { + const MeshPaintData& data = m_meshes[instruction.dataIndex]; + + painter.save(); + painter.setMatrix(PDFPainterHelper::getBLMatrix(pagePointToDevicePointMatrix)); + data.mesh.paint(painter, data.alpha); + painter.restore(); + break; + } + + case InstructionType::Clip: + { + // Blend2D does not have path clipping + break; + } + + case InstructionType::SaveGraphicState: + { + painter.save(); + break; + } + + case InstructionType::RestoreGraphicState: + { + painter.restore(); + break; + } + + case InstructionType::SetWorldMatrix: + { + QTransform transform(m_matrices[instruction.dataIndex] * pagePointToDevicePointMatrix); + BLMatrix2D matrix = PDFPainterHelper::getBLMatrix(transform); + painter.setMatrix(matrix); + break; + } + + case InstructionType::SetCompositionMode: + { + painter.setCompOp(PDFPainterHelper::getBLCompOp(m_compositionModes[instruction.dataIndex])); + break; + } + + default: + { + Q_ASSERT(false); + break; + } + } + } + + painter.restore(); +} + void PDFPrecompiledPage::redact(QPainterPath redactPath, const QTransform& matrix, QColor color) { if (redactPath.isEmpty()) diff --git a/Pdf4QtLibCore/sources/pdfpainter.h b/Pdf4QtLibCore/sources/pdfpainter.h index 0ca55ef..c4d0fea 100644 --- a/Pdf4QtLibCore/sources/pdfpainter.h +++ b/Pdf4QtLibCore/sources/pdfpainter.h @@ -30,6 +30,8 @@ #include #include +class BLContext; + namespace pdf { @@ -196,6 +198,18 @@ public: PDFRenderer::Features features, PDFReal opacity) const; + /// Paints page onto the blend2d painter using matrix + /// \param painter Painter, onto which is page drawn + /// \param cropBox Page's crop box + /// \param pagePointToDevicePointMatrix Page point to device point transformation matrix + /// \param features Renderer features + /// \param opacity Opacity of page graphics + void draw(BLContext& painter, + const QRectF& cropBox, + const QTransform& pagePointToDevicePointMatrix, + PDFRenderer::Features features, + PDFReal opacity) const; + /// Redact path - remove all content intersecting given path, /// and fill redact path with given color. /// \param redactPath Redaction path in page coordinates diff --git a/Pdf4QtLibCore/sources/pdfpainterutils.cpp b/Pdf4QtLibCore/sources/pdfpainterutils.cpp index 6e07c28..3a36ae9 100644 --- a/Pdf4QtLibCore/sources/pdfpainterutils.cpp +++ b/Pdf4QtLibCore/sources/pdfpainterutils.cpp @@ -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 #include #include "pdfdbgheap.h" @@ -63,4 +64,277 @@ QRect PDFPainterHelper::drawBubble(QPainter* painter, QPoint point, QColor color return rectangle; } +BLMatrix2D PDFPainterHelper::getBLMatrix(QTransform transform) +{ + BLMatrix2D matrix; + matrix.reset(transform.m11(), transform.m12(), transform.m21(), transform.m22(), transform.dx(), transform.dy()); + return matrix; +} + +BLRect PDFPainterHelper::getBLRect(QRect rect) +{ + return BLRect(rect.x(), rect.y(), rect.width(), rect.height()); +} + +BLRect PDFPainterHelper::getBLRect(QRectF rect) +{ + return BLRect(rect.x(), rect.y(), rect.width(), rect.height()); +} + +BLPath PDFPainterHelper::getBLPath(const QPainterPath& path) +{ + BLPath blPath; + + int elementCount = path.elementCount(); + for (int i = 0; i < elementCount; ++i) { + const QPainterPath::Element& element = path.elementAt(i); + + switch (element.type) + { + case QPainterPath::MoveToElement: + blPath.moveTo(element.x, element.y); + break; + + case QPainterPath::LineToElement: + blPath.lineTo(element.x, element.y); + break; + + case QPainterPath::CurveToElement: + if (i + 2 < elementCount) + { + const QPainterPath::Element& ctrlPoint1 = path.elementAt(i++); + const QPainterPath::Element& ctrlPoint2 = path.elementAt(i++); + const QPainterPath::Element& endPoint = path.elementAt(i); + blPath.cubicTo(ctrlPoint1.x, ctrlPoint1.y, ctrlPoint2.x, ctrlPoint2.y, endPoint.x, endPoint.y); + } + break; + + case QPainterPath::CurveToDataElement: + Q_ASSERT(false); + break; + } + } + + return blPath; +} + +void PDFPainterHelper::setBLPen(BLContext& context, const QPen& pen) +{ + const Qt::PenCapStyle capStyle = pen.capStyle(); + const Qt::PenJoinStyle joinStyle = pen.joinStyle(); + const QColor color = pen.color(); + const qreal width = pen.widthF(); + const qreal miterLimit = pen.miterLimit(); + const qreal dashOffset = pen.dashOffset(); + const QList customDashPattern = pen.dashPattern(); + const Qt::PenStyle penStyle = pen.style(); + + context.setStrokeAlpha(pen.color().alphaF()); + context.setStrokeWidth(width); + context.setStrokeMiterLimit(miterLimit); + + switch (capStyle) + { + case Qt::FlatCap: + context.setStrokeCaps(BL_STROKE_CAP_BUTT); + break; + case Qt::SquareCap: + context.setStrokeCaps(BL_STROKE_CAP_SQUARE); + break; + case Qt::RoundCap: + context.setStrokeCaps(BL_STROKE_CAP_ROUND); + break; + } + + BLArray dashArray; + + for (double value : customDashPattern) + { + dashArray.append(value); + } + + context.setStrokeDashOffset(dashOffset); + context.setStrokeDashArray(dashArray); + + switch (joinStyle) + { + case Qt::MiterJoin: + context.setStrokeJoin(BL_STROKE_JOIN_MITER_CLIP); + break; + case Qt::BevelJoin: + context.setStrokeJoin(BL_STROKE_JOIN_BEVEL); + break; + case Qt::RoundJoin: + context.setStrokeJoin(BL_STROKE_JOIN_ROUND); + break; + case Qt::SvgMiterJoin: + context.setStrokeJoin(BL_STROKE_JOIN_MITER_CLIP); + break; + } + + context.setStrokeStyle(BLRgba32(color.rgba())); + + BLStrokeOptions strokeOptions = context.strokeOptions(); + + switch (penStyle) + { + case Qt::SolidLine: + strokeOptions.dashArray.clear(); + strokeOptions.dashOffset = 0.0; + break; + + case Qt::DashLine: + { + constexpr double dashPattern[] = {4, 4}; + strokeOptions.dashArray.assignData(dashPattern, std::size(dashPattern)); + break; + } + + case Qt::DotLine: + { + constexpr double dashPattern[] = {1, 3}; + strokeOptions.dashArray.assignData(dashPattern, std::size(dashPattern)); + break; + } + + case Qt::DashDotLine: + { + constexpr double dashPattern[] = {4, 2, 1, 2}; + strokeOptions.dashArray.assignData(dashPattern, std::size(dashPattern)); + break; + } + + case Qt::DashDotDotLine: + { + constexpr double dashPattern[] = {4, 2, 1, 2, 1, 2}; + strokeOptions.dashArray.assignData(dashPattern, std::size(dashPattern)); + break; + } + + default: + break; + } + + context.setStrokeOptions(strokeOptions); +} + +void PDFPainterHelper::setBLBrush(BLContext& context, const QBrush& brush) +{ + auto setGradientStops = [](BLGradient& blGradient, const auto& qGradient) + { + QVector stops; + for (const auto& stop : qGradient.stops()) + { + stops.append(BLGradientStop(stop.first, BLRgba32(stop.second.red(), stop.second.green(), stop.second.blue(), stop.second.alpha()))); + } + blGradient.assignStops(stops.constData(), stops.size()); + }; + + switch (brush.style()) + { + default: + case Qt::SolidPattern: + { + QColor color = brush.color(); + BLRgba32 blColor = BLRgba32(color.red(), color.green(), color.blue(), color.alpha()); + context.setFillStyle(blColor); + break; + } + case Qt::LinearGradientPattern: + { + const QGradient* gradient = brush.gradient(); + if (gradient && gradient->type() == QGradient::LinearGradient) + { + const QLinearGradient* linearGradient = static_cast(gradient); + BLLinearGradientValues blLinearGradient; + blLinearGradient.x0 = linearGradient->start().x(); + blLinearGradient.y0 = linearGradient->start().y(); + blLinearGradient.x1 = linearGradient->finalStop().x(); + blLinearGradient.y1 = linearGradient->finalStop().y(); + BLGradient blGradient(blLinearGradient); + setGradientStops(blGradient, *gradient); + context.setFillStyle(blGradient); + } + break; + } + case Qt::RadialGradientPattern: + { + const QGradient* gradient = brush.gradient(); + if (gradient && gradient->type() == QGradient::RadialGradient) + { + const QRadialGradient* radialGradient = static_cast(gradient); + BLRadialGradientValues blRadialGradientValues; + blRadialGradientValues.x0 = radialGradient->center().x(); + blRadialGradientValues.y0 = radialGradient->center().y(); + blRadialGradientValues.x1 = radialGradient->focalPoint().x(); + blRadialGradientValues.y1 = radialGradient->focalPoint().y(); + blRadialGradientValues.r0 = radialGradient->radius(); + BLGradient blGradient(blRadialGradientValues); + setGradientStops(blGradient, *gradient); + context.setFillStyle(blGradient); + } + break; + } + } +} + +BLCompOp PDFPainterHelper::getBLCompOp(QPainter::CompositionMode mode) +{ + switch (mode) + { + case QPainter::CompositionMode_SourceOver: + return BL_COMP_OP_SRC_OVER; + case QPainter::CompositionMode_DestinationOver: + return BL_COMP_OP_DST_OVER; + case QPainter::CompositionMode_Clear: + return BL_COMP_OP_CLEAR; + case QPainter::CompositionMode_Source: + return BL_COMP_OP_SRC_COPY; + case QPainter::CompositionMode_Destination: + return BL_COMP_OP_DST_COPY; + case QPainter::CompositionMode_SourceIn: + return BL_COMP_OP_SRC_IN; + case QPainter::CompositionMode_DestinationIn: + return BL_COMP_OP_DST_IN; + case QPainter::CompositionMode_SourceOut: + return BL_COMP_OP_SRC_OUT; + case QPainter::CompositionMode_DestinationOut: + return BL_COMP_OP_DST_OUT; + case QPainter::CompositionMode_SourceAtop: + return BL_COMP_OP_SRC_ATOP; + case QPainter::CompositionMode_DestinationAtop: + return BL_COMP_OP_DST_ATOP; + case QPainter::CompositionMode_Xor: + return BL_COMP_OP_XOR; + case QPainter::CompositionMode_Plus: + return BL_COMP_OP_PLUS; + case QPainter::CompositionMode_Multiply: + return BL_COMP_OP_MULTIPLY; + case QPainter::CompositionMode_Screen: + return BL_COMP_OP_SCREEN; + case QPainter::CompositionMode_Overlay: + return BL_COMP_OP_OVERLAY; + case QPainter::CompositionMode_Darken: + return BL_COMP_OP_DARKEN; + case QPainter::CompositionMode_Lighten: + return BL_COMP_OP_LIGHTEN; + case QPainter::CompositionMode_ColorDodge: + return BL_COMP_OP_COLOR_DODGE; + case QPainter::CompositionMode_ColorBurn: + return BL_COMP_OP_COLOR_BURN; + case QPainter::CompositionMode_HardLight: + return BL_COMP_OP_HARD_LIGHT; + case QPainter::CompositionMode_SoftLight: + return BL_COMP_OP_SOFT_LIGHT; + case QPainter::CompositionMode_Difference: + return BL_COMP_OP_DIFFERENCE; + case QPainter::CompositionMode_Exclusion: + return BL_COMP_OP_EXCLUSION; + default: + break; + } + + return BL_COMP_OP_SRC_OVER; +} + } // namespace pdf diff --git a/Pdf4QtLibCore/sources/pdfpainterutils.h b/Pdf4QtLibCore/sources/pdfpainterutils.h index ecef6e1..ba98566 100644 --- a/Pdf4QtLibCore/sources/pdfpainterutils.h +++ b/Pdf4QtLibCore/sources/pdfpainterutils.h @@ -22,6 +22,8 @@ #include +#include + namespace pdf { @@ -55,6 +57,27 @@ public: /// \param text Text inside the bubble /// \param alignment Bubble alignment relative to the bubble position point static QRect drawBubble(QPainter* painter, QPoint point, QColor color, QString text, Qt::Alignment alignment); + + /// Get BL matrix from transformation + static BLMatrix2D getBLMatrix(QTransform transform); + + /// Get BL rect from regular rect + static BLRect getBLRect(QRect rect); + + /// Get BL rect from regular rect + static BLRect getBLRect(QRectF rect); + + /// Get BL path from path + static BLPath getBLPath(const QPainterPath& path); + + /// Set pen to the context + static void setBLPen(BLContext& context, const QPen& pen); + + /// Set brush to the context + static void setBLBrush(BLContext& context, const QBrush& brush); + + /// Returns composition operator + static BLCompOp getBLCompOp(QPainter::CompositionMode mode); }; } // namespace pdf diff --git a/Pdf4QtLibCore/sources/pdfpattern.cpp b/Pdf4QtLibCore/sources/pdfpattern.cpp index fdd8dd2..96f655c 100644 --- a/Pdf4QtLibCore/sources/pdfpattern.cpp +++ b/Pdf4QtLibCore/sources/pdfpattern.cpp @@ -22,10 +22,13 @@ #include "pdfcolorspaces.h" #include "pdfexecutionpolicy.h" #include "pdfconstants.h" +#include "pdfpainterutils.h" #include #include +#include + #include "pdfdbgheap.h" #include @@ -1359,6 +1362,45 @@ void PDFMesh::paint(QPainter* painter, PDFReal alpha) const painter->restore(); } +void PDFMesh::paint(BLContext& context, PDFReal alpha) const +{ + if (m_triangles.empty()) + { + return; + } + + context.save(); + PDFPainterHelper::setBLPen(context, Qt::NoPen); + + if (!m_backgroundPath.isEmpty() && m_backgroundColor.isValid()) + { + QColor backgroundColor = m_backgroundColor; + backgroundColor.setAlphaF(alpha); + PDFPainterHelper::setBLBrush(context, QBrush(backgroundColor, Qt::SolidPattern)); + context.fillPath(PDFPainterHelper::getBLPath(m_backgroundPath)); + } + + QColor color; + + // Draw all triangles + for (const Triangle& triangle : m_triangles) + { + if (color != triangle.color) + { + QColor newColor(triangle.color); + newColor.setAlphaF(alpha); + PDFPainterHelper::setBLBrush(context, QBrush(newColor, Qt::SolidPattern)); + color = newColor; + } + + context.fillTriangle(m_vertices[triangle.v1].x(), m_vertices[triangle.v1].y(), + m_vertices[triangle.v2].x(), m_vertices[triangle.v2].y(), + m_vertices[triangle.v3].x(), m_vertices[triangle.v3].y()); + } + + context.restore(); +} + void PDFMesh::transform(const QTransform& matrix) { for (QPointF& vertex : m_vertices) diff --git a/Pdf4QtLibCore/sources/pdfpattern.h b/Pdf4QtLibCore/sources/pdfpattern.h index a50d4ab..217e079 100644 --- a/Pdf4QtLibCore/sources/pdfpattern.h +++ b/Pdf4QtLibCore/sources/pdfpattern.h @@ -29,6 +29,8 @@ #include +class BLContext; + namespace pdf { class PDFPattern; @@ -94,6 +96,11 @@ public: /// \param alpha Opacity factor void paint(QPainter* painter, PDFReal alpha) const; + /// Paints the mesh on the context + /// \param context Painter, onto which is mesh drawn + /// \param alpha Opacity factor + void paint(BLContext& context, PDFReal alpha) const; + /// Transforms the mesh according to the matrix transform /// \param matrix Matrix transform to be performed void transform(const QTransform& matrix); diff --git a/Pdf4QtLibCore/sources/pdfrenderer.cpp b/Pdf4QtLibCore/sources/pdfrenderer.cpp index 4139f8d..585dea0 100644 --- a/Pdf4QtLibCore/sources/pdfrenderer.cpp +++ b/Pdf4QtLibCore/sources/pdfrenderer.cpp @@ -26,13 +26,7 @@ #include #include -#ifdef PDF4QT_ENABLE_OPENGL -#include -#include -#include -#include -#include -#endif +#include #include "pdfdbgheap.h" @@ -227,54 +221,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) { } 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 +244,37 @@ 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) { - // 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)) + BLContext blContext; + BLImage blImage; + + blContext.setHint(BL_CONTEXT_HINT_RENDERING_QUALITY, BL_RENDERING_QUALITY_MAX_VALUE); + + blImage.createFromData(image.width(), image.height(), BL_FORMAT_PRGB32, image.bits(), image.bytesPerLine()); + if (blContext.begin(blImage) == BL_SUCCESS) { - if (!m_fbo || m_fbo->width() != size.width() || m_fbo->height() != size.height()) - { - // Delete old framebuffer object - delete m_fbo; + blContext.clearAll(); - // Create a new framebuffer object - QOpenGLFramebufferObjectFormat format; - format.setSamples(m_surfaceFormat.samples()); - m_fbo = new QOpenGLFramebufferObject(size.width(), size.height(), format); + compiledPage->draw(blContext, page->getCropBox(), matrix, features, 1.0); + + if (annotationManager) + { + QList errors; + PDFTextLayoutGetter textLayoutGetter(nullptr, pageIndex); + annotationManager->drawPage(blContext, pageIndex, compiledPage, textLayoutGetter, matrix, errors); } - 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 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(); + blContext.end(); } } -#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 +288,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 +299,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 +816,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 +831,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::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(context.functions()->glGetString(GL_VERSION)); - const char* vendorStr = reinterpret_cast(context.functions()->glGetString(GL_VENDOR)); - const char* rendererStr = reinterpret_cast(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 diff --git a/Pdf4QtLibCore/sources/pdfrenderer.h b/Pdf4QtLibCore/sources/pdfrenderer.h index d4d2cdb..5b74be0 100644 --- a/Pdf4QtLibCore/sources/pdfrenderer.h +++ b/Pdf4QtLibCore/sources/pdfrenderer.h @@ -28,13 +28,9 @@ #include #include #include -#include #include 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 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. diff --git a/Pdf4QtLibWidgets/CMakeLists.txt b/Pdf4QtLibWidgets/CMakeLists.txt index e8e620b..591ce20 100644 --- a/Pdf4QtLibWidgets/CMakeLists.txt +++ b/Pdf4QtLibWidgets/CMakeLists.txt @@ -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}) diff --git a/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.cpp b/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.cpp index 6c0db60..8806827 100644 --- a/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.cpp +++ b/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.cpp @@ -24,6 +24,7 @@ #include "pdfannotation.h" #include "pdfdrawwidget.h" #include "pdfwidgetannotation.h" +#include "pdfpainterutils.h" #include #include @@ -31,6 +32,8 @@ #include #include +#include + #include "pdfdbgheap.h" namespace pdf @@ -469,7 +472,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) { m_controller = new PDFDrawSpaceController(this); connect(m_controller, &PDFDrawSpaceController::drawSpaceChanged, this, &PDFDrawWidgetProxy::update); @@ -765,6 +768,18 @@ void PDFDrawWidgetProxy::draw(QPainter* painter, QRect rect) } } +void PDFDrawWidgetProxy::draw(BLContext& context, QRect rect) +{ + drawPages(context, rect, m_features); + + for (IDocumentDrawInterface* drawInterface : m_drawInterfaces) + { + context.save(); + drawInterface->drawPostRendering(context, rect); + context.restore(); + } +} + QColor PDFDrawWidgetProxy::getPaperColor() { QColor paperColor = getCMSManager()->getCurrentCMS()->getPaperColor(); @@ -920,6 +935,153 @@ void PDFDrawWidgetProxy::drawPages(QPainter* painter, QRect rect, PDFRenderer::F } } +void PDFDrawWidgetProxy::drawPages(BLContext& context, QRect rect, PDFRenderer::Features features) +{ + PDFPainterHelper::setBLBrush(context, QBrush(Qt::lightGray)); + context.fillRect(rect); + BLMatrix2D baseMatrix = context.userMatrix(); + + // Use current paper color (it can be a bit different from white) + QColor paperColor = getPaperColor(); + + // Iterate trough pages and display them on the painter device + for (const LayoutItem& item : m_layout.items) + { + // The offsets m_horizontalOffset and m_verticalOffset are offsets to the + // topleft point of the block. But block maybe doesn't start at (0, 0), + // so we must also use translation from the block beginning. + QRect placedRect = item.pageRect.translated(m_horizontalOffset - m_layout.blockRect.left(), m_verticalOffset - m_layout.blockRect.top()); + if (placedRect.intersects(rect)) + { + GroupInfo groupInfo = getGroupInfo(item.groupIndex); + + // Clear the page space by paper color + if (groupInfo.drawPaper) + { + PDFPainterHelper::setBLBrush(context, paperColor); + context.fillRect(placedRect); + } + + const PDFPrecompiledPage* compiledPage = m_compiler->getCompiledPage(item.pageIndex, true); + if (compiledPage && compiledPage->isValid()) + { + QElapsedTimer timer; + timer.start(); + + const PDFPage* page = m_controller->getDocument()->getCatalog()->getPage(item.pageIndex); + QTransform matrix = QTransform(createPagePointToDevicePointMatrix(page, placedRect)) * baseMatrix; + compiledPage->draw(context, page->getCropBox(), matrix, features, groupInfo.transparency); + PDFTextLayoutGetter layoutGetter = m_textLayoutCompiler->getTextLayoutLazy(item.pageIndex); + + // Draw text blocks/text lines, if it is enabled + if (features.testFlag(PDFRenderer::DebugTextBlocks)) + { + m_textLayoutCompiler->makeTextLayout(); + const PDFTextLayout& layout = layoutGetter; + const PDFTextBlocks& textBlocks = layout.getTextBlocks(); + + context.save(); + painter->setFont(m_widget->font()); + painter->setPen(Qt::red); + painter->setBrush(QColor(255, 0, 0, 128)); + + QFontMetricsF fontMetrics(painter->font(), painter->device()); + int blockIndex = 1; + for (const PDFTextBlock& block : textBlocks) + { + QString blockNumber = QString::number(blockIndex++); + + painter->drawPath(matrix.map(block.getBoundingBox())); + painter->drawText(matrix.map(block.getTopLeft()) - QPointF(fontMetrics.horizontalAdvance(blockNumber), 0), blockNumber, Qt::TextSingleLine, 0); + } + + context.restore(); + } + if (features.testFlag(PDFRenderer::DebugTextLines)) + { + m_textLayoutCompiler->makeTextLayout(); + const PDFTextLayout& layout = layoutGetter; + const PDFTextBlocks& textBlocks = layout.getTextBlocks(); + + context.save(); + painter->setFont(m_widget->font()); + painter->setPen(Qt::green); + painter->setBrush(QColor(0, 255, 0, 128)); + + QFontMetricsF fontMetrics(painter->font(), painter->device()); + int lineIndex = 1; + for (const PDFTextBlock& block : textBlocks) + { + for (const PDFTextLine& line : block.getLines()) + { + QString lineNumber = QString::number(lineIndex++); + + painter->drawPath(matrix.map(line.getBoundingBox())); + painter->drawText(matrix.map(line.getTopLeft()) - QPointF(fontMetrics.horizontalAdvance(lineNumber), 0), lineNumber, Qt::TextSingleLine, 0); + } + } + + context.restore(); + } + + QList drawInterfaceErrors; + if (!features.testFlag(PDFRenderer::DenyExtraGraphics)) + { + for (IDocumentDrawInterface* drawInterface : m_drawInterfaces) + { + context.save(); + drawInterface->drawPage(context, item.pageIndex, compiledPage, layoutGetter, matrix, drawInterfaceErrors); + context.restore(); + } + } + + const qint64 drawTimeNS = timer.nsecsElapsed(); + + // Draw rendering times + if (features.testFlag(PDFRenderer::DisplayTimes)) + { + QFont font = m_widget->font(); + font.setPointSize(12); + + auto formatDrawTime = [](qint64 nanoseconds) + { + PDFReal miliseconds = nanoseconds / 1000000.0; + return QString::number(miliseconds, 'f', 3); + }; + + QFontMetrics fontMetrics(font); + const int lineSpacing = fontMetrics.lineSpacing(); + + context.save(); + painter->setPen(Qt::red); + painter->setFont(font); + context.translate(placedRect.topLeft()); + context.translate(placedRect.width() / 20.0, placedRect.height() / 20.0); // Offset + + painter->setBackground(QBrush(Qt::white)); + painter->setBackgroundMode(Qt::OpaqueMode); + painter->drawText(0, 0, PDFTranslationContext::tr("Compile time: %1 [ms]").arg(formatDrawTime(compiledPage->getCompilingTimeNS()))); + painter->translate(0, lineSpacing); + painter->drawText(0, 0, PDFTranslationContext::tr("Draw time: %1 [ms]").arg(formatDrawTime(drawTimeNS))); + + context.restore(); + } + + const QList& pageErrors = compiledPage->getErrors(); + if (!pageErrors.empty() || !drawInterfaceErrors.empty()) + { + QList errors = pageErrors; + if (!drawInterfaceErrors.isEmpty()) + { + errors.append(drawInterfaceErrors); + } + Q_EMIT renderingError(item.pageIndex, qMove(errors)); + } + } + } + } +} + QImage PDFDrawWidgetProxy::drawThumbnailImage(PDFInteger pageIndex, int pixelSize) const { QImage image; @@ -1403,11 +1565,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) diff --git a/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.h b/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.h index 4c1d84d..4c429ee 100644 --- a/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.h +++ b/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.h @@ -34,6 +34,8 @@ class QPainter; class QScrollBar; class QTimer; +class BLContext; + namespace pdf { class PDFProgress; @@ -212,6 +214,15 @@ public: /// \param rect Rectangle in which the content is painted void draw(QPainter* painter, QRect rect); + /// Draws the actually visible pages on the context using the rectangle. + /// Rectangle is space in the widget, which is used for painting the PDF. + /// This function is using drawPages function to draw all pages. After that, + /// custom drawing is performed. + /// \sa drawPages + /// \param context Context to paint the PDF pages + /// \param rect Rectangle in which the content is painted + void draw(BLContext& context, QRect rect); + /// Draws the actually visible pages on the painter using the rectangle. /// Rectangle is space in the widget, which is used for painting the PDF. /// \param painter Painter to paint the PDF pages @@ -219,6 +230,13 @@ public: /// \param features Rendering features void drawPages(QPainter* painter, QRect rect, PDFRenderer::Features features); + /// Draws the actually visible pages on the painter using the rectangle. + /// Rectangle is space in the widget, which is used for painting the PDF. + /// \param painter Painter to paint the PDF pages + /// \param rect Rectangle in which the content is painted + /// \param features Rendering features + void drawPages(BLContext& context, QRect rect, PDFRenderer::Features features); + /// Draws thumbnail image of the given size (so larger of the page size /// width or height equals to pixel size and the latter size is rescaled /// using the aspect ratio) @@ -317,9 +335,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 +355,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 +477,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 +550,8 @@ private: /// Additional drawing interfaces std::set 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 diff --git a/Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp b/Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp index f4019ad..b034a3a 100644 --- a/Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp +++ b/Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp @@ -30,12 +30,14 @@ #include #include +#include + #include "pdfdbgheap.h" 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 +46,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 +65,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 +93,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(m_drawWidget->getWidget()); - PDFDrawWidget* softwareDrawWidget = qobject_cast(m_drawWidget->getWidget()); - - // Do we need to change renderer? - if ((openglDrawWidget && engine != RendererEngine::OpenGL) || (softwareDrawWidget && engine != RendererEngine::Software)) - { - QGridLayout* layout = qobject_cast(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 +116,6 @@ int PDFWidget::getPageRenderingErrorCount() const return count; } -void PDFWidget::updateRendererImpl() -{ -#ifdef PDF4QT_ENABLE_OPENGL - PDFOpenGLDrawWidget* openglDrawWidget = qobject_cast(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& errors) { // Empty list of error should not be reported! @@ -182,29 +146,6 @@ void PDFWidget::onPageImageChanged(bool all, const std::vector& 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 +164,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 +190,38 @@ void PDFWidget::setAnnotationManager(PDFWidgetAnnotationManager* annotationManag addInputInterface(m_annotationManager); } -template -PDFDrawWidgetBase::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 -std::vector PDFDrawWidgetBase::getCurrentPages() const +std::vector PDFDrawWidget::getCurrentPages() const { return this->m_widget->getDrawWidgetProxy()->getPagesIntersectingRect(this->rect()); } -template -QSize PDFDrawWidgetBase::minimumSizeHint() const +QSize PDFDrawWidget::minimumSizeHint() const { return QSize(200, 200); } -template -bool PDFDrawWidgetBase::event(QEvent* event) +bool PDFDrawWidget::event(QEvent* event) { if (event->type() == QEvent::ShortcutOverride) { return processEvent(static_cast(event)); } - return BaseWidget::event(event); + return BaseClass::event(event); } -template -void PDFDrawWidgetBase::performMouseOperation(QPoint currentMousePosition) +void PDFDrawWidget::performMouseOperation(QPoint currentMousePosition) { switch (m_mouseOperation) { @@ -323,9 +249,8 @@ void PDFDrawWidgetBase::performMouseOperation(QPoint currentMousePos } } -template template -bool PDFDrawWidgetBase::processEvent(Event* event) +bool PDFDrawWidget::processEvent(Event* event) { QString tooltip; for (IDrawWidgetInputInterface* inputInterface : m_widget->getInputInterfaces()) @@ -351,8 +276,7 @@ bool PDFDrawWidgetBase::processEvent(Event* event) return false; } -template -void PDFDrawWidgetBase::keyPressEvent(QKeyEvent* event) +void PDFDrawWidget::keyPressEvent(QKeyEvent* event) { event->ignore(); @@ -388,8 +312,7 @@ void PDFDrawWidgetBase::keyPressEvent(QKeyEvent* event) updateCursor(); } -template -void PDFDrawWidgetBase::keyReleaseEvent(QKeyEvent* event) +void PDFDrawWidget::keyReleaseEvent(QKeyEvent* event) { event->ignore(); @@ -401,8 +324,7 @@ void PDFDrawWidgetBase::keyReleaseEvent(QKeyEvent* event) event->accept(); } -template -void PDFDrawWidgetBase::mousePressEvent(QMouseEvent* event) +void PDFDrawWidget::mousePressEvent(QMouseEvent* event) { event->ignore(); @@ -442,8 +364,7 @@ void PDFDrawWidgetBase::mousePressEvent(QMouseEvent* event) event->accept(); } -template -void PDFDrawWidgetBase::mouseDoubleClickEvent(QMouseEvent* event) +void PDFDrawWidget::mouseDoubleClickEvent(QMouseEvent* event) { event->ignore(); @@ -453,8 +374,7 @@ void PDFDrawWidgetBase::mouseDoubleClickEvent(QMouseEvent* event) } } -template -void PDFDrawWidgetBase::mouseReleaseEvent(QMouseEvent* event) +void PDFDrawWidget::mouseReleaseEvent(QMouseEvent* event) { event->ignore(); @@ -491,8 +411,7 @@ void PDFDrawWidgetBase::mouseReleaseEvent(QMouseEvent* event) event->accept(); } -template -void PDFDrawWidgetBase::mouseMoveEvent(QMouseEvent* event) +void PDFDrawWidget::mouseMoveEvent(QMouseEvent* event) { event->ignore(); @@ -506,8 +425,7 @@ void PDFDrawWidgetBase::mouseMoveEvent(QMouseEvent* event) event->accept(); } -template -void PDFDrawWidgetBase::updateCursor() +void PDFDrawWidget::updateCursor() { std::optional cursor; @@ -554,8 +472,7 @@ void PDFDrawWidgetBase::updateCursor() } } -template -void PDFDrawWidgetBase::onAutoScrollTimeout() +void PDFDrawWidget::onAutoScrollTimeout() { if (m_mouseOperation != MouseOperation::AutoScroll) { @@ -579,8 +496,7 @@ void PDFDrawWidgetBase::onAutoScrollTimeout() proxy->scrollByPixels(QPoint(scrollX, scrollY)); } -template -void PDFDrawWidgetBase::wheelEvent(QWheelEvent* event) +void PDFDrawWidget::wheelEvent(QWheelEvent* event) { event->ignore(); @@ -659,62 +575,56 @@ void PDFDrawWidgetBase::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()); + switch (getPDFWidget()->getDrawWidgetProxy()->getRendererEngine()) + { + case RendererEngine::Blend2D: + { + BLContext blContext; + BLImage blImage; + + QRect rect = this->rect(); + if (m_blend2DframeBuffer.size() != rect.size()) + { + m_blend2DframeBuffer = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied); + } + + BLContextCreateInfo info{}; + info.reset(); + info.flags = BL_CONTEXT_CREATE_FLAG_FALLBACK_TO_SYNC; + info.threadCount = QThread::idealThreadCount(); + + blContext.setHint(BL_CONTEXT_HINT_RENDERING_QUALITY, BL_RENDERING_QUALITY_MAX_VALUE); + + blImage.createFromData(m_blend2DframeBuffer.width(), m_blend2DframeBuffer.height(), BL_FORMAT_PRGB32, m_blend2DframeBuffer.bits(), m_blend2DframeBuffer.bytesPerLine()); + if (blContext.begin(blImage, info) == BL_SUCCESS) + { + blContext.clearAll(); + getPDFWidget()->getDrawWidgetProxy()->draw(blContext, rect); + blContext.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 +634,4 @@ void PDFDrawWidget::resizeEvent(QResizeEvent* event) getPDFWidget()->getDrawWidgetProxy()->update(); } -#ifdef PDF4QT_ENABLE_OPENGL -template class PDFDrawWidgetBase; -#endif -template class PDFDrawWidgetBase; - } // namespace pdf diff --git a/Pdf4QtLibWidgets/sources/pdfdrawwidget.h b/Pdf4QtLibWidgets/sources/pdfdrawwidget.h index 69310f3..da864bd 100644 --- a/Pdf4QtLibWidgets/sources/pdfdrawwidget.h +++ b/Pdf4QtLibWidgets/sources/pdfdrawwidget.h @@ -27,10 +27,6 @@ #include #include -#ifdef PDF4QT_ENABLE_OPENGL -#include -#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& errors); void onPageImageChanged(bool all, const std::vector& 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 m_inputInterfaces; + RendererEngine m_rendererEngine; }; -template -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 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 -{ - Q_OBJECT - -private: - using BaseClass = PDFDrawWidgetBase; - -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 -{ - Q_OBJECT - -private: - using BaseClass = PDFDrawWidgetBase; - -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; -#endif -extern template class PDFDrawWidgetBase; - } // namespace pdf #endif // PDFDRAWWIDGET_H diff --git a/Pdf4QtLibWidgets/sources/pdfwidgetannotation.cpp b/Pdf4QtLibWidgets/sources/pdfwidgetannotation.cpp index 4d797ef..fda8c2e 100644 --- a/Pdf4QtLibWidgets/sources/pdfwidgetannotation.cpp +++ b/Pdf4QtLibWidgets/sources/pdfwidgetannotation.cpp @@ -539,4 +539,9 @@ void PDFWidgetAnnotationManager::drawPage(QPainter* painter, BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors); } +void PDFWidgetAnnotationManager::drawPage(BLContext& context, PDFInteger pageIndex, const PDFPrecompiledPage* compiledPage, PDFTextLayoutGetter& layoutGetter, const QTransform& pagePointToDevicePointMatrix, QList& errors) const +{ + BaseClass::drawPage(context, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors); +} + } // namespace pdf diff --git a/Pdf4QtLibWidgets/sources/pdfwidgetannotation.h b/Pdf4QtLibWidgets/sources/pdfwidgetannotation.h index 4ad1865..a57c704 100644 --- a/Pdf4QtLibWidgets/sources/pdfwidgetannotation.h +++ b/Pdf4QtLibWidgets/sources/pdfwidgetannotation.h @@ -57,6 +57,13 @@ public: const QTransform& pagePointToDevicePointMatrix, QList& errors) const override; + virtual void drawPage(BLContext& context, + PDFInteger pageIndex, + const PDFPrecompiledPage* compiledPage, + PDFTextLayoutGetter& layoutGetter, + const QTransform& pagePointToDevicePointMatrix, + QList& errors) const override; + /// Returns tooltip generated from annotation virtual QString getTooltip() const override { return m_tooltip; } diff --git a/Pdf4QtViewer/CMakeLists.txt b/Pdf4QtViewer/CMakeLists.txt index ce04fcb..8761be4 100644 --- a/Pdf4QtViewer/CMakeLists.txt +++ b/Pdf4QtViewer/CMakeLists.txt @@ -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}) diff --git a/Pdf4QtViewer/pdfprogramcontroller.cpp b/Pdf4QtViewer/pdfprogramcontroller.cpp index 3f0533d..2b8b56a 100644 --- a/Pdf4QtViewer/pdfprogramcontroller.cpp +++ b/Pdf4QtViewer/pdfprogramcontroller.cpp @@ -2298,24 +2298,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; diff --git a/Pdf4QtViewer/pdfprogramcontroller.h b/Pdf4QtViewer/pdfprogramcontroller.h index e19eb63..32f9d82 100644 --- a/Pdf4QtViewer/pdfprogramcontroller.h +++ b/Pdf4QtViewer/pdfprogramcontroller.h @@ -297,8 +297,6 @@ public: void writeSettings(); void resetSettings(); - void checkHardwareOpenGLAvailability(); - void performPrint(); void performSave(); void performSaveAs(); diff --git a/Pdf4QtViewer/pdfrendertoimagesdialog.cpp b/Pdf4QtViewer/pdfrendertoimagesdialog.cpp index 191acb5..5c52958 100644 --- a/Pdf4QtViewer/pdfrendertoimagesdialog.cpp +++ b/Pdf4QtViewer/pdfrendertoimagesdialog.cpp @@ -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]() diff --git a/Pdf4QtViewer/pdfviewermainwindow.cpp b/Pdf4QtViewer/pdfviewermainwindow.cpp index 644b8db..5024c75 100644 --- a/Pdf4QtViewer/pdfviewermainwindow.cpp +++ b/Pdf4QtViewer/pdfviewermainwindow.cpp @@ -543,7 +543,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) diff --git a/Pdf4QtViewer/pdfviewermainwindowlite.cpp b/Pdf4QtViewer/pdfviewermainwindowlite.cpp index 385318d..08b8677 100644 --- a/Pdf4QtViewer/pdfviewermainwindowlite.cpp +++ b/Pdf4QtViewer/pdfviewermainwindowlite.cpp @@ -432,7 +432,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) diff --git a/Pdf4QtViewer/pdfviewersettings.cpp b/Pdf4QtViewer/pdfviewersettings.cpp index cf11de5..b54cbd2 100644 --- a/Pdf4QtViewer/pdfviewersettings.cpp +++ b/Pdf4QtViewer/pdfviewersettings.cpp @@ -43,7 +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(settings.value("rendererFeaturesv2", static_cast(pdf::PDFRenderer::getDefaultFeatures())).toInt()); - m_settings.m_rendererEngine = static_cast(settings.value("renderingEngine", static_cast(pdf::RendererEngine::OpenGL)).toInt()); + m_settings.m_rendererEngine = static_cast(settings.value("renderingEngine", static_cast(pdf::RendererEngine::Blend2D)).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_prefetchPages = settings.value("prefetchPages", defaultSettings.m_prefetchPages).toBool(); @@ -271,7 +271,7 @@ void PDFViewerSettings::setColorTolerance(pdf::PDFReal colorTolerance) PDFViewerSettings::Settings::Settings() : m_features(pdf::PDFRenderer::getDefaultFeatures()), - m_rendererEngine(pdf::RendererEngine::OpenGL), + m_rendererEngine(pdf::RendererEngine::Blend2D), m_multisampleAntialiasing(true), m_rendererSamples(16), m_prefetchPages(true), diff --git a/Pdf4QtViewer/pdfviewersettings.h b/Pdf4QtViewer/pdfviewersettings.h index 281e103..1e73f9b 100644 --- a/Pdf4QtViewer/pdfviewersettings.h +++ b/Pdf4QtViewer/pdfviewersettings.h @@ -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; diff --git a/Pdf4QtViewer/pdfviewersettingsdialog.cpp b/Pdf4QtViewer/pdfviewersettingsdialog.cpp index d2d54b4..735f48e 100644 --- a/Pdf4QtViewer/pdfviewersettingsdialog.cpp +++ b/Pdf4QtViewer/pdfviewersettingsdialog.cpp @@ -102,8 +102,8 @@ PDFViewerSettingsDialog::PDFViewerSettingsDialog(const PDFViewerSettings::Settin font.setPointSize(font.pointSize() * 1.5); ui->optionsPagesWidget->setFont(font); - ui->renderingEngineComboBox->addItem(tr("Software"), static_cast(pdf::RendererEngine::Software)); - ui->renderingEngineComboBox->addItem(tr("Hardware accelerated (OpenGL)"), static_cast(pdf::RendererEngine::OpenGL)); + ui->renderingEngineComboBox->addItem(tr("Software | QPainter"), static_cast(pdf::RendererEngine::QPainter)); + ui->renderingEngineComboBox->addItem(tr("Software | Blend2D | Multithreaded"), static_cast(pdf::RendererEngine::Blend2D)); for (int i : { 1, 2, 4, 8, 16 }) { @@ -279,29 +279,6 @@ void PDFViewerSettingsDialog::loadData() ui->renderingEngineComboBox->setCurrentIndex(ui->renderingEngineComboBox->findData(static_cast(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(m_settings.m_multithreadingStrategy))); diff --git a/Pdf4QtViewer/pdfviewersettingsdialog.ui b/Pdf4QtViewer/pdfviewersettingsdialog.ui index ad687e1..df90046 100644 --- a/Pdf4QtViewer/pdfviewersettingsdialog.ui +++ b/Pdf4QtViewer/pdfviewersettingsdialog.ui @@ -35,7 +35,7 @@ - 6 + 0 @@ -59,47 +59,16 @@ - - + + - Enable + Multithreading strategy - - - - Multisample antialiasing (MSAA) - - - - - - - - - - Prefetch pages - - - - - - - MSAA Samples count - - - - - - - Enable - - - @@ -107,22 +76,29 @@ - - + + - Multithreading strategy + Prefetch pages - + + + + + Enable + + + - <html><head/><body><p>Choose a rendering method based on your needs. Although <span style=" font-weight:600;">Software Rendering</span> is slower than the hardware-accelerated <span style=" font-weight:600;">OpenGL Rendering</span>, it can be utilized when OpenGL is not available on your platform. The default (and recommended) method is OpenGL Rendering. </p><p>OpenGL rendering employs <span style=" font-weight:600;">Multisample Antialiasing (MSAA)</span>, 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. </p><p>The <span style=" font-weight:600;">Prefetch Pages</span> feature pre-renders pages adjacent to the currently viewed pages, minimizing flickering during scrolling. Prefetched pages are stored in the page cache. </p><p>The <span style=" font-weight:600;">Multithreading Strategy</span> determines how the program will utilize CPU cores. With the <span style=" font-weight:600;">Single Thread</span> 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. </p></body></html> + <html><head/><body><p>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.</p><p>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.</p><p>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.</p><p>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.</p><p>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.</p></body></html> true diff --git a/Pdf4QtViewerLite/main.cpp b/Pdf4QtViewerLite/main.cpp index 6074ff6..c1e1321 100644 --- a/Pdf4QtViewerLite/main.cpp +++ b/Pdf4QtViewerLite/main.cpp @@ -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"); diff --git a/Pdf4QtViewerPlugins/AudioBookPlugin/CMakeLists.txt b/Pdf4QtViewerPlugins/AudioBookPlugin/CMakeLists.txt index 5e45277..b696d78 100644 --- a/Pdf4QtViewerPlugins/AudioBookPlugin/CMakeLists.txt +++ b/Pdf4QtViewerPlugins/AudioBookPlugin/CMakeLists.txt @@ -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) diff --git a/Pdf4QtViewerPlugins/DimensionsPlugin/CMakeLists.txt b/Pdf4QtViewerPlugins/DimensionsPlugin/CMakeLists.txt index c91f480..7fb4947 100644 --- a/Pdf4QtViewerPlugins/DimensionsPlugin/CMakeLists.txt +++ b/Pdf4QtViewerPlugins/DimensionsPlugin/CMakeLists.txt @@ -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 diff --git a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/CMakeLists.txt b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/CMakeLists.txt index 56e63b7..a3c8435 100644 --- a/Pdf4QtViewerPlugins/ObjectInspectorPlugin/CMakeLists.txt +++ b/Pdf4QtViewerPlugins/ObjectInspectorPlugin/CMakeLists.txt @@ -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 diff --git a/Pdf4QtViewerPlugins/OutputPreviewPlugin/CMakeLists.txt b/Pdf4QtViewerPlugins/OutputPreviewPlugin/CMakeLists.txt index 0a777f8..b28aae3 100644 --- a/Pdf4QtViewerPlugins/OutputPreviewPlugin/CMakeLists.txt +++ b/Pdf4QtViewerPlugins/OutputPreviewPlugin/CMakeLists.txt @@ -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 diff --git a/Pdf4QtViewerPlugins/RedactPlugin/CMakeLists.txt b/Pdf4QtViewerPlugins/RedactPlugin/CMakeLists.txt index e046154..9acfac1 100644 --- a/Pdf4QtViewerPlugins/RedactPlugin/CMakeLists.txt +++ b/Pdf4QtViewerPlugins/RedactPlugin/CMakeLists.txt @@ -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 diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/CMakeLists.txt b/Pdf4QtViewerPlugins/SignaturePlugin/CMakeLists.txt index f381e7a..c6650e0 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/CMakeLists.txt +++ b/Pdf4QtViewerPlugins/SignaturePlugin/CMakeLists.txt @@ -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) diff --git a/Pdf4QtViewerPlugins/SoftProofingPlugin/CMakeLists.txt b/Pdf4QtViewerPlugins/SoftProofingPlugin/CMakeLists.txt index e749ef3..ea24c1c 100644 --- a/Pdf4QtViewerPlugins/SoftProofingPlugin/CMakeLists.txt +++ b/Pdf4QtViewerPlugins/SoftProofingPlugin/CMakeLists.txt @@ -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 diff --git a/Pdf4QtViewerProfi/main.cpp b/Pdf4QtViewerProfi/main.cpp index 69d1250..2dea3c0 100644 --- a/Pdf4QtViewerProfi/main.cpp +++ b/Pdf4QtViewerProfi/main.cpp @@ -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"); diff --git a/PdfTool/main.cpp b/PdfTool/main.cpp index 75a1962..64d829e 100644 --- a/PdfTool/main.cpp +++ b/PdfTool/main.cpp @@ -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); diff --git a/PdfTool/pdftoolabstractapplication.cpp b/PdfTool/pdftoolabstractapplication.cpp index 7733a45..781f9be 100644 --- a/PdfTool/pdftoolabstractapplication.cpp +++ b/PdfTool/pdftoolabstractapplication.cpp @@ -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 { diff --git a/PdfTool/pdftoolabstractapplication.h b/PdfTool/pdftoolabstractapplication.h index 9f4e434..5a28d71 100644 --- a/PdfTool/pdftoolabstractapplication.h +++ b/PdfTool/pdftoolabstractapplication.h @@ -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(); diff --git a/PdfTool/pdftoolrender.cpp b/PdfTool/pdftoolrender.cpp index 3e0cd26..6721d73 100644 --- a/PdfTool/pdftoolrender.cpp +++ b/PdfTool/pdftoolrender.cpp @@ -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, nullptr); auto onRenderError = [this](pdf::PDFInteger pageIndex, pdf::PDFRenderError error) { diff --git a/vcpkg.json b/vcpkg.json index 62e2c3b..5bb2723 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -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" ] }