Create bitmap from rendered image

This commit is contained in:
Jakub Melka 2021-02-06 18:49:37 +01:00
parent 3fdbcfb4c5
commit 33df634a15
3 changed files with 125 additions and 4 deletions

View File

@ -104,6 +104,16 @@ void PDFFloatBitmap::makeOpaque()
}
}
void PDFFloatBitmap::makeColorBlack()
{
fillProcessColorChannels(m_format.hasProcessColorsSubtractive() ? 1.0 : 0.0);
}
void PDFFloatBitmap::makeColorWhite()
{
fillProcessColorChannels(m_format.hasProcessColorsSubtractive() ? 0.0 : 1.0);
}
size_t PDFFloatBitmap::getPixelIndex(size_t x, size_t y) const
{
return (y * m_width + x) * m_pixelSize;
@ -440,6 +450,23 @@ void PDFFloatBitmap::blend(const PDFFloatBitmap& source,
}
}
void PDFFloatBitmap::fillProcessColorChannels(PDFColorComponent value)
{
if (!m_format.hasProcessColors())
{
// No process colors
return;
}
const uint8_t channelStart = m_format.getProcessColorChannelIndexStart();
const uint8_t channelEnd = m_format.getProcessColorChannelIndexEnd();
for (PDFColorComponent* pixel = begin(); pixel != end(); pixel += m_pixelSize)
{
std::fill(pixel + channelStart, pixel + channelEnd, value);
}
}
void PDFFloatBitmap::fillChannel(size_t channel, PDFColorComponent value)
{
// Do we have just one channel?
@ -571,12 +598,16 @@ void PDFTransparencyRenderer::beginPaint(QSize pixelSize)
Q_ASSERT(m_deviceColorSpace);
Q_ASSERT(m_processColorSpace);
m_transparencyGroupDataStack.clear();
m_painterStateStack.push(PDFTransparencyPainterState());
PDFPixelFormat pixelFormat = PDFPixelFormat::createFormat(uint8_t(m_deviceColorSpace->getColorComponentCount()),
uint8_t(m_inkMapper->getActiveSpotColorCount()),
true, m_deviceColorSpace->getColorComponentCount() == 4);
PDFFloatBitmapWithColorSpace paper = PDFFloatBitmapWithColorSpace(pixelSize.width(), pixelSize.height(), pixelFormat, m_deviceColorSpace);
paper.makeColorWhite();
PDFTransparencyGroupPainterData deviceGroup;
deviceGroup.alphaIsShape = getGraphicState()->getAlphaIsShape();
deviceGroup.alphaStroke = getGraphicState()->getAlphaStroking();
@ -584,7 +615,7 @@ void PDFTransparencyRenderer::beginPaint(QSize pixelSize)
deviceGroup.blendMode = getGraphicState()->getBlendMode();
deviceGroup.blackPointCompensationMode = getGraphicState()->getBlackPointCompensationMode();
deviceGroup.renderingIntent = RenderingIntent::RelativeColorimetric;
deviceGroup.initialBackdrop = PDFFloatBitmapWithColorSpace(pixelSize.width(), pixelSize.height(), pixelFormat, m_deviceColorSpace);
deviceGroup.initialBackdrop = qMove(paper);
deviceGroup.immediateBackdrop = deviceGroup.initialBackdrop;
deviceGroup.blendColorSpace = m_deviceColorSpace;
@ -613,10 +644,82 @@ const PDFFloatBitmap& PDFTransparencyRenderer::endPaint()
return *getImmediateBackdrop();
}
QImage PDFTransparencyRenderer::toImage(bool use16Bit) const
{
QImage image;
if (m_transparencyGroupDataStack.size() == 1 && // We have finished the painting
m_transparencyGroupDataStack.back().immediateBackdrop.getPixelFormat().getProcessColorChannelCount() == 3) // We have exactly three process colors (RGB)
{
const PDFFloatBitmapWithColorSpace& floatImage = m_transparencyGroupDataStack.back().immediateBackdrop;
Q_ASSERT(floatImage.getPixelFormat().hasOpacityChannel());
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;
}
void PDFTransparencyRenderer::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule)
{
auto mappedStrokeColor = getMappedStrokeColor();
auto mappedFillColor = getMappedFillColor();
}
void PDFTransparencyRenderer::performClipping(const QPainterPath& path, Qt::FillRule fillRule)

View File

@ -161,6 +161,14 @@ public:
/// If bitmap doesn't have shape/opacity channel, nothing happens.
void makeOpaque();
/// Fillss process color channels to a value, that corresponds to black,
/// so 0.0 for additive colors, 1.0 for subtractive colors.
void makeColorBlack();
/// Fillss process color channels to a value, that corresponds to white,
/// so 1.0 for additive colors, 0.0 for subtractive colors.
void makeColorWhite();
/// Returns index where given pixel starts in the data block
/// \param x Horizontal coordinate of the pixel
/// \param y Vertical coordinate of the pixel
@ -205,6 +213,7 @@ public:
OverprintMode overprintMode);
private:
void fillProcessColorChannels(PDFColorComponent value);
void fillChannel(size_t channel, PDFColorComponent value);
PDFPixelFormat m_format;
@ -306,7 +315,6 @@ public:
PDFPixelFormat targetPixelFormat) const;
private:
const PDFDocument* m_document;
std::vector<SpotColorInfo> m_spotColors;
size_t m_activeSpotColors = 0;
@ -352,6 +360,13 @@ public:
/// group.
const PDFFloatBitmap& endPaint();
/// 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;
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;
virtual void performUpdateGraphicsState(const PDFPageContentProcessorState& state) override;

View File

@ -73,6 +73,9 @@ void OutputPreviewDialog::updateImage()
renderer.beginPaint(imageSize);
renderer.processContents();
renderer.endPaint();
QImage image = renderer.toImage(false);
ui->imageLabel->setPixmap(QPixmap::fromImage(image));
}
} // namespace pdfplugin