mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Issue #123: Blend2D painting implementation
This commit is contained in:
@ -32,8 +32,6 @@
|
||||
#include <QScreen>
|
||||
#include <QGuiApplication>
|
||||
|
||||
#include <Blend2d.h>
|
||||
|
||||
#include "pdfdbgheap.h"
|
||||
|
||||
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 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 image;
|
||||
|
@ -34,8 +34,6 @@ class QPainter;
|
||||
class QScrollBar;
|
||||
class QTimer;
|
||||
|
||||
class BLContext;
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFProgress;
|
||||
@ -214,15 +212,6 @@ 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
|
||||
@ -230,13 +219,6 @@ 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)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "pdfannotation.h"
|
||||
#include "pdfwidgetannotation.h"
|
||||
#include "pdfwidgetformmanager.h"
|
||||
#include "pdfblpainter.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QGridLayout>
|
||||
@ -30,8 +31,6 @@
|
||||
#include <QPixmapCache>
|
||||
#include <QColorSpace>
|
||||
|
||||
#include <Blend2d.h>
|
||||
|
||||
#include "pdfdbgheap.h"
|
||||
|
||||
namespace pdf
|
||||
@ -583,33 +582,23 @@ void PDFDrawWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
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();
|
||||
PDFBLPaintDevice blPaintDevice(m_blend2DframeBuffer, true);
|
||||
QPainter blPainter;
|
||||
|
||||
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)
|
||||
if (blPainter.begin(&blPaintDevice))
|
||||
{
|
||||
blContext.clearAll();
|
||||
getPDFWidget()->getDrawWidgetProxy()->draw(blContext, rect);
|
||||
blContext.end();
|
||||
|
||||
QPainter painter(this);
|
||||
painter.drawImage(QPoint(0, 0), m_blend2DframeBuffer);
|
||||
getPDFWidget()->getDrawWidgetProxy()->draw(&blPainter, rect);
|
||||
blPainter.end();
|
||||
}
|
||||
|
||||
QPainter painter(this);
|
||||
painter.drawImage(QPoint(0, 0), m_blend2DframeBuffer);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -539,9 +539,4 @@ 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<PDFRenderError>& errors) const
|
||||
{
|
||||
BaseClass::drawPage(context, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -57,13 +57,6 @@ public:
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
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
|
||||
virtual QString getTooltip() const override { return m_tooltip; }
|
||||
|
||||
|
@ -1197,7 +1197,7 @@ void PDFMagnifierTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
if (m_mousePos != mousePos)
|
||||
{
|
||||
m_mousePos = mousePos;
|
||||
getProxy()->repaintNeeded();
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user