mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Create bitmap from rendered image
This commit is contained in:
@ -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
|
size_t PDFFloatBitmap::getPixelIndex(size_t x, size_t y) const
|
||||||
{
|
{
|
||||||
return (y * m_width + x) * m_pixelSize;
|
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)
|
void PDFFloatBitmap::fillChannel(size_t channel, PDFColorComponent value)
|
||||||
{
|
{
|
||||||
// Do we have just one channel?
|
// Do we have just one channel?
|
||||||
@ -571,12 +598,16 @@ void PDFTransparencyRenderer::beginPaint(QSize pixelSize)
|
|||||||
Q_ASSERT(m_deviceColorSpace);
|
Q_ASSERT(m_deviceColorSpace);
|
||||||
Q_ASSERT(m_processColorSpace);
|
Q_ASSERT(m_processColorSpace);
|
||||||
|
|
||||||
|
m_transparencyGroupDataStack.clear();
|
||||||
m_painterStateStack.push(PDFTransparencyPainterState());
|
m_painterStateStack.push(PDFTransparencyPainterState());
|
||||||
|
|
||||||
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()),
|
||||||
true, m_deviceColorSpace->getColorComponentCount() == 4);
|
true, m_deviceColorSpace->getColorComponentCount() == 4);
|
||||||
|
|
||||||
|
PDFFloatBitmapWithColorSpace paper = PDFFloatBitmapWithColorSpace(pixelSize.width(), pixelSize.height(), pixelFormat, m_deviceColorSpace);
|
||||||
|
paper.makeColorWhite();
|
||||||
|
|
||||||
PDFTransparencyGroupPainterData deviceGroup;
|
PDFTransparencyGroupPainterData deviceGroup;
|
||||||
deviceGroup.alphaIsShape = getGraphicState()->getAlphaIsShape();
|
deviceGroup.alphaIsShape = getGraphicState()->getAlphaIsShape();
|
||||||
deviceGroup.alphaStroke = getGraphicState()->getAlphaStroking();
|
deviceGroup.alphaStroke = getGraphicState()->getAlphaStroking();
|
||||||
@ -584,7 +615,7 @@ void PDFTransparencyRenderer::beginPaint(QSize pixelSize)
|
|||||||
deviceGroup.blendMode = getGraphicState()->getBlendMode();
|
deviceGroup.blendMode = getGraphicState()->getBlendMode();
|
||||||
deviceGroup.blackPointCompensationMode = getGraphicState()->getBlackPointCompensationMode();
|
deviceGroup.blackPointCompensationMode = getGraphicState()->getBlackPointCompensationMode();
|
||||||
deviceGroup.renderingIntent = RenderingIntent::RelativeColorimetric;
|
deviceGroup.renderingIntent = RenderingIntent::RelativeColorimetric;
|
||||||
deviceGroup.initialBackdrop = PDFFloatBitmapWithColorSpace(pixelSize.width(), pixelSize.height(), pixelFormat, m_deviceColorSpace);
|
deviceGroup.initialBackdrop = qMove(paper);
|
||||||
deviceGroup.immediateBackdrop = deviceGroup.initialBackdrop;
|
deviceGroup.immediateBackdrop = deviceGroup.initialBackdrop;
|
||||||
deviceGroup.blendColorSpace = m_deviceColorSpace;
|
deviceGroup.blendColorSpace = m_deviceColorSpace;
|
||||||
|
|
||||||
@ -613,10 +644,82 @@ const PDFFloatBitmap& PDFTransparencyRenderer::endPaint()
|
|||||||
return *getImmediateBackdrop();
|
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)
|
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)
|
void PDFTransparencyRenderer::performClipping(const QPainterPath& path, Qt::FillRule fillRule)
|
||||||
|
@ -161,6 +161,14 @@ public:
|
|||||||
/// If bitmap doesn't have shape/opacity channel, nothing happens.
|
/// If bitmap doesn't have shape/opacity channel, nothing happens.
|
||||||
void makeOpaque();
|
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
|
/// Returns index where given pixel starts in the data block
|
||||||
/// \param x Horizontal coordinate of the pixel
|
/// \param x Horizontal coordinate of the pixel
|
||||||
/// \param y Vertical coordinate of the pixel
|
/// \param y Vertical coordinate of the pixel
|
||||||
@ -205,6 +213,7 @@ public:
|
|||||||
OverprintMode overprintMode);
|
OverprintMode overprintMode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void fillProcessColorChannels(PDFColorComponent value);
|
||||||
void fillChannel(size_t channel, PDFColorComponent value);
|
void fillChannel(size_t channel, PDFColorComponent value);
|
||||||
|
|
||||||
PDFPixelFormat m_format;
|
PDFPixelFormat m_format;
|
||||||
@ -306,7 +315,6 @@ public:
|
|||||||
PDFPixelFormat targetPixelFormat) const;
|
PDFPixelFormat targetPixelFormat) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const PDFDocument* m_document;
|
const PDFDocument* m_document;
|
||||||
std::vector<SpotColorInfo> m_spotColors;
|
std::vector<SpotColorInfo> m_spotColors;
|
||||||
size_t m_activeSpotColors = 0;
|
size_t m_activeSpotColors = 0;
|
||||||
@ -352,6 +360,13 @@ public:
|
|||||||
/// group.
|
/// group.
|
||||||
const PDFFloatBitmap& endPaint();
|
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 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 performClipping(const QPainterPath& path, Qt::FillRule fillRule) override;
|
||||||
virtual void performUpdateGraphicsState(const PDFPageContentProcessorState& state) override;
|
virtual void performUpdateGraphicsState(const PDFPageContentProcessorState& state) override;
|
||||||
|
@ -73,6 +73,9 @@ void OutputPreviewDialog::updateImage()
|
|||||||
renderer.beginPaint(imageSize);
|
renderer.beginPaint(imageSize);
|
||||||
renderer.processContents();
|
renderer.processContents();
|
||||||
renderer.endPaint();
|
renderer.endPaint();
|
||||||
|
|
||||||
|
QImage image = renderer.toImage(false);
|
||||||
|
ui->imageLabel->setPixmap(QPixmap::fromImage(image));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pdfplugin
|
} // namespace pdfplugin
|
||||||
|
Reference in New Issue
Block a user