Draw buffer commiting

This commit is contained in:
Jakub Melka
2021-02-07 18:59:39 +01:00
parent 6a9cc5c5d6
commit f0b1707d12
4 changed files with 95 additions and 19 deletions

View File

@ -149,7 +149,8 @@ void PDFFloatBitmap::blend(const PDFFloatBitmap& source,
BlendMode mode, BlendMode mode,
bool knockoutGroup, bool knockoutGroup,
uint32_t activeColorChannels, uint32_t activeColorChannels,
OverprintMode overprintMode) OverprintMode overprintMode,
QRect blendRegion)
{ {
Q_ASSERT(source.getWidth() == target.getWidth()); Q_ASSERT(source.getWidth() == target.getWidth());
Q_ASSERT(source.getHeight() == target.getHeight()); Q_ASSERT(source.getHeight() == target.getHeight());
@ -158,8 +159,11 @@ void PDFFloatBitmap::blend(const PDFFloatBitmap& source,
Q_ASSERT(source.getHeight() == softMask.getHeight()); Q_ASSERT(source.getHeight() == softMask.getHeight());
Q_ASSERT(softMask.getPixelFormat() == PDFPixelFormat::createOpacityMask()); Q_ASSERT(softMask.getPixelFormat() == PDFPixelFormat::createOpacityMask());
const size_t width = source.getWidth(); Q_ASSERT(blendRegion.left() >= 0);
const size_t height = source.getHeight(); Q_ASSERT(blendRegion.top() >= 0);
Q_ASSERT(blendRegion.right() < source.getWidth());
Q_ASSERT(blendRegion.bottom() < source.getHeight());
const PDFPixelFormat pixelFormat = source.getPixelFormat(); const PDFPixelFormat pixelFormat = source.getPixelFormat();
const uint8_t shapeChannel = pixelFormat.getShapeChannelIndex(); const uint8_t shapeChannel = pixelFormat.getShapeChannelIndex();
const uint8_t opacityChannel = pixelFormat.getOpacityChannelIndex(); const uint8_t opacityChannel = pixelFormat.getOpacityChannelIndex();
@ -256,9 +260,9 @@ void PDFFloatBitmap::blend(const PDFFloatBitmap& source,
} }
} }
for (size_t x = 0; x < width; ++x) for (size_t x = blendRegion.left(); x <= blendRegion.right(); ++x)
{ {
for (size_t y = 0; y < height; ++y) for (size_t y = blendRegion.top(); y <= blendRegion.bottom(); ++y)
{ {
PDFConstColorBuffer sourceColor = source.getPixel(x, y); PDFConstColorBuffer sourceColor = source.getPixel(x, y);
PDFColorBuffer targetColor = target.getPixel(x, y); PDFColorBuffer targetColor = target.getPixel(x, y);
@ -600,6 +604,8 @@ void PDFTransparencyRenderer::beginPaint(QSize pixelSize)
m_transparencyGroupDataStack.clear(); m_transparencyGroupDataStack.clear();
m_painterStateStack.push(PDFTransparencyPainterState()); m_painterStateStack.push(PDFTransparencyPainterState());
m_painterStateStack.top().softMask = PDFFloatBitmap(pixelSize.width(), pixelSize.height(), PDFPixelFormat::createOpacityMask());
m_painterStateStack.top().softMask.makeOpaque();
PDFPixelFormat pixelFormat = PDFPixelFormat::createFormat(uint8_t(m_deviceColorSpace->getColorComponentCount()), PDFPixelFormat pixelFormat = PDFPixelFormat::createFormat(uint8_t(m_deviceColorSpace->getColorComponentCount()),
uint8_t(m_inkMapper->getActiveSpotColorCount()), uint8_t(m_inkMapper->getActiveSpotColorCount()),
@ -719,6 +725,8 @@ QImage PDFTransparencyRenderer::toImage(bool use16Bit) const
void PDFTransparencyRenderer::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule) void PDFTransparencyRenderer::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule)
{ {
Q_UNUSED(fillRule);
PDFPainterPathSampler clipSampler(m_painterStateStack.top().clipPath, m_settings.samplesCount, 1.0f); PDFPainterPathSampler clipSampler(m_painterStateStack.top().clipPath, m_settings.samplesCount, 1.0f);
QMatrix worldMatrix = getCurrentWorldMatrix(); QMatrix worldMatrix = getCurrentWorldMatrix();
@ -776,7 +784,7 @@ void PDFTransparencyRenderer::performPathPainting(const QPainterPath& path, bool
} }
m_drawBuffer.markActiveColors(fillColor.activeChannels); m_drawBuffer.markActiveColors(fillColor.activeChannels);
m_drawBuffer.modify(fillRect); m_drawBuffer.modify(fillRect, true, false);
} }
} }
@ -784,12 +792,12 @@ void PDFTransparencyRenderer::performPathPainting(const QPainterPath& path, bool
{ {
// We must stroke the path. // We must stroke the path.
QPainterPathStroker stroker; QPainterPathStroker stroker;
stroker.setCapStyle(m_graphicState.getLineCapStyle()); stroker.setCapStyle(getGraphicState()->getLineCapStyle());
stroker.setWidth(m_graphicState.getLineWidth()); stroker.setWidth(getGraphicState()->getLineWidth());
stroker.setMiterLimit(m_graphicState.getMitterLimit()); stroker.setMiterLimit(getGraphicState()->getMitterLimit());
stroker.setJoinStyle(m_graphicState.getLineJoinStyle()); stroker.setJoinStyle(getGraphicState()->getLineJoinStyle());
const PDFLineDashPattern& lineDashPattern = m_graphicState.getLineDashPattern(); const PDFLineDashPattern& lineDashPattern = getGraphicState()->getLineDashPattern();
if (!lineDashPattern.isSolid()) if (!lineDashPattern.isSolid())
{ {
stroker.setDashPattern(QVector<PDFReal>::fromStdVector(lineDashPattern.getDashArray())); stroker.setDashPattern(QVector<PDFReal>::fromStdVector(lineDashPattern.getDashArray()));
@ -834,7 +842,7 @@ void PDFTransparencyRenderer::performPathPainting(const QPainterPath& path, bool
} }
m_drawBuffer.markActiveColors(strokeColor.activeChannels); m_drawBuffer.markActiveColors(strokeColor.activeChannels);
m_drawBuffer.modify(strokeRect); m_drawBuffer.modify(strokeRect, false, true);
} }
} }
@ -983,7 +991,8 @@ void PDFTransparencyRenderer::performEndTransparencyGroup(ProcessOrder order, co
sourceData.immediateBackdrop.convertToColorSpace(getCMS(), targetData.renderingIntent, targetData.blendColorSpace, this); sourceData.immediateBackdrop.convertToColorSpace(getCMS(), targetData.renderingIntent, targetData.blendColorSpace, this);
PDFFloatBitmap::blend(sourceData.immediateBackdrop, targetData.immediateBackdrop, *getBackdrop(), *getInitialBackdrop(), sourceData.softMask, PDFFloatBitmap::blend(sourceData.immediateBackdrop, targetData.immediateBackdrop, *getBackdrop(), *getInitialBackdrop(), sourceData.softMask,
sourceData.alphaIsShape, sourceData.alphaFill, BlendMode::Normal, targetData.group.knockout, 0xFFFF, PDFFloatBitmap::OverprintMode::NoOveprint); sourceData.alphaIsShape, sourceData.alphaFill, BlendMode::Normal, targetData.group.knockout, 0xFFFF,
PDFFloatBitmap::OverprintMode::NoOveprint, getPaintRect());
// Create draw buffer // Create draw buffer
PDFFloatBitmapWithColorSpace* backdrop = getImmediateBackdrop(); PDFFloatBitmapWithColorSpace* backdrop = getImmediateBackdrop();
@ -1088,6 +1097,28 @@ PDFFloatBitmapWithColorSpace* PDFTransparencyRenderer::getBackdrop()
} }
} }
const PDFFloatBitmapWithColorSpace* PDFTransparencyRenderer::getInitialBackdrop() const
{
return &m_transparencyGroupDataStack.back().initialBackdrop;
}
const PDFFloatBitmapWithColorSpace* PDFTransparencyRenderer::getImmediateBackdrop() const
{
return &m_transparencyGroupDataStack.back().immediateBackdrop;
}
const PDFFloatBitmapWithColorSpace* PDFTransparencyRenderer::getBackdrop() const
{
if (isTransparencyGroupKnockout())
{
return getInitialBackdrop();
}
else
{
return getImmediateBackdrop();
}
}
const PDFColorSpacePointer& PDFTransparencyRenderer::getBlendColorSpace() const const PDFColorSpacePointer& PDFTransparencyRenderer::getBlendColorSpace() const
{ {
return m_transparencyGroupDataStack.back().blendColorSpace; return m_transparencyGroupDataStack.back().blendColorSpace;
@ -1224,10 +1255,10 @@ PDFTransparencyRenderer::PDFMappedColor PDFTransparencyRenderer::getMappedFillCo
QRect PDFTransparencyRenderer::getPaintRect() const QRect PDFTransparencyRenderer::getPaintRect() const
{ {
return QRect(0, 0, getBackdrop()->getWidth(), getBackdrop()->getHeight()); return QRect(0, 0, int(getBackdrop()->getWidth()), int(getBackdrop()->getHeight()));
} }
QRect PDFTransparencyRenderer::getActualFillRect(QRectF& fillRect) const QRect PDFTransparencyRenderer::getActualFillRect(const QRectF& fillRect) const
{ {
int xLeft = qFloor(fillRect.left()) - 1; int xLeft = qFloor(fillRect.left()) - 1;
int xRight = qCeil(fillRect.right()) + 1; int xRight = qCeil(fillRect.right()) + 1;
@ -1242,6 +1273,22 @@ void PDFTransparencyRenderer::flushDrawBuffer()
{ {
if (m_drawBuffer.isModified()) if (m_drawBuffer.isModified())
{ {
PDFOverprintMode overprintMode = getGraphicState()->getOverprintMode();
const bool useOverprint = (overprintMode.overprintFilling && m_drawBuffer.isContainsFilling()) ||
(overprintMode.overprintStroking && m_drawBuffer.isContainsStroking());
PDFFloatBitmap::OverprintMode selectedOverprintMode = PDFFloatBitmap::OverprintMode::NoOveprint;
if (useOverprint)
{
selectedOverprintMode = overprintMode.overprintMode == 0 ? PDFFloatBitmap::OverprintMode::Overprint_Mode_0
: PDFFloatBitmap::OverprintMode::Overprint_Mode_1;
}
PDFFloatBitmap::blend(m_drawBuffer, *getImmediateBackdrop(), *getBackdrop(), *getInitialBackdrop(), m_painterStateStack.top().softMask,
getGraphicState()->getAlphaIsShape(), 1.0f, getGraphicState()->getBlendMode(), isTransparencyGroupKnockout(),
m_drawBuffer.getActiveColors(), selectedOverprintMode, m_drawBuffer.getModifiedRect());
m_drawBuffer.clear(); m_drawBuffer.clear();
} }
} }
@ -1547,12 +1594,16 @@ void PDFDrawBuffer::clear()
} }
m_activeColors = 0; m_activeColors = 0;
m_containsFilling = false;
m_containsStroking = false;
m_modifiedRect = QRect(); m_modifiedRect = QRect();
} }
void PDFDrawBuffer::modify(QRect rect) void PDFDrawBuffer::modify(QRect rect, bool containsFilling, bool containsStroking)
{ {
m_modifiedRect = m_modifiedRect.united(rect); m_modifiedRect = m_modifiedRect.united(rect);
m_containsFilling |= containsFilling;
m_containsStroking |= containsStroking;
} }
} // namespace pdf } // namespace pdf

View File

@ -200,6 +200,7 @@ public:
/// \param mode Blend mode /// \param mode Blend mode
/// \param activeColorChannels Active color channels /// \param activeColorChannels Active color channels
/// \param overprintMode Overprint mode /// \param overprintMode Overprint mode
/// \param blendRegion Blend region
static void blend(const PDFFloatBitmap& source, static void blend(const PDFFloatBitmap& source,
PDFFloatBitmap& target, PDFFloatBitmap& target,
const PDFFloatBitmap& backdrop, const PDFFloatBitmap& backdrop,
@ -210,7 +211,8 @@ public:
BlendMode mode, BlendMode mode,
bool knockoutGroup, bool knockoutGroup,
uint32_t activeColorChannels, uint32_t activeColorChannels,
OverprintMode overprintMode); OverprintMode overprintMode,
QRect blendRegion);
private: private:
void fillProcessColorChannels(PDFColorComponent value); void fillProcessColorChannels(PDFColorComponent value);
@ -354,13 +356,24 @@ public:
void clear(); void clear();
/// Marks given area as modified /// Marks given area as modified
void modify(QRect rect); void modify(QRect rect, bool containsFilling, bool containsStroking);
/// Returns true, if draw buffer is modified and needs to be flushed /// Returns true, if draw buffer is modified and needs to be flushed
bool isModified() const { return m_modifiedRect.isValid(); } bool isModified() const { return m_modifiedRect.isValid(); }
/// Returns active colors
uint32_t getActiveColors() const { return m_activeColors; }
/// Returns modified rectangle
QRect getModifiedRect() const { return m_modifiedRect; }
bool isContainsFilling() const { return m_containsFilling; }
bool isContainsStroking() const { return m_containsStroking; }
private: private:
uint32_t m_activeColors = 0; uint32_t m_activeColors = 0;
bool m_containsFilling = false;
bool m_containsStroking = false;
QRect m_modifiedRect; QRect m_modifiedRect;
}; };
@ -451,6 +464,7 @@ private:
struct PDFTransparencyPainterState struct PDFTransparencyPainterState
{ {
QPainterPath clipPath; ///< Clipping path in device state coordinates QPainterPath clipPath; ///< Clipping path in device state coordinates
PDFFloatBitmap softMask;
}; };
struct PDFMappedColor struct PDFMappedColor
@ -473,6 +487,9 @@ private:
PDFFloatBitmapWithColorSpace* getInitialBackdrop(); PDFFloatBitmapWithColorSpace* getInitialBackdrop();
PDFFloatBitmapWithColorSpace* getImmediateBackdrop(); PDFFloatBitmapWithColorSpace* getImmediateBackdrop();
PDFFloatBitmapWithColorSpace* getBackdrop(); PDFFloatBitmapWithColorSpace* getBackdrop();
const PDFFloatBitmapWithColorSpace* getInitialBackdrop() const;
const PDFFloatBitmapWithColorSpace* getImmediateBackdrop() const;
const PDFFloatBitmapWithColorSpace* getBackdrop() const;
const PDFColorSpacePointer& getBlendColorSpace() const; const PDFColorSpacePointer& getBlendColorSpace() const;
PDFTransparencyPainterState* getPainterState() { return &m_painterStateStack.top(); } PDFTransparencyPainterState* getPainterState() { return &m_painterStateStack.top(); }
@ -492,7 +509,7 @@ private:
/// Returns fill area from fill rectangle /// Returns fill area from fill rectangle
/// \param fillRect Fill rectangle /// \param fillRect Fill rectangle
QRect getActualFillRect(QRectF& fillRect) const; QRect getActualFillRect(const QRectF& fillRect) const;
/// Flushes draw buffer /// Flushes draw buffer
void flushDrawBuffer(); void flushDrawBuffer();

View File

@ -47,6 +47,12 @@ OutputPreviewDialog::~OutputPreviewDialog()
delete ui; delete ui;
} }
void OutputPreviewDialog::resizeEvent(QResizeEvent* event)
{
QDialog::resizeEvent(event);
updateImage();
}
void OutputPreviewDialog::updateImage() void OutputPreviewDialog::updateImage()
{ {
const pdf::PDFPage* page = m_document->getCatalog()->getPage(ui->pageIndexScrollBar->value() - 1); const pdf::PDFPage* page = m_document->getCatalog()->getPage(ui->pageIndexScrollBar->value() - 1);

View File

@ -40,6 +40,8 @@ public:
explicit OutputPreviewDialog(const pdf::PDFDocument* document, pdf::PDFWidget* widget, QWidget* parent); explicit OutputPreviewDialog(const pdf::PDFDocument* document, pdf::PDFWidget* widget, QWidget* parent);
virtual ~OutputPreviewDialog() override; virtual ~OutputPreviewDialog() override;
virtual void resizeEvent(QResizeEvent* event) override;
private: private:
void updateImage(); void updateImage();