mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-04-14 10:22:14 +02:00
Issue #123: Blend2D painting implementation
This commit is contained in:
parent
d314683d38
commit
f3e1a94e1c
@ -82,7 +82,7 @@ MainWindow::MainWindow(QWidget* parent) :
|
|||||||
ui->documentFrame->setLayout(new QVBoxLayout);
|
ui->documentFrame->setLayout(new QVBoxLayout);
|
||||||
|
|
||||||
m_cmsManager = new pdf::PDFCMSManager(this);
|
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);
|
m_pdfWidget->getDrawWidgetProxy()->setProgress(m_progress);
|
||||||
ui->documentFrame->layout()->addWidget(m_pdfWidget);
|
ui->documentFrame->layout()->addWidget(m_pdfWidget);
|
||||||
m_pdfWidget->getDrawWidgetProxy()->registerDrawInterface(&m_drawInterface);
|
m_pdfWidget->getDrawWidgetProxy()->registerDrawInterface(&m_drawInterface);
|
||||||
|
@ -146,6 +146,8 @@ add_library(Pdf4QtLibCore SHARED
|
|||||||
cmaps.qrc
|
cmaps.qrc
|
||||||
sources/pdfcertificatestore.h
|
sources/pdfcertificatestore.h
|
||||||
sources/pdfcertificatestore.cpp
|
sources/pdfcertificatestore.cpp
|
||||||
|
sources/pdfblpainter.h
|
||||||
|
sources/pdfblpainter.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
|
@ -1482,17 +1482,6 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFAnnotationManager::drawPage(BLContext& context, PDFInteger pageIndex, const PDFPrecompiledPage* compiledPage, PDFTextLayoutGetter& layoutGetter, const QTransform& pagePointToDevicePointMatrix, QList<PDFRenderError>& 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,
|
void PDFAnnotationManager::drawAnnotation(const PageAnnotation& annotation,
|
||||||
const QTransform& pagePointToDevicePointMatrix,
|
const QTransform& pagePointToDevicePointMatrix,
|
||||||
const PDFPage* page,
|
const PDFPage* page,
|
||||||
|
@ -40,8 +40,6 @@ class QKeyEvent;
|
|||||||
class QMouseEvent;
|
class QMouseEvent;
|
||||||
class QWheelEvent;
|
class QWheelEvent;
|
||||||
|
|
||||||
class BLContext;
|
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
class PDFWidget;
|
class PDFWidget;
|
||||||
@ -1468,13 +1466,6 @@ public:
|
|||||||
const QTransform& pagePointToDevicePointMatrix,
|
const QTransform& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const;
|
QList<PDFRenderError>& errors) const;
|
||||||
|
|
||||||
virtual void drawPage(BLContext& context,
|
|
||||||
PDFInteger pageIndex,
|
|
||||||
const PDFPrecompiledPage* compiledPage,
|
|
||||||
PDFTextLayoutGetter& layoutGetter,
|
|
||||||
const QTransform& pagePointToDevicePointMatrix,
|
|
||||||
QList<PDFRenderError>& errors) const;
|
|
||||||
|
|
||||||
/// Set document
|
/// Set document
|
||||||
/// \param document New document
|
/// \param document New document
|
||||||
virtual void setDocument(const PDFModifiedDocument& document);
|
virtual void setDocument(const PDFModifiedDocument& document);
|
||||||
|
755
Pdf4QtLibCore/sources/pdfblpainter.cpp
Normal file
755
Pdf4QtLibCore/sources/pdfblpainter.cpp
Normal file
@ -0,0 +1,755 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#include "pdfblpainter.h"
|
||||||
|
#include "pdffont.h"
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
#include <QPainterPath>
|
||||||
|
#include <QPaintEngine>
|
||||||
|
|
||||||
|
#include <Blend2d.h>
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
class PDFBLPaintEngine : public QPaintEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFBLPaintEngine(QImage& qtOffscreenBuffer, bool isMultithreaded);
|
||||||
|
|
||||||
|
virtual bool begin(QPaintDevice*) override;
|
||||||
|
virtual bool end() override;
|
||||||
|
virtual void updateState(const QPaintEngineState& updatedState) override;
|
||||||
|
virtual void drawRects(const QRect* rects, int rectCount) override;
|
||||||
|
virtual void drawRects(const QRectF* rects, int rectCount) override;
|
||||||
|
virtual void drawLines(const QLine* lines, int lineCount) override;
|
||||||
|
virtual void drawLines(const QLineF* lines, int lineCount) override;
|
||||||
|
virtual void drawEllipse(const QRectF& r) override;
|
||||||
|
virtual void drawEllipse(const QRect& r) override;
|
||||||
|
virtual void drawPath(const QPainterPath& path) override;
|
||||||
|
virtual void drawPoints(const QPointF* points, int pointCount) override;
|
||||||
|
virtual void drawPoints(const QPoint* points, int pointCount) override;
|
||||||
|
virtual void drawPolygon(const QPointF* points, int pointCount, PolygonDrawMode mode) override;
|
||||||
|
virtual void drawPolygon(const QPoint* points, int pointCount, PolygonDrawMode mode) override;
|
||||||
|
virtual void drawPixmap(const QRectF& r, const QPixmap& pm, const QRectF& sr) override;
|
||||||
|
virtual void drawTextItem(const QPointF& p, const QTextItem& textItem) override;
|
||||||
|
virtual void drawTiledPixmap(const QRectF& r, const QPixmap& pixmap, const QPointF& s) override;
|
||||||
|
virtual void drawImage(const QRectF& r, const QImage& pm, const QRectF& sr, Qt::ImageConversionFlags flags) override;
|
||||||
|
virtual Type type() const override;
|
||||||
|
|
||||||
|
static PaintEngineFeatures getStaticFeatures();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// Get BL matrix from transformation
|
||||||
|
static BLMatrix2D getBLMatrix(QTransform transform);
|
||||||
|
|
||||||
|
static BLPoint getBLPoint(const QPoint& point);
|
||||||
|
static BLPoint getBLPoint(const QPointF& point);
|
||||||
|
|
||||||
|
/// Get BL rect from regular rect
|
||||||
|
static BLRectI 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);
|
||||||
|
|
||||||
|
/// Load font
|
||||||
|
static bool loadBLFont(BLFont& font, QString fontName, PDFReal fontSize);
|
||||||
|
|
||||||
|
/// Returns composition operator
|
||||||
|
static BLCompOp getBLCompOp(QPainter::CompositionMode mode);
|
||||||
|
|
||||||
|
bool isStrokeActive() const { return m_currentPen.style() != Qt::NoPen; }
|
||||||
|
bool isFillActive() const { return m_currentBrush.style() != Qt::NoBrush; }
|
||||||
|
|
||||||
|
QImage& m_qtOffscreenBuffer;
|
||||||
|
std::optional<BLContext> m_blContext;
|
||||||
|
std::optional<BLImage> m_blOffscreenBuffer;
|
||||||
|
bool m_isMultithreaded;
|
||||||
|
|
||||||
|
QPen m_currentPen;
|
||||||
|
QBrush m_currentBrush;
|
||||||
|
QFont m_currentFont;
|
||||||
|
};
|
||||||
|
|
||||||
|
PDFBLPaintDevice::PDFBLPaintDevice(QImage& offscreenBuffer, bool isMultithreaded) :
|
||||||
|
m_offscreenBuffer(offscreenBuffer),
|
||||||
|
m_paintEngine(new PDFBLPaintEngine(offscreenBuffer, isMultithreaded))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFBLPaintDevice::~PDFBLPaintDevice()
|
||||||
|
{
|
||||||
|
delete m_paintEngine;
|
||||||
|
m_paintEngine = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFBLPaintDevice::devType() const
|
||||||
|
{
|
||||||
|
return QInternal::CustomRaster;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPaintEngine* PDFBLPaintDevice::paintEngine() const
|
||||||
|
{
|
||||||
|
return m_paintEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFBLPaintDevice::metric(PaintDeviceMetric metric) const
|
||||||
|
{
|
||||||
|
switch (metric)
|
||||||
|
{
|
||||||
|
case QPaintDevice::PdmWidth:
|
||||||
|
return m_offscreenBuffer.width();
|
||||||
|
case QPaintDevice::PdmHeight:
|
||||||
|
return m_offscreenBuffer.height();
|
||||||
|
case QPaintDevice::PdmWidthMM:
|
||||||
|
return m_offscreenBuffer.widthMM();
|
||||||
|
case QPaintDevice::PdmHeightMM:
|
||||||
|
return m_offscreenBuffer.heightMM();
|
||||||
|
case QPaintDevice::PdmNumColors:
|
||||||
|
return m_offscreenBuffer.colorCount();
|
||||||
|
case QPaintDevice::PdmDepth:
|
||||||
|
return m_offscreenBuffer.depth();
|
||||||
|
case QPaintDevice::PdmDpiX:
|
||||||
|
return m_offscreenBuffer.logicalDpiX();
|
||||||
|
case QPaintDevice::PdmDpiY:
|
||||||
|
return m_offscreenBuffer.logicalDpiY();
|
||||||
|
case QPaintDevice::PdmPhysicalDpiX:
|
||||||
|
return m_offscreenBuffer.physicalDpiX();
|
||||||
|
case QPaintDevice::PdmPhysicalDpiY:
|
||||||
|
return m_offscreenBuffer.physicalDpiY();
|
||||||
|
case QPaintDevice::PdmDevicePixelRatio:
|
||||||
|
return m_offscreenBuffer.devicePixelRatio();
|
||||||
|
case QPaintDevice::PdmDevicePixelRatioScaled:
|
||||||
|
return m_offscreenBuffer.devicePixelRatioFScale();
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFBLPaintEngine::PDFBLPaintEngine(QImage& qtOffscreenBuffer, bool isMultithreaded) :
|
||||||
|
QPaintEngine(getStaticFeatures()),
|
||||||
|
m_qtOffscreenBuffer(qtOffscreenBuffer),
|
||||||
|
m_isMultithreaded(isMultithreaded)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PDFBLPaintEngine::begin(QPaintDevice*)
|
||||||
|
{
|
||||||
|
if (isActive())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blContext.emplace();
|
||||||
|
m_blOffscreenBuffer.emplace();
|
||||||
|
|
||||||
|
BLContextCreateInfo info{};
|
||||||
|
|
||||||
|
if (m_isMultithreaded)
|
||||||
|
{
|
||||||
|
info.flags = BL_CONTEXT_CREATE_FLAG_FALLBACK_TO_SYNC;
|
||||||
|
info.threadCount = QThread::idealThreadCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blContext->setHint(BL_CONTEXT_HINT_RENDERING_QUALITY, BL_RENDERING_QUALITY_MAX_VALUE);
|
||||||
|
|
||||||
|
m_blOffscreenBuffer->createFromData(m_qtOffscreenBuffer.width(), m_qtOffscreenBuffer.height(), BL_FORMAT_PRGB32, m_qtOffscreenBuffer.bits(), m_qtOffscreenBuffer.bytesPerLine());
|
||||||
|
if (m_blContext->begin(m_blOffscreenBuffer.value(), info) == BL_SUCCESS)
|
||||||
|
{
|
||||||
|
m_blContext->clearAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_blContext.reset();
|
||||||
|
m_blOffscreenBuffer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PDFBLPaintEngine::end()
|
||||||
|
{
|
||||||
|
if (!isActive())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blContext->end();
|
||||||
|
m_blContext.reset();
|
||||||
|
m_blOffscreenBuffer.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::updateState(const QPaintEngineState& updatedState)
|
||||||
|
{
|
||||||
|
/* DirtyBrushOrigin = 0x0004,
|
||||||
|
DirtyFont = 0x0008,
|
||||||
|
DirtyBackground = 0x0010,
|
||||||
|
DirtyBackgroundMode = 0x0020,
|
||||||
|
DirtyClipRegion = 0x0080,
|
||||||
|
DirtyClipPath = 0x0100,
|
||||||
|
DirtyHints = 0x0200,
|
||||||
|
DirtyClipEnabled = 0x0800,*/
|
||||||
|
|
||||||
|
if (updatedState.state().testFlag(QPaintEngine::DirtyPen))
|
||||||
|
{
|
||||||
|
m_currentPen = updatedState.pen();
|
||||||
|
setBLPen(m_blContext.value(), updatedState.pen());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedState.state().testFlag(QPaintEngine::DirtyBrush))
|
||||||
|
{
|
||||||
|
m_currentBrush = updatedState.brush();
|
||||||
|
setBLBrush(m_blContext.value(), updatedState.brush());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedState.state().testFlag(QPaintEngine::DirtyCompositionMode))
|
||||||
|
{
|
||||||
|
m_blContext->setCompOp(getBLCompOp(updatedState.compositionMode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedState.state().testFlag(QPaintEngine::DirtyOpacity))
|
||||||
|
{
|
||||||
|
m_blContext->setGlobalAlpha(updatedState.opacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedState.state().testFlag(QPaintEngine::DirtyTransform))
|
||||||
|
{
|
||||||
|
m_blContext->setMatrix(getBLMatrix(updatedState.transform()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawRects(const QRect* rects, int rectCount)
|
||||||
|
{
|
||||||
|
BLArray<BLRectI> blRects;
|
||||||
|
blRects.reserve(rectCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < rectCount; ++i)
|
||||||
|
{
|
||||||
|
blRects.append(getBLRect(rects[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFillActive())
|
||||||
|
{
|
||||||
|
m_blContext->fillRectArray(blRects.view());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStrokeActive())
|
||||||
|
{
|
||||||
|
m_blContext->strokeRectArray(blRects.view());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawRects(const QRectF* rects, int rectCount)
|
||||||
|
{
|
||||||
|
BLArray<BLRect> blRects;
|
||||||
|
blRects.reserve(rectCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < rectCount; ++i)
|
||||||
|
{
|
||||||
|
blRects.append(getBLRect(rects[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFillActive())
|
||||||
|
{
|
||||||
|
m_blContext->fillRectArray(blRects.view());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStrokeActive())
|
||||||
|
{
|
||||||
|
m_blContext->strokeRectArray(blRects.view());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawLines(const QLine* lines, int lineCount)
|
||||||
|
{
|
||||||
|
if (!isStrokeActive())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < lineCount; ++i)
|
||||||
|
{
|
||||||
|
const QLine& line = lines[i];
|
||||||
|
m_blContext->strokeLine(line.x1(), line.y1(), line.x2(), line.y2());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawLines(const QLineF* lines, int lineCount)
|
||||||
|
{
|
||||||
|
if (!isStrokeActive())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < lineCount; ++i)
|
||||||
|
{
|
||||||
|
const QLineF& line = lines[i];
|
||||||
|
m_blContext->strokeLine(line.x1(), line.y1(), line.x2(), line.y2());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawEllipse(const QRectF& r)
|
||||||
|
{
|
||||||
|
QPointF c = r.center();
|
||||||
|
BLEllipse blEllipse(c.x(), c.y(), r.width() * 0.5, r.height() * 0.5);
|
||||||
|
|
||||||
|
if (isFillActive())
|
||||||
|
{
|
||||||
|
m_blContext->fillEllipse(blEllipse);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStrokeActive())
|
||||||
|
{
|
||||||
|
m_blContext->strokeEllipse(blEllipse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawEllipse(const QRect& r)
|
||||||
|
{
|
||||||
|
QPointF c = r.center();
|
||||||
|
BLEllipse blEllipse(c.x(), c.y(), r.width() * 0.5, r.height() * 0.5);
|
||||||
|
|
||||||
|
if (isFillActive())
|
||||||
|
{
|
||||||
|
m_blContext->fillEllipse(blEllipse);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStrokeActive())
|
||||||
|
{
|
||||||
|
m_blContext->strokeEllipse(blEllipse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawPath(const QPainterPath& path)
|
||||||
|
{
|
||||||
|
BLPath blPath = getBLPath(path);
|
||||||
|
|
||||||
|
BLFillRule fillRule{};
|
||||||
|
|
||||||
|
switch (path.fillRule())
|
||||||
|
{
|
||||||
|
case Qt::OddEvenFill:
|
||||||
|
fillRule = BL_FILL_RULE_EVEN_ODD;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qt::WindingFill:
|
||||||
|
fillRule = BL_FILL_RULE_NON_ZERO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blContext->setFillRule(fillRule);
|
||||||
|
|
||||||
|
if (isFillActive())
|
||||||
|
{
|
||||||
|
m_blContext->fillPath(blPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStrokeActive())
|
||||||
|
{
|
||||||
|
m_blContext->strokePath(blPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawPoints(const QPointF* points, int pointCount)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawPoints(const QPoint* points, int pointCount)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawPolygon(const QPointF* points, int pointCount, PolygonDrawMode mode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawPolygon(const QPoint* points, int pointCount, PolygonDrawMode mode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawPixmap(const QRectF& r, const QPixmap& pm, const QRectF& sr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawTextItem(const QPointF& p, const QTextItem& textItem)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawTiledPixmap(const QRectF& r, const QPixmap& pixmap, const QPointF& s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBLPaintEngine::drawImage(const QRectF& r, const QImage& pm, const QRectF& sr, Qt::ImageConversionFlags flags)
|
||||||
|
{
|
||||||
|
QImage image = pm;
|
||||||
|
|
||||||
|
if (image.format() != QImage::Format_ARGB32_Premultiplied)
|
||||||
|
{
|
||||||
|
image.convertTo(QImage::Format_ARGB32_Premultiplied);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLImage blImage;
|
||||||
|
blImage.createFromData(image.width(), image.height(), BL_FORMAT_PRGB32, image.bits(), image.bytesPerLine());
|
||||||
|
|
||||||
|
BLImage blDrawImage;
|
||||||
|
blDrawImage.assignDeep(blImage);
|
||||||
|
|
||||||
|
m_blContext->blitImage(BLRect(r.x(), r.y(), r.width(), r.height()),
|
||||||
|
blDrawImage,
|
||||||
|
BLRectI(sr.x(), sr.y(), sr.width(), sr.height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
QPaintEngine::Type PDFBLPaintEngine::type() const
|
||||||
|
{
|
||||||
|
return User;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPaintEngine::PaintEngineFeatures PDFBLPaintEngine::getStaticFeatures()
|
||||||
|
{
|
||||||
|
return PrimitiveTransform | PixmapTransform | LinearGradientFill |
|
||||||
|
RadialGradientFill | ConicalGradientFill | AlphaBlend |
|
||||||
|
PorterDuff | PainterPaths | Antialiasing | ConstantOpacity |
|
||||||
|
BlendModes | PaintOutsidePaintEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BLMatrix2D PDFBLPaintEngine::getBLMatrix(QTransform transform)
|
||||||
|
{
|
||||||
|
BLMatrix2D matrix;
|
||||||
|
matrix.reset(transform.m11(), transform.m12(), transform.m21(), transform.m22(), transform.dx(), transform.dy());
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLPoint PDFBLPaintEngine::getBLPoint(const QPoint& point)
|
||||||
|
{
|
||||||
|
return BLPoint(point.x(), point.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
BLPoint PDFBLPaintEngine::getBLPoint(const QPointF& point)
|
||||||
|
{
|
||||||
|
return BLPoint(point.x(), point.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
BLRectI PDFBLPaintEngine::getBLRect(QRect rect)
|
||||||
|
{
|
||||||
|
return BLRectI(rect.x(), rect.y(), rect.width(), rect.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
BLRect PDFBLPaintEngine::getBLRect(QRectF rect)
|
||||||
|
{
|
||||||
|
return BLRect(rect.x(), rect.y(), rect.width(), rect.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
BLPath PDFBLPaintEngine::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 PDFBLPaintEngine::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<qreal> 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<double> 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 PDFBLPaintEngine::setBLBrush(BLContext& context, const QBrush& brush)
|
||||||
|
{
|
||||||
|
auto setGradientStops = [](BLGradient& blGradient, const auto& qGradient)
|
||||||
|
{
|
||||||
|
QVector<BLGradientStop> 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<const QLinearGradient*>(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<const QRadialGradient*>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PDFBLPaintEngine::loadBLFont(BLFont& font, QString fontName, PDFReal fontSize)
|
||||||
|
{
|
||||||
|
QByteArray data = PDFSystemFont::getFontData(fontName.toLatin1());
|
||||||
|
|
||||||
|
BLFontData blFontData;
|
||||||
|
if (blFontData.createFromData(data.data(), data.size()) == BL_SUCCESS)
|
||||||
|
{
|
||||||
|
BLFontFace fontFace;
|
||||||
|
if (fontFace.createFromData(blFontData, 0) == BL_SUCCESS)
|
||||||
|
{
|
||||||
|
if (font.createFromFace(fontFace, fontSize) == BL_SUCCESS)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLCompOp PDFBLPaintEngine::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
|
49
Pdf4QtLibCore/sources/pdfblpainter.h
Normal file
49
Pdf4QtLibCore/sources/pdfblpainter.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int metric(PaintDeviceMetric metric) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QImage& m_offscreenBuffer;
|
||||||
|
PDFBLPaintEngine* m_paintEngine;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pdf
|
||||||
|
|
||||||
|
#endif // PDFBLPAINTER_H
|
@ -2685,4 +2685,16 @@ CharacterInfos PDFRealizedType3FontImpl::getCharacterInfos() const
|
|||||||
return result;
|
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
|
} // namespace pdf
|
||||||
|
@ -698,6 +698,12 @@ private:
|
|||||||
std::map<QByteArray, QByteArray> m_cmaps;
|
std::map<QByteArray, QByteArray> m_cmaps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PDF4QTLIBCORESHARED_EXPORT PDFSystemFont
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QByteArray getFontData(const QByteArray& fontName);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFFONT_H
|
#endif // PDFFONT_H
|
||||||
|
@ -24,8 +24,6 @@
|
|||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
|
||||||
#include <Blend2d.h>
|
|
||||||
|
|
||||||
#include "pdfdbgheap.h"
|
#include "pdfdbgheap.h"
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
@ -623,135 +621,6 @@ void PDFPrecompiledPage::draw(QPainter* painter,
|
|||||||
painter->restore();
|
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)
|
void PDFPrecompiledPage::redact(QPainterPath redactPath, const QTransform& matrix, QColor color)
|
||||||
{
|
{
|
||||||
if (redactPath.isEmpty())
|
if (redactPath.isEmpty())
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
class BLContext;
|
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -198,18 +196,6 @@ public:
|
|||||||
PDFRenderer::Features features,
|
PDFRenderer::Features features,
|
||||||
PDFReal opacity) const;
|
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,
|
/// Redact path - remove all content intersecting given path,
|
||||||
/// and fill redact path with given color.
|
/// and fill redact path with given color.
|
||||||
/// \param redactPath Redaction path in page coordinates
|
/// \param redactPath Redaction path in page coordinates
|
||||||
|
@ -64,277 +64,5 @@ QRect PDFPainterHelper::drawBubble(QPainter* painter, QPoint point, QColor color
|
|||||||
return rectangle;
|
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<qreal> 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<double> 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<BLGradientStop> 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<const QLinearGradient*>(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<const QRadialGradient*>(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
|
} // namespace pdf
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
#include <Blend2d.h>
|
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -57,27 +55,6 @@ public:
|
|||||||
/// \param text Text inside the bubble
|
/// \param text Text inside the bubble
|
||||||
/// \param alignment Bubble alignment relative to the bubble position point
|
/// \param alignment Bubble alignment relative to the bubble position point
|
||||||
static QRect drawBubble(QPainter* painter, QPoint point, QColor color, QString text, Qt::Alignment alignment);
|
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
|
} // namespace pdf
|
||||||
|
@ -27,8 +27,6 @@
|
|||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
#include <Blend2d.h>
|
|
||||||
|
|
||||||
#include "pdfdbgheap.h"
|
#include "pdfdbgheap.h"
|
||||||
|
|
||||||
#include <execution>
|
#include <execution>
|
||||||
@ -1362,45 +1360,6 @@ void PDFMesh::paint(QPainter* painter, PDFReal alpha) const
|
|||||||
painter->restore();
|
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)
|
void PDFMesh::transform(const QTransform& matrix)
|
||||||
{
|
{
|
||||||
for (QPointF& vertex : m_vertices)
|
for (QPointF& vertex : m_vertices)
|
||||||
|
@ -29,8 +29,6 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class BLContext;
|
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
class PDFPattern;
|
class PDFPattern;
|
||||||
@ -96,11 +94,6 @@ public:
|
|||||||
/// \param alpha Opacity factor
|
/// \param alpha Opacity factor
|
||||||
void paint(QPainter* painter, PDFReal alpha) const;
|
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
|
/// Transforms the mesh according to the matrix transform
|
||||||
/// \param matrix Matrix transform to be performed
|
/// \param matrix Matrix transform to be performed
|
||||||
void transform(const QTransform& matrix);
|
void transform(const QTransform& matrix);
|
||||||
|
@ -21,13 +21,12 @@
|
|||||||
#include "pdfexecutionpolicy.h"
|
#include "pdfexecutionpolicy.h"
|
||||||
#include "pdfprogress.h"
|
#include "pdfprogress.h"
|
||||||
#include "pdfannotation.h"
|
#include "pdfannotation.h"
|
||||||
|
#include "pdfblpainter.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
|
||||||
#include <Blend2d.h>
|
|
||||||
|
|
||||||
#include "pdfdbgheap.h"
|
#include "pdfdbgheap.h"
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
@ -250,26 +249,16 @@ QImage PDFRasterizer::render(PDFInteger pageIndex,
|
|||||||
|
|
||||||
if (m_rendererEngine == RendererEngine::Blend2D)
|
if (m_rendererEngine == RendererEngine::Blend2D)
|
||||||
{
|
{
|
||||||
BLContext blContext;
|
PDFBLPaintDevice blPaintDevice(image, false);
|
||||||
BLImage blImage;
|
|
||||||
|
|
||||||
blContext.setHint(BL_CONTEXT_HINT_RENDERING_QUALITY, BL_RENDERING_QUALITY_MAX_VALUE);
|
QPainter painter(&blPaintDevice);
|
||||||
|
compiledPage->draw(&painter, page->getCropBox(), matrix, features, 1.0);
|
||||||
|
|
||||||
blImage.createFromData(image.width(), image.height(), BL_FORMAT_PRGB32, image.bits(), image.bytesPerLine());
|
if (annotationManager)
|
||||||
if (blContext.begin(blImage) == BL_SUCCESS)
|
|
||||||
{
|
{
|
||||||
blContext.clearAll();
|
QList<PDFRenderError> errors;
|
||||||
|
PDFTextLayoutGetter textLayoutGetter(nullptr, pageIndex);
|
||||||
compiledPage->draw(blContext, page->getCropBox(), matrix, features, 1.0);
|
annotationManager->drawPage(&painter, pageIndex, compiledPage, textLayoutGetter, matrix, errors);
|
||||||
|
|
||||||
if (annotationManager)
|
|
||||||
{
|
|
||||||
QList<PDFRenderError> errors;
|
|
||||||
PDFTextLayoutGetter textLayoutGetter(nullptr, pageIndex);
|
|
||||||
annotationManager->drawPage(blContext, pageIndex, compiledPage, textLayoutGetter, matrix, errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
blContext.end();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -32,8 +32,6 @@
|
|||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
|
||||||
#include <Blend2d.h>
|
|
||||||
|
|
||||||
#include "pdfdbgheap.h"
|
#include "pdfdbgheap.h"
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
@ -768,18 +766,6 @@ 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 PDFDrawWidgetProxy::getPaperColor()
|
||||||
{
|
{
|
||||||
QColor paperColor = getCMSManager()->getCurrentCMS()->getPaperColor();
|
QColor paperColor = getCMSManager()->getCurrentCMS()->getPaperColor();
|
||||||
@ -935,153 +921,6 @@ 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<PDFRenderError> 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<PDFRenderError>& pageErrors = compiledPage->getErrors();
|
|
||||||
if (!pageErrors.empty() || !drawInterfaceErrors.empty())
|
|
||||||
{
|
|
||||||
QList<PDFRenderError> errors = pageErrors;
|
|
||||||
if (!drawInterfaceErrors.isEmpty())
|
|
||||||
{
|
|
||||||
errors.append(drawInterfaceErrors);
|
|
||||||
}
|
|
||||||
Q_EMIT renderingError(item.pageIndex, qMove(errors));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage PDFDrawWidgetProxy::drawThumbnailImage(PDFInteger pageIndex, int pixelSize) const
|
QImage PDFDrawWidgetProxy::drawThumbnailImage(PDFInteger pageIndex, int pixelSize) const
|
||||||
{
|
{
|
||||||
QImage image;
|
QImage image;
|
||||||
|
@ -34,8 +34,6 @@ class QPainter;
|
|||||||
class QScrollBar;
|
class QScrollBar;
|
||||||
class QTimer;
|
class QTimer;
|
||||||
|
|
||||||
class BLContext;
|
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
class PDFProgress;
|
class PDFProgress;
|
||||||
@ -214,15 +212,6 @@ public:
|
|||||||
/// \param rect Rectangle in which the content is painted
|
/// \param rect Rectangle in which the content is painted
|
||||||
void draw(QPainter* painter, QRect rect);
|
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.
|
/// Draws the actually visible pages on the painter using the rectangle.
|
||||||
/// Rectangle is space in the widget, which is used for painting the PDF.
|
/// Rectangle is space in the widget, which is used for painting the PDF.
|
||||||
/// \param painter Painter to paint the PDF pages
|
/// \param painter Painter to paint the PDF pages
|
||||||
@ -230,13 +219,6 @@ public:
|
|||||||
/// \param features Rendering features
|
/// \param features Rendering features
|
||||||
void drawPages(QPainter* painter, QRect rect, PDFRenderer::Features 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
|
/// 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
|
/// width or height equals to pixel size and the latter size is rescaled
|
||||||
/// using the aspect ratio)
|
/// using the aspect ratio)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "pdfannotation.h"
|
#include "pdfannotation.h"
|
||||||
#include "pdfwidgetannotation.h"
|
#include "pdfwidgetannotation.h"
|
||||||
#include "pdfwidgetformmanager.h"
|
#include "pdfwidgetformmanager.h"
|
||||||
|
#include "pdfblpainter.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
@ -30,8 +31,6 @@
|
|||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include <QColorSpace>
|
#include <QColorSpace>
|
||||||
|
|
||||||
#include <Blend2d.h>
|
|
||||||
|
|
||||||
#include "pdfdbgheap.h"
|
#include "pdfdbgheap.h"
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
@ -583,33 +582,23 @@ void PDFDrawWidget::paintEvent(QPaintEvent* event)
|
|||||||
{
|
{
|
||||||
case RendererEngine::Blend2D:
|
case RendererEngine::Blend2D:
|
||||||
{
|
{
|
||||||
BLContext blContext;
|
|
||||||
BLImage blImage;
|
|
||||||
|
|
||||||
QRect rect = this->rect();
|
QRect rect = this->rect();
|
||||||
if (m_blend2DframeBuffer.size() != rect.size())
|
if (m_blend2DframeBuffer.size() != rect.size())
|
||||||
{
|
{
|
||||||
m_blend2DframeBuffer = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
|
m_blend2DframeBuffer = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
|
||||||
}
|
}
|
||||||
|
|
||||||
BLContextCreateInfo info{};
|
PDFBLPaintDevice blPaintDevice(m_blend2DframeBuffer, true);
|
||||||
info.reset();
|
QPainter blPainter;
|
||||||
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);
|
if (blPainter.begin(&blPaintDevice))
|
||||||
|
|
||||||
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(&blPainter, rect);
|
||||||
getPDFWidget()->getDrawWidgetProxy()->draw(blContext, rect);
|
blPainter.end();
|
||||||
blContext.end();
|
|
||||||
|
|
||||||
QPainter painter(this);
|
|
||||||
painter.drawImage(QPoint(0, 0), m_blend2DframeBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.drawImage(QPoint(0, 0), m_blend2DframeBuffer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,9 +539,4 @@ void PDFWidgetAnnotationManager::drawPage(QPainter* painter,
|
|||||||
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFWidgetAnnotationManager::drawPage(BLContext& context, PDFInteger pageIndex, const PDFPrecompiledPage* compiledPage, PDFTextLayoutGetter& layoutGetter, const QTransform& pagePointToDevicePointMatrix, QList<PDFRenderError>& errors) const
|
|
||||||
{
|
|
||||||
BaseClass::drawPage(context, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -57,13 +57,6 @@ public:
|
|||||||
const QTransform& pagePointToDevicePointMatrix,
|
const QTransform& pagePointToDevicePointMatrix,
|
||||||
QList<PDFRenderError>& errors) const override;
|
QList<PDFRenderError>& errors) const override;
|
||||||
|
|
||||||
virtual void drawPage(BLContext& context,
|
|
||||||
PDFInteger pageIndex,
|
|
||||||
const PDFPrecompiledPage* compiledPage,
|
|
||||||
PDFTextLayoutGetter& layoutGetter,
|
|
||||||
const QTransform& pagePointToDevicePointMatrix,
|
|
||||||
QList<PDFRenderError>& errors) const override;
|
|
||||||
|
|
||||||
/// Returns tooltip generated from annotation
|
/// Returns tooltip generated from annotation
|
||||||
virtual QString getTooltip() const override { return m_tooltip; }
|
virtual QString getTooltip() const override { return m_tooltip; }
|
||||||
|
|
||||||
|
@ -1197,7 +1197,7 @@ void PDFMagnifierTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
|||||||
if (m_mousePos != mousePos)
|
if (m_mousePos != mousePos)
|
||||||
{
|
{
|
||||||
m_mousePos = mousePos;
|
m_mousePos = mousePos;
|
||||||
getProxy()->repaintNeeded();
|
Q_EMIT getProxy()->repaintNeeded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,7 +624,7 @@ void PDFProgramController::initialize(Features features,
|
|||||||
|
|
||||||
readSettings(Settings(GeneralSettings | PluginsSettings | RecentFileSettings | CertificateSettings));
|
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->setObjectName("pdfWidget");
|
||||||
m_pdfWidget->updateCacheLimits(m_settings->getCompiledPageCacheLimit() * 1024, m_settings->getThumbnailsCacheLimit(), m_settings->getFontCacheLimit(), m_settings->getInstancedFontCacheLimit());
|
m_pdfWidget->updateCacheLimits(m_settings->getCompiledPageCacheLimit() * 1024, m_settings->getThumbnailsCacheLimit(), m_settings->getFontCacheLimit(), m_settings->getInstancedFontCacheLimit());
|
||||||
m_pdfWidget->getDrawWidgetProxy()->setProgress(m_progress);
|
m_pdfWidget->getDrawWidgetProxy()->setProgress(m_progress);
|
||||||
@ -1697,7 +1697,7 @@ void PDFProgramController::updateActionsAvailability()
|
|||||||
|
|
||||||
void PDFProgramController::onViewerSettingsChanged()
|
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->updateCacheLimits(m_settings->getCompiledPageCacheLimit() * 1024, m_settings->getThumbnailsCacheLimit(), m_settings->getFontCacheLimit(), m_settings->getInstancedFontCacheLimit());
|
||||||
m_pdfWidget->getDrawWidgetProxy()->setFeatures(m_settings->getFeatures());
|
m_pdfWidget->getDrawWidgetProxy()->setFeatures(m_settings->getFeatures());
|
||||||
m_pdfWidget->getDrawWidgetProxy()->setPreferredMeshResolutionRatio(m_settings->getPreferredMeshResolutionRatio());
|
m_pdfWidget->getDrawWidgetProxy()->setPreferredMeshResolutionRatio(m_settings->getPreferredMeshResolutionRatio());
|
||||||
|
@ -44,8 +44,6 @@ void PDFViewerSettings::readSettings(QSettings& settings, const pdf::PDFCMSSetti
|
|||||||
m_settings.m_directory = settings.value("defaultDirectory", QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).toString();
|
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_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::Blend2D)).toInt());
|
m_settings.m_rendererEngine = static_cast<pdf::RendererEngine>(settings.value("renderingEngine", static_cast<int>(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();
|
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_preferredMeshResolutionRatio = settings.value("preferredMeshResolutionRatio", defaultSettings.m_preferredMeshResolutionRatio).toDouble();
|
||||||
m_settings.m_minimalMeshResolutionRatio = settings.value("minimalMeshResolutionRatio", defaultSettings.m_minimalMeshResolutionRatio).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("defaultDirectory", m_settings.m_directory);
|
||||||
settings.setValue("rendererFeaturesv2", static_cast<int>(m_settings.m_features));
|
settings.setValue("rendererFeaturesv2", static_cast<int>(m_settings.m_features));
|
||||||
settings.setValue("renderingEngine", static_cast<int>(m_settings.m_rendererEngine));
|
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("prefetchPages", m_settings.m_prefetchPages);
|
||||||
settings.setValue("preferredMeshResolutionRatio", m_settings.m_preferredMeshResolutionRatio);
|
settings.setValue("preferredMeshResolutionRatio", m_settings.m_preferredMeshResolutionRatio);
|
||||||
settings.setValue("minimalMeshResolutionRatio", m_settings.m_minimalMeshResolutionRatio);
|
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)
|
void PDFViewerSettings::setPreferredMeshResolutionRatio(pdf::PDFReal preferredMeshResolutionRatio)
|
||||||
{
|
{
|
||||||
if (m_settings.m_preferredMeshResolutionRatio != preferredMeshResolutionRatio)
|
if (m_settings.m_preferredMeshResolutionRatio != preferredMeshResolutionRatio)
|
||||||
@ -272,8 +254,6 @@ void PDFViewerSettings::setColorTolerance(pdf::PDFReal colorTolerance)
|
|||||||
PDFViewerSettings::Settings::Settings() :
|
PDFViewerSettings::Settings::Settings() :
|
||||||
m_features(pdf::PDFRenderer::getDefaultFeatures()),
|
m_features(pdf::PDFRenderer::getDefaultFeatures()),
|
||||||
m_rendererEngine(pdf::RendererEngine::Blend2D),
|
m_rendererEngine(pdf::RendererEngine::Blend2D),
|
||||||
m_multisampleAntialiasing(true),
|
|
||||||
m_rendererSamples(16),
|
|
||||||
m_prefetchPages(true),
|
m_prefetchPages(true),
|
||||||
m_preferredMeshResolutionRatio(0.02),
|
m_preferredMeshResolutionRatio(0.02),
|
||||||
m_minimalMeshResolutionRatio(0.005),
|
m_minimalMeshResolutionRatio(0.005),
|
||||||
|
@ -111,11 +111,7 @@ public:
|
|||||||
pdf::RendererEngine getRendererEngine() const;
|
pdf::RendererEngine getRendererEngine() const;
|
||||||
void setRendererEngine(pdf::RendererEngine rendererEngine);
|
void setRendererEngine(pdf::RendererEngine rendererEngine);
|
||||||
|
|
||||||
int getRendererSamples() const;
|
|
||||||
void setRendererSamples(int rendererSamples);
|
|
||||||
|
|
||||||
bool isPagePrefetchingEnabled() const { return m_settings.m_prefetchPages; }
|
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; }
|
pdf::PDFReal getPreferredMeshResolutionRatio() const { return m_settings.m_preferredMeshResolutionRatio; }
|
||||||
void setPreferredMeshResolutionRatio(pdf::PDFReal preferredMeshResolutionRatio);
|
void setPreferredMeshResolutionRatio(pdf::PDFReal preferredMeshResolutionRatio);
|
||||||
|
@ -105,11 +105,6 @@ PDFViewerSettingsDialog::PDFViewerSettingsDialog(const PDFViewerSettings::Settin
|
|||||||
ui->renderingEngineComboBox->addItem(tr("Software | QPainter"), static_cast<int>(pdf::RendererEngine::QPainter));
|
ui->renderingEngineComboBox->addItem(tr("Software | QPainter"), static_cast<int>(pdf::RendererEngine::QPainter));
|
||||||
ui->renderingEngineComboBox->addItem(tr("Software | Blend2D | Multithreaded"), static_cast<int>(pdf::RendererEngine::Blend2D));
|
ui->renderingEngineComboBox->addItem(tr("Software | Blend2D | Multithreaded"), static_cast<int>(pdf::RendererEngine::Blend2D));
|
||||||
|
|
||||||
for (int i : { 1, 2, 4, 8, 16 })
|
|
||||||
{
|
|
||||||
ui->multisampleAntialiasingSamplesCountComboBox->addItem(QString::number(i), i);
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->multithreadingComboBox->addItem(tr("Single thread"), static_cast<int>(pdf::PDFExecutionPolicy::Strategy::SingleThreaded));
|
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));
|
ui->multithreadingComboBox->addItem(tr("Multithreading (load balanced)"), static_cast<int>(pdf::PDFExecutionPolicy::Strategy::PageMultithreaded));
|
||||||
ui->multithreadingComboBox->addItem(tr("Multithreading (maximum threads)"), static_cast<int>(pdf::PDFExecutionPolicy::Strategy::AlwaysMultithreaded));
|
ui->multithreadingComboBox->addItem(tr("Multithreading (maximum threads)"), static_cast<int>(pdf::PDFExecutionPolicy::Strategy::AlwaysMultithreaded));
|
||||||
@ -409,14 +404,6 @@ void PDFViewerSettingsDialog::saveData()
|
|||||||
{
|
{
|
||||||
m_settings.m_rendererEngine = static_cast<pdf::RendererEngine>(ui->renderingEngineComboBox->currentData().toInt());
|
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)
|
else if (sender == ui->prefetchPagesCheckBox)
|
||||||
{
|
{
|
||||||
m_settings.m_prefetchPages = ui->prefetchPagesCheckBox->isChecked();
|
m_settings.m_prefetchPages = ui->prefetchPagesCheckBox->isChecked();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user