mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	Bitmap processing
This commit is contained in:
		@@ -323,9 +323,49 @@ PDFRGB PDFBlendFunction::blend_Luminosity(PDFRGB Cb, PDFRGB Cs)
 | 
			
		||||
    return nonseparable_SetLum(Cb, nonseparable_Lum(Cs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFGray PDFBlendFunction::blend_Hue(PDFGray Cb, PDFGray Cs)
 | 
			
		||||
{
 | 
			
		||||
    return nonseparable_rgb2gray(blend_Hue(nonseparable_gray2rgb(Cb), nonseparable_gray2rgb(Cs)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFGray PDFBlendFunction::blend_Saturation(PDFGray Cb, PDFGray Cs)
 | 
			
		||||
{
 | 
			
		||||
    return nonseparable_rgb2gray(blend_Saturation(nonseparable_gray2rgb(Cb), nonseparable_gray2rgb(Cs)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFGray PDFBlendFunction::blend_Color(PDFGray Cb, PDFGray Cs)
 | 
			
		||||
{
 | 
			
		||||
    return nonseparable_rgb2gray(blend_Color(nonseparable_gray2rgb(Cb), nonseparable_gray2rgb(Cs)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFGray PDFBlendFunction::blend_Luminosity(PDFGray Cb, PDFGray Cs)
 | 
			
		||||
{
 | 
			
		||||
    return nonseparable_rgb2gray(blend_Luminosity(nonseparable_gray2rgb(Cb), nonseparable_gray2rgb(Cs)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFCMYK PDFBlendFunction::blend_Hue(PDFCMYK Cb, PDFCMYK Cs)
 | 
			
		||||
{
 | 
			
		||||
    return nonseparable_rgb2cmyk(blend_Hue(nonseparable_cmyk2rgb(Cb), nonseparable_cmyk2rgb(Cs)), Cb[3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFCMYK PDFBlendFunction::blend_Saturation(PDFCMYK Cb, PDFCMYK Cs)
 | 
			
		||||
{
 | 
			
		||||
    return nonseparable_rgb2cmyk(blend_Saturation(nonseparable_cmyk2rgb(Cb), nonseparable_cmyk2rgb(Cs)), Cb[3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFCMYK PDFBlendFunction::blend_Color(PDFCMYK Cb, PDFCMYK Cs)
 | 
			
		||||
{
 | 
			
		||||
    return nonseparable_rgb2cmyk(blend_Color(nonseparable_cmyk2rgb(Cb), nonseparable_cmyk2rgb(Cs)), Cb[3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFCMYK PDFBlendFunction::blend_Luminosity(PDFCMYK Cb, PDFCMYK Cs)
 | 
			
		||||
{
 | 
			
		||||
    return nonseparable_rgb2cmyk(blend_Luminosity(nonseparable_cmyk2rgb(Cb), nonseparable_cmyk2rgb(Cs)), Cs[3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFRGB PDFBlendFunction::nonseparable_gray2rgb(PDFGray gray)
 | 
			
		||||
{
 | 
			
		||||
    return PDFRGB{ gray, gray, gray };
 | 
			
		||||
    return nonseparable_SetLum(PDFRGB{ 0.0f, 0.0f, 0.0f }, gray);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFGray PDFBlendFunction::nonseparable_rgb2gray(PDFRGB rgb)
 | 
			
		||||
 
 | 
			
		||||
@@ -120,6 +120,49 @@ public:
 | 
			
		||||
    /// \param Cs Source color
 | 
			
		||||
    static PDFRGB blend_Luminosity(PDFRGB Cb, PDFRGB Cs);
 | 
			
		||||
 | 
			
		||||
    /// Blend non-separable hue function
 | 
			
		||||
    /// \param Cb Backdrop color
 | 
			
		||||
    /// \param Cs Source color
 | 
			
		||||
    static PDFGray blend_Hue(PDFGray Cb, PDFGray Cs);
 | 
			
		||||
 | 
			
		||||
    /// Blend non-separable saturation function
 | 
			
		||||
    /// \param Cb Backdrop color
 | 
			
		||||
    /// \param Cs Source color
 | 
			
		||||
    static PDFGray blend_Saturation(PDFGray Cb, PDFGray Cs);
 | 
			
		||||
 | 
			
		||||
    /// Blend non-separable color function
 | 
			
		||||
    /// \param Cb Backdrop color
 | 
			
		||||
    /// \param Cs Source color
 | 
			
		||||
    static PDFGray blend_Color(PDFGray Cb, PDFGray Cs);
 | 
			
		||||
 | 
			
		||||
    /// Blend non-separable luminosity function
 | 
			
		||||
    /// \param Cb Backdrop color
 | 
			
		||||
    /// \param Cs Source color
 | 
			
		||||
    static PDFGray blend_Luminosity(PDFGray Cb, PDFGray Cs);
 | 
			
		||||
 | 
			
		||||
    /// Blend non-separable hue function
 | 
			
		||||
    /// \param Cb Backdrop color
 | 
			
		||||
    /// \param Cs Source color
 | 
			
		||||
    static PDFCMYK blend_Hue(PDFCMYK Cb, PDFCMYK Cs);
 | 
			
		||||
 | 
			
		||||
    /// Blend non-separable saturation function
 | 
			
		||||
    /// \param Cb Backdrop color
 | 
			
		||||
    /// \param Cs Source color
 | 
			
		||||
    static PDFCMYK blend_Saturation(PDFCMYK Cb, PDFCMYK Cs);
 | 
			
		||||
 | 
			
		||||
    /// Blend non-separable color function
 | 
			
		||||
    /// \param Cb Backdrop color
 | 
			
		||||
    /// \param Cs Source color
 | 
			
		||||
    static PDFCMYK blend_Color(PDFCMYK Cb, PDFCMYK Cs);
 | 
			
		||||
 | 
			
		||||
    /// Blend non-separable luminosity function
 | 
			
		||||
    /// \param Cb Backdrop color
 | 
			
		||||
    /// \param Cs Source color
 | 
			
		||||
    static PDFCMYK blend_Luminosity(PDFCMYK Cb, PDFCMYK Cs);
 | 
			
		||||
 | 
			
		||||
    /// Union function
 | 
			
		||||
    static constexpr PDFColorComponent blend_Union(PDFColorComponent b, PDFColorComponent s) { return b + s - b * s; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static PDFRGB nonseparable_gray2rgb(PDFGray gray);
 | 
			
		||||
    static PDFGray nonseparable_rgb2gray(PDFRGB rgb);
 | 
			
		||||
 
 | 
			
		||||
@@ -613,6 +613,9 @@ protected:
 | 
			
		||||
    /// Returns document
 | 
			
		||||
    const PDFDocument* getDocument() const { return m_document; }
 | 
			
		||||
 | 
			
		||||
    /// Returns color management system
 | 
			
		||||
    const PDFCMS* getCMS() const { return m_CMS; }
 | 
			
		||||
 | 
			
		||||
    /// Parses transparency group
 | 
			
		||||
    PDFTransparencyGroup parseTransparencyGroup(const PDFObject& object);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
 | 
			
		||||
#include "pdftransparencyrenderer.h"
 | 
			
		||||
#include "pdfdocument.h"
 | 
			
		||||
#include "pdfcms.h"
 | 
			
		||||
 | 
			
		||||
namespace pdf
 | 
			
		||||
{
 | 
			
		||||
@@ -37,7 +38,7 @@ PDFFloatBitmap::PDFFloatBitmap(size_t width, size_t height, PDFPixelFormat forma
 | 
			
		||||
{
 | 
			
		||||
    Q_ASSERT(format.isValid());
 | 
			
		||||
 | 
			
		||||
    m_data.resize(format.calculateBitmapDataLength(width, height), static_cast<PDFColorComponent>(0.0));
 | 
			
		||||
    m_data.resize(format.calculateBitmapDataLength(width, height), static_cast<PDFColorComponent>(0.0f));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFColorBuffer PDFFloatBitmap::getPixel(size_t x, size_t y)
 | 
			
		||||
@@ -46,6 +47,11 @@ PDFColorBuffer PDFFloatBitmap::getPixel(size_t x, size_t y)
 | 
			
		||||
    return PDFColorBuffer(m_data.data() + index, m_pixelSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFColorBuffer PDFFloatBitmap::getPixels()
 | 
			
		||||
{
 | 
			
		||||
    return PDFColorBuffer(m_data.data(), m_data.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const PDFColorComponent* PDFFloatBitmap::begin() const
 | 
			
		||||
{
 | 
			
		||||
    return m_data.data();
 | 
			
		||||
@@ -66,11 +72,146 @@ PDFColorComponent* PDFFloatBitmap::end()
 | 
			
		||||
    return m_data.data() + m_data.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PDFFloatBitmap::makeTransparent()
 | 
			
		||||
{
 | 
			
		||||
    if (m_format.hasShapeChannel())
 | 
			
		||||
    {
 | 
			
		||||
        fillChannel(m_format.getShapeChannelIndex(), 0.0f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_format.hasOpacityChannel())
 | 
			
		||||
    {
 | 
			
		||||
        fillChannel(m_format.getOpacityChannelIndex(), 0.0f);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PDFFloatBitmap::makeOpaque()
 | 
			
		||||
{
 | 
			
		||||
    if (m_format.hasShapeChannel())
 | 
			
		||||
    {
 | 
			
		||||
        fillChannel(m_format.getShapeChannelIndex(), 1.0f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_format.hasOpacityChannel())
 | 
			
		||||
    {
 | 
			
		||||
        fillChannel(m_format.getOpacityChannelIndex(), 1.0f);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t PDFFloatBitmap::getPixelIndex(size_t x, size_t y) const
 | 
			
		||||
{
 | 
			
		||||
    return (y * m_width + x) * m_pixelSize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFFloatBitmap PDFFloatBitmap::extractProcessColors()
 | 
			
		||||
{
 | 
			
		||||
    PDFPixelFormat format = PDFPixelFormat::createFormat(m_format.getProcessColorChannelCount(), 0, false, m_format.hasProcessColorsSubtractive());
 | 
			
		||||
    PDFFloatBitmap result(getWidth(), getHeight(), format);
 | 
			
		||||
 | 
			
		||||
    for (size_t x = 0; x < getWidth(); ++x)
 | 
			
		||||
    {
 | 
			
		||||
        for (size_t y = 0; y < getHeight(); ++y)
 | 
			
		||||
        {
 | 
			
		||||
            PDFColorBuffer sourceProcessColorBuffer = getPixel(x, y);
 | 
			
		||||
            PDFColorBuffer targetProcessColorBuffer = result.getPixel(x, y);
 | 
			
		||||
 | 
			
		||||
            Q_ASSERT(sourceProcessColorBuffer.size() >= targetProcessColorBuffer.size());
 | 
			
		||||
            std::copy(sourceProcessColorBuffer.cbegin(), std::next(sourceProcessColorBuffer.cbegin(), targetProcessColorBuffer.size()), targetProcessColorBuffer.begin());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PDFFloatBitmap::fillChannel(size_t channel, PDFColorComponent value)
 | 
			
		||||
{
 | 
			
		||||
    // Do we have just one channel?
 | 
			
		||||
    if (m_format.getChannelCount() == 1)
 | 
			
		||||
    {
 | 
			
		||||
        Q_ASSERT(channel == 0);
 | 
			
		||||
        std::fill(m_data.begin(), m_data.end(), value);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (PDFColorComponent* pixel = begin(); pixel != end(); pixel += m_pixelSize)
 | 
			
		||||
    {
 | 
			
		||||
        pixel[channel] = value;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFFloatBitmapWithColorSpace::PDFFloatBitmapWithColorSpace()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFFloatBitmapWithColorSpace::PDFFloatBitmapWithColorSpace(size_t width, size_t height, PDFPixelFormat format, PDFColorSpacePointer blendColorSpace) :
 | 
			
		||||
    PDFFloatBitmap(width, height, format),
 | 
			
		||||
    m_colorSpace(blendColorSpace)
 | 
			
		||||
{
 | 
			
		||||
    Q_ASSERT(!blendColorSpace || blendColorSpace->isBlendColorSpace());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFColorSpacePointer PDFFloatBitmapWithColorSpace::getColorSpace() const
 | 
			
		||||
{
 | 
			
		||||
    return m_colorSpace;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PDFFloatBitmapWithColorSpace::setColorSpace(const PDFColorSpacePointer& colorSpace)
 | 
			
		||||
{
 | 
			
		||||
    m_colorSpace = colorSpace;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PDFFloatBitmapWithColorSpace::convertToColorSpace(const PDFCMS* cms,
 | 
			
		||||
                                                       RenderingIntent intent,
 | 
			
		||||
                                                       const PDFColorSpacePointer& targetColorSpace,
 | 
			
		||||
                                                       PDFRenderErrorReporter* reporter)
 | 
			
		||||
{
 | 
			
		||||
    Q_ASSERT(m_colorSpace);
 | 
			
		||||
    if (m_colorSpace->equals(targetColorSpace.get()))
 | 
			
		||||
    {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const uint8_t targetDeviceColors = static_cast<uint8_t>(targetColorSpace->getColorComponentCount());
 | 
			
		||||
    PDFPixelFormat newFormat = getPixelFormat();
 | 
			
		||||
    newFormat.setProcessColors(targetDeviceColors);
 | 
			
		||||
    newFormat.setProcessColorsSubtractive(targetDeviceColors == 4);
 | 
			
		||||
 | 
			
		||||
    PDFFloatBitmap sourceProcessColors = extractProcessColors();
 | 
			
		||||
    PDFFloatBitmap targetProcessColors(sourceProcessColors.getWidth(), sourceProcessColors.getHeight(), PDFPixelFormat::createFormat(targetDeviceColors, 0, false, newFormat.hasProcessColorsSubtractive()));
 | 
			
		||||
 | 
			
		||||
    if (!PDFAbstractColorSpace::transform(m_colorSpace.data(), targetColorSpace.data(), cms, intent, sourceProcessColors.getPixels(), targetProcessColors.getPixels(), reporter))
 | 
			
		||||
    {
 | 
			
		||||
        reporter->reportRenderError(RenderErrorType::Error, PDFTranslationContext::tr("Transformation between blending color spaces failed."));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PDFFloatBitmapWithColorSpace temporary(getWidth(), getHeight(), newFormat, targetColorSpace);
 | 
			
		||||
    for (size_t x = 0; x < getWidth(); ++x)
 | 
			
		||||
    {
 | 
			
		||||
        for (size_t y = 0; y < getHeight(); ++y)
 | 
			
		||||
        {
 | 
			
		||||
            PDFColorBuffer sourceProcessColorBuffer = targetProcessColors.getPixel(x, y);
 | 
			
		||||
            PDFColorBuffer sourceSpotColorAndOpacityBuffer = getPixel(x, y);
 | 
			
		||||
            PDFColorBuffer targetBuffer = temporary.getPixel(x, y);
 | 
			
		||||
 | 
			
		||||
            Q_ASSERT(sourceProcessColorBuffer.size() <= targetBuffer.size());
 | 
			
		||||
 | 
			
		||||
            // Copy process colors
 | 
			
		||||
            auto targetIt = targetBuffer.begin();
 | 
			
		||||
            targetIt = std::copy(sourceProcessColorBuffer.cbegin(), sourceProcessColorBuffer.cend(), targetIt);
 | 
			
		||||
 | 
			
		||||
            Q_ASSERT(std::distance(targetIt, targetBuffer.end()) == temporary.getPixelFormat().getSpotColorChannelCount() + temporary.getPixelFormat().getAuxiliaryChannelCount());
 | 
			
		||||
 | 
			
		||||
            auto sourceIt = std::next(sourceSpotColorAndOpacityBuffer.cbegin(), temporary.getPixelFormat().getProcessColorChannelCount());
 | 
			
		||||
            targetIt = std::copy(sourceIt, sourceSpotColorAndOpacityBuffer.cend(), targetIt);
 | 
			
		||||
 | 
			
		||||
            Q_ASSERT(targetIt == targetBuffer.cend());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *this = qMove(temporary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFTransparencyRenderer::PDFTransparencyRenderer(const PDFPage* page,
 | 
			
		||||
                                                 const PDFDocument* document,
 | 
			
		||||
                                                 const PDFFontCache* fontCache,
 | 
			
		||||
@@ -110,6 +251,8 @@ const PDFFloatBitmap& PDFTransparencyRenderer::endPaint()
 | 
			
		||||
    Q_ASSERT(m_active);
 | 
			
		||||
    m_pageTransparencyGroupGuard.reset();
 | 
			
		||||
    m_active = false;
 | 
			
		||||
 | 
			
		||||
    return *getImmediateBackdrop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PDFTransparencyRenderer::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule)
 | 
			
		||||
@@ -134,10 +277,86 @@ void PDFTransparencyRenderer::performRestoreGraphicState(ProcessOrder order)
 | 
			
		||||
 | 
			
		||||
void PDFTransparencyRenderer::performBeginTransparencyGroup(ProcessOrder order, const PDFTransparencyGroup& transparencyGroup)
 | 
			
		||||
{
 | 
			
		||||
    if (order == ProcessOrder::BeforeOperation)
 | 
			
		||||
    {
 | 
			
		||||
        PDFTransparencyGroupPainterData data;
 | 
			
		||||
        data.group = transparencyGroup;
 | 
			
		||||
        data.alphaIsShape = getGraphicState()->getAlphaIsShape();
 | 
			
		||||
        data.alphaFill = getGraphicState()->getAlphaFilling();
 | 
			
		||||
        data.alphaStroke = getGraphicState()->getAlphaStroking();
 | 
			
		||||
        data.blendMode = getGraphicState()->getBlendMode();
 | 
			
		||||
        data.blackPointCompensationMode = getGraphicState()->getBlackPointCompensationMode();
 | 
			
		||||
        data.renderingIntent = getGraphicState()->getRenderingIntent();
 | 
			
		||||
        data.blendColorSpace = transparencyGroup.colorSpacePointer;
 | 
			
		||||
 | 
			
		||||
        if (!data.blendColorSpace)
 | 
			
		||||
        {
 | 
			
		||||
            data.blendColorSpace = getBlendColorSpace();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Create initial backdrop, according to 11.4.8 of PDF 2.0 specification.
 | 
			
		||||
        // If group is knockout, use initial backdrop.
 | 
			
		||||
        PDFFloatBitmapWithColorSpace* oldBackdrop = getBackdrop();
 | 
			
		||||
        data.initialBackdrop = *getBackdrop();
 | 
			
		||||
 | 
			
		||||
        if (isTransparencyGroupIsolated())
 | 
			
		||||
        {
 | 
			
		||||
            // Make initial backdrop transparent
 | 
			
		||||
            data.initialBackdrop.makeTransparent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Prepare soft mask
 | 
			
		||||
        data.softMask = PDFFloatBitmap(oldBackdrop->getWidth(), oldBackdrop->getHeight(), PDFPixelFormat::createOpacityMask());
 | 
			
		||||
        // TODO: Create soft mask
 | 
			
		||||
        data.softMask.makeOpaque();
 | 
			
		||||
 | 
			
		||||
        data.initialBackdrop.convertToColorSpace(getCMS(), data.renderingIntent, data.blendColorSpace, this);
 | 
			
		||||
        data.immediateBackdrop = data.initialBackdrop;
 | 
			
		||||
 | 
			
		||||
        m_transparencyGroupDataStack.emplace_back(qMove(data));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PDFTransparencyRenderer::performEndTransparencyGroup(ProcessOrder order, const PDFTransparencyGroup& transparencyGroup)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFFloatBitmapWithColorSpace* PDFTransparencyRenderer::getInitialBackdrop()
 | 
			
		||||
{
 | 
			
		||||
    return &m_transparencyGroupDataStack.back().initialBackdrop;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFFloatBitmapWithColorSpace* PDFTransparencyRenderer::getImmediateBackdrop()
 | 
			
		||||
{
 | 
			
		||||
    return &m_transparencyGroupDataStack.back().immediateBackdrop;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PDFFloatBitmapWithColorSpace* PDFTransparencyRenderer::getBackdrop()
 | 
			
		||||
{
 | 
			
		||||
    if (isTransparencyGroupKnockout())
 | 
			
		||||
    {
 | 
			
		||||
        return getInitialBackdrop();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return getImmediateBackdrop();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const PDFColorSpacePointer& PDFTransparencyRenderer::getBlendColorSpace() const
 | 
			
		||||
{
 | 
			
		||||
    return m_transparencyGroupDataStack.back().blendColorSpace;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PDFTransparencyRenderer::isTransparencyGroupIsolated() const
 | 
			
		||||
{
 | 
			
		||||
    return m_transparencyGroupDataStack.back().group.isolated;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PDFTransparencyRenderer::isTransparencyGroupKnockout() const
 | 
			
		||||
{
 | 
			
		||||
    return m_transparencyGroupDataStack.back().group.knockout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}   // namespace pdf
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,19 @@ public:
 | 
			
		||||
 | 
			
		||||
    inline void setProcessColors(const uint8_t& processColors) { m_processColors = processColors; }
 | 
			
		||||
    inline void setSpotColors(const uint8_t& spotColors) { m_spotColors = spotColors; }
 | 
			
		||||
    inline void setProcessColorsSubtractive(bool subtractive)
 | 
			
		||||
    {
 | 
			
		||||
        if (subtractive)
 | 
			
		||||
        {
 | 
			
		||||
            m_flags |= FLAG_PROCESS_COLORS_SUBTRACTIVE;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            m_flags &= ~FLAG_PROCESS_COLORS_SUBTRACTIVE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr PDFPixelFormat createOpacityMask() { return PDFPixelFormat(0, 0, FLAG_HAS_OPACITY_CHANNEL); }
 | 
			
		||||
    static constexpr PDFPixelFormat createFormatDefaultGray(uint8_t spotColors) { return createFormat(1, spotColors, true, false); }
 | 
			
		||||
    static constexpr PDFPixelFormat createFormatDefaultRGB(uint8_t spotColors) { return createFormat(3, spotColors, true, false); }
 | 
			
		||||
    static constexpr PDFPixelFormat createFormatDefaultCMYK(uint8_t spotColors) { return createFormat(4, spotColors, true, true); }
 | 
			
		||||
@@ -117,18 +129,39 @@ public:
 | 
			
		||||
    /// Returns buffer with pixel channels
 | 
			
		||||
    PDFColorBuffer getPixel(size_t x, size_t y);
 | 
			
		||||
 | 
			
		||||
    /// Returns buffer with all pixels
 | 
			
		||||
    PDFColorBuffer getPixels();
 | 
			
		||||
 | 
			
		||||
    const PDFColorComponent* begin() const;
 | 
			
		||||
    const PDFColorComponent* end() const;
 | 
			
		||||
 | 
			
		||||
    PDFColorComponent* begin();
 | 
			
		||||
    PDFColorComponent* end();
 | 
			
		||||
 | 
			
		||||
    size_t getWidth() const { return m_width; }
 | 
			
		||||
    size_t getHeight() const { return m_height; }
 | 
			
		||||
    size_t getPixelSize() const { return m_pixelSize; }
 | 
			
		||||
    PDFPixelFormat getPixelFormat() const { return m_format; }
 | 
			
		||||
 | 
			
		||||
    /// Fills both shape and opacity channel with zero value.
 | 
			
		||||
    /// If bitmap doesn't have shape/opacity channel, nothing happens.
 | 
			
		||||
    void makeTransparent();
 | 
			
		||||
 | 
			
		||||
    /// Fills both shape and opacity channel with 1.0 value.
 | 
			
		||||
    /// If bitmap doesn't have shape/opacity channel, nothing happens.
 | 
			
		||||
    void makeOpaque();
 | 
			
		||||
 | 
			
		||||
    /// Returns index where given pixel starts in the data block
 | 
			
		||||
    /// \param x Horizontal coordinate of the pixel
 | 
			
		||||
    /// \param y Vertical coordinate of the pixel
 | 
			
		||||
    size_t getPixelIndex(size_t x, size_t y) const;
 | 
			
		||||
 | 
			
		||||
    /// Extract process colors into another bitmap
 | 
			
		||||
    PDFFloatBitmap extractProcessColors();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void fillChannel(size_t channel, PDFColorComponent value);
 | 
			
		||||
 | 
			
		||||
    PDFPixelFormat m_format;
 | 
			
		||||
    std::size_t m_width;
 | 
			
		||||
    std::size_t m_height;
 | 
			
		||||
@@ -136,6 +169,29 @@ private:
 | 
			
		||||
    std::vector<PDFColorComponent> m_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Float bitmap with color space
 | 
			
		||||
class PDFFloatBitmapWithColorSpace : public PDFFloatBitmap
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit PDFFloatBitmapWithColorSpace();
 | 
			
		||||
    explicit PDFFloatBitmapWithColorSpace(size_t width, size_t height, PDFPixelFormat format);
 | 
			
		||||
    explicit PDFFloatBitmapWithColorSpace(size_t width, size_t height, PDFPixelFormat format, PDFColorSpacePointer blendColorSpace);
 | 
			
		||||
 | 
			
		||||
    PDFColorSpacePointer getColorSpace() const;
 | 
			
		||||
    void setColorSpace(const PDFColorSpacePointer& colorSpace);
 | 
			
		||||
 | 
			
		||||
    /// Converts bitmap to target color space
 | 
			
		||||
    /// \param cms Color management system
 | 
			
		||||
    /// \param targetColorSpace Target color space
 | 
			
		||||
    void convertToColorSpace(const PDFCMS* cms,
 | 
			
		||||
                             RenderingIntent intent,
 | 
			
		||||
                             const PDFColorSpacePointer& targetColorSpace,
 | 
			
		||||
                             PDFRenderErrorReporter* reporter);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    PDFColorSpacePointer m_colorSpace;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Renders PDF pages with transparency, using 32-bit floating point precision.
 | 
			
		||||
/// Both device color space and blending color space can be defined. It implements
 | 
			
		||||
/// page blending space and device blending space. So, painted graphics is being
 | 
			
		||||
@@ -184,9 +240,21 @@ private:
 | 
			
		||||
        PDFReal alphaFill = 1.0;
 | 
			
		||||
        BlendMode blendMode = BlendMode::Normal;
 | 
			
		||||
        BlackPointCompensationMode blackPointCompensationMode = BlackPointCompensationMode::Default;
 | 
			
		||||
        RenderingIntent RenderingIntent = RenderingIntent::RelativeColorimetric;
 | 
			
		||||
        RenderingIntent renderingIntent = RenderingIntent::RelativeColorimetric;
 | 
			
		||||
        PDFFloatBitmapWithColorSpace initialBackdrop;   ///< Initial backdrop
 | 
			
		||||
        PDFFloatBitmapWithColorSpace immediateBackdrop; ///< Immediate backdrop
 | 
			
		||||
        PDFFloatBitmap softMask; ///< Soft mask for this group
 | 
			
		||||
        PDFColorSpacePointer blendColorSpace;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    PDFFloatBitmapWithColorSpace* getInitialBackdrop();
 | 
			
		||||
    PDFFloatBitmapWithColorSpace* getImmediateBackdrop();
 | 
			
		||||
    PDFFloatBitmapWithColorSpace* getBackdrop();
 | 
			
		||||
    const PDFColorSpacePointer& getBlendColorSpace() const;
 | 
			
		||||
 | 
			
		||||
    bool isTransparencyGroupIsolated() const;
 | 
			
		||||
    bool isTransparencyGroupKnockout() const;
 | 
			
		||||
 | 
			
		||||
    PDFColorSpacePointer m_deviceColorSpace;    ///< Device color space (color space for final result)
 | 
			
		||||
    PDFColorSpacePointer m_processColorSpace;   ///< Process color space (color space, in which is page graphic's blended)
 | 
			
		||||
    std::unique_ptr<PDFTransparencyGroupGuard> m_pageTransparencyGroupGuard;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user