Blending output with paper

This commit is contained in:
Jakub Melka 2021-02-11 19:42:55 +01:00
parent e743761ce4
commit 3da8cf2252
3 changed files with 92 additions and 59 deletions

View File

@ -650,7 +650,75 @@ const PDFFloatBitmap& PDFTransparencyRenderer::endPaint()
return *getImmediateBackdrop();
}
QImage PDFTransparencyRenderer::toImage(bool use16Bit) const
QImage PDFTransparencyRenderer::toImageImpl(const PDFFloatBitmapWithColorSpace& floatImage, bool use16Bit) const
{
QImage image;
Q_ASSERT(floatImage.getPixelFormat().getProcessColorChannelCount() == 3);
if (use16Bit)
{
image = QImage(int(floatImage.getWidth()), int(floatImage.getHeight()), QImage::Format_RGBA64);
const PDFPixelFormat pixelFormat = floatImage.getPixelFormat();
const int height = image.height();
const int width = image.width();
const float scale = std::numeric_limits<quint16>::max();
const uint8_t channelStart = pixelFormat.getProcessColorChannelIndexStart();
const uint8_t channelEnd = pixelFormat.getProcessColorChannelIndexEnd();
const uint8_t opacityChannel = pixelFormat.getOpacityChannelIndex();
for (int y = 0; y < height; ++y)
{
quint16* pixels = reinterpret_cast<quint16*>(image.bits() + y * image.bytesPerLine());
for (int x = 0; x < width; ++x)
{
PDFConstColorBuffer colorBuffer = floatImage.getPixel(x, y);
for (uint8_t channel = channelStart; channel < channelEnd; ++channel)
{
*pixels++ = quint16(colorBuffer[channel] * scale);
}
*pixels++ = quint16(colorBuffer[opacityChannel] * scale);
}
}
}
else
{
image = QImage(int(floatImage.getWidth()), int(floatImage.getHeight()), QImage::Format_RGBA8888);
const PDFPixelFormat pixelFormat = floatImage.getPixelFormat();
const int height = image.height();
const int width = image.width();
const float scale = std::numeric_limits<quint8>::max();
const uint8_t channelStart = pixelFormat.getProcessColorChannelIndexStart();
const uint8_t channelEnd = pixelFormat.getProcessColorChannelIndexEnd();
const uint8_t opacityChannel = pixelFormat.getOpacityChannelIndex();
for (int y = 0; y < height; ++y)
{
quint8* pixels = reinterpret_cast<quint8*>(image.bits() + y * image.bytesPerLine());
for (int x = 0; x < width; ++x)
{
PDFConstColorBuffer colorBuffer = floatImage.getPixel(x, y);
for (uint8_t channel = channelStart; channel < channelEnd; ++channel)
{
*pixels++ = quint8(colorBuffer[channel] * scale);
}
*pixels++ = quint8(colorBuffer[opacityChannel] * scale);
}
}
}
return image;
}
QImage PDFTransparencyRenderer::toImage(bool use16Bit, bool usePaper, PDFRGB paperColor) const
{
QImage image;
@ -660,64 +728,24 @@ QImage PDFTransparencyRenderer::toImage(bool use16Bit) const
const PDFFloatBitmapWithColorSpace& floatImage = m_transparencyGroupDataStack.back().immediateBackdrop;
Q_ASSERT(floatImage.getPixelFormat().hasOpacityChannel());
if (use16Bit)
if (!usePaper)
{
image = QImage(int(floatImage.getWidth()), int(floatImage.getHeight()), QImage::Format_RGBA64);
const PDFPixelFormat pixelFormat = floatImage.getPixelFormat();
const int height = image.height();
const int width = image.width();
const float scale = std::numeric_limits<quint16>::max();
const uint8_t channelStart = pixelFormat.getProcessColorChannelIndexStart();
const uint8_t channelEnd = pixelFormat.getProcessColorChannelIndexEnd();
const uint8_t opacityChannel = pixelFormat.getOpacityChannelIndex();
for (int y = 0; y < height; ++y)
{
quint16* pixels = reinterpret_cast<quint16*>(image.bits() + y * image.bytesPerLine());
for (int x = 0; x < width; ++x)
{
PDFConstColorBuffer colorBuffer = floatImage.getPixel(x, y);
for (uint8_t channel = channelStart; channel < channelEnd; ++channel)
{
*pixels++ = quint16(colorBuffer[channel] * scale);
}
*pixels++ = quint16(colorBuffer[opacityChannel] * scale);
}
}
return toImageImpl(floatImage, use16Bit);
}
else
{
image = QImage(int(floatImage.getWidth()), int(floatImage.getHeight()), QImage::Format_RGBA8888);
const PDFPixelFormat pixelFormat = floatImage.getPixelFormat();
const int height = image.height();
const int width = image.width();
const float scale = std::numeric_limits<quint8>::max();
const uint8_t channelStart = pixelFormat.getProcessColorChannelIndexStart();
const uint8_t channelEnd = pixelFormat.getProcessColorChannelIndexEnd();
const uint8_t opacityChannel = pixelFormat.getOpacityChannelIndex();
PDFFloatBitmapWithColorSpace paperImage(floatImage.getWidth(), floatImage.getHeight(), floatImage.getPixelFormat(), floatImage.getColorSpace());
paperImage.makeOpaque();
paperImage.fillChannel(0, paperColor[0]);
paperImage.fillChannel(1, paperColor[1]);
paperImage.fillChannel(2, paperColor[2]);
for (int y = 0; y < height; ++y)
{
quint8* pixels = reinterpret_cast<quint8*>(image.bits() + y * image.bytesPerLine());
PDFFloatBitmap softMask(paperImage.getWidth(), paperImage.getHeight(), PDFPixelFormat::createOpacityMask());
softMask.makeOpaque();
for (int x = 0; x < width; ++x)
{
PDFConstColorBuffer colorBuffer = floatImage.getPixel(x, y);
QRect blendRegion(0, 0, floatImage.getWidth(), floatImage.getHeight());
PDFFloatBitmapWithColorSpace::blend(floatImage, paperImage, paperImage, paperImage, softMask, false, 1.0f, BlendMode::Normal, false, 0xFFFF, PDFFloatBitmap::OverprintMode::NoOveprint, blendRegion);
for (uint8_t channel = channelStart; channel < channelEnd; ++channel)
{
*pixels++ = quint8(colorBuffer[channel] * scale);
}
*pixels++ = quint8(colorBuffer[opacityChannel] * scale);
}
}
}
return toImageImpl(paperImage, use16Bit);
}
return image;

View File

@ -214,10 +214,10 @@ public:
OverprintMode overprintMode,
QRect blendRegion);
private:
void fillProcessColorChannels(PDFColorComponent value);
void fillChannel(size_t channel, PDFColorComponent value);
private:
PDFPixelFormat m_format;
std::size_t m_width;
std::size_t m_height;
@ -443,9 +443,11 @@ public:
/// This function should be called only after call to \p endPaint. After painting,
/// when it is finished, the result float image can be converted to QImage with
/// this function, but only, if the float image is RGB. If error occurs, empty
/// image is returned.
/// \param use16bit
QImage toImage(bool use16Bit) const;
/// image is returned. Also, result image can be painted onto opaque paper
/// with paper color \p paperColor.
/// \param use16bit Produce 16-bit image instead of standard 8-bit
/// \param usePaper Blend image with opaque paper, with color \p paperColor
QImage toImage(bool use16Bit, bool usePaper = false, PDFRGB paperColor = PDFRGB()) const;
virtual void performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule) override;
virtual void performClipping(const QPainterPath& path, Qt::FillRule fillRule) override;
@ -501,6 +503,9 @@ private:
PDFMappedColor createMappedColor(const PDFColor& sourceColor,
const PDFAbstractColorSpace* sourceColorSpace);
/// Converts RGB bitmap to the image.
QImage toImageImpl(const PDFFloatBitmapWithColorSpace& floatImage, bool use16Bit) const;
PDFFloatBitmapWithColorSpace* getInitialBackdrop();
PDFFloatBitmapWithColorSpace* getImmediateBackdrop();
PDFFloatBitmapWithColorSpace* getBackdrop();

View File

@ -26,7 +26,7 @@ namespace pdfplugin
{
OutputPreviewDialog::OutputPreviewDialog(const pdf::PDFDocument* document, pdf::PDFWidget* widget, QWidget* parent) :
QDialog(parent),
QDialog(parent, Qt::Dialog | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint),
ui(new Ui::OutputPreviewDialog),
m_inkMapper(document),
m_document(document),
@ -80,7 +80,7 @@ void OutputPreviewDialog::updateImage()
renderer.processContents();
renderer.endPaint();
QImage image = renderer.toImage(false);
QImage image = renderer.toImage(false, true, pdf::PDFRGB{ 1.0f, 1.0f, 1.0f });
ui->imageLabel->setPixmap(QPixmap::fromImage(image));
}