Uncolored tiling patterns, tiling patterns colors

This commit is contained in:
Jakub Melka 2019-09-26 19:14:04 +02:00
parent 40f3f9f9b4
commit 59ad9afadd
7 changed files with 104 additions and 32 deletions

View File

@ -241,7 +241,7 @@ QColor PDFAbstractColorSpace::getCheckedColor(const PDFColor& color) const
{
if (getColorComponentCount() != color.size())
{
throw PDFParserException(PDFTranslationContext::tr("Invalid number of color components. Expected number is %1, actual number is %2.").arg(static_cast<int>(getColorComponentCount()), static_cast<int>(color.size())));
throw PDFParserException(PDFTranslationContext::tr("Invalid number of color components. Expected number is %1, actual number is %2.").arg(static_cast<int>(getColorComponentCount())).arg(static_cast<int>(color.size())));
}
return getColor(color);
@ -352,7 +352,13 @@ PDFColorSpacePointer PDFAbstractColorSpace::createColorSpaceImpl(const PDFDictio
if (name == COLOR_SPACE_NAME_PATTERN)
{
return PDFColorSpacePointer(new PDFPatternColorSpace(std::make_shared<PDFInvalidPattern>()));
PDFColorSpacePointer uncoloredPatternColorSpace;
if (count == 2)
{
uncoloredPatternColorSpace = createColorSpaceImpl(colorSpaceDictionary, document, document->getObject(array->getItem(1)), recursion);
}
return PDFColorSpacePointer(new PDFPatternColorSpace(std::make_shared<PDFInvalidPattern>(), qMove(uncoloredPatternColorSpace), PDFColor()));
}
if (dictionary)
@ -413,7 +419,7 @@ PDFColorSpacePointer PDFAbstractColorSpace::createDeviceColorSpaceByNameImpl(con
if (name == COLOR_SPACE_NAME_PATTERN)
{
return PDFColorSpacePointer(new PDFPatternColorSpace(std::make_shared<PDFInvalidPattern>()));
return PDFColorSpacePointer(new PDFPatternColorSpace(std::make_shared<PDFInvalidPattern>(), nullptr, PDFColor()));
}
if (name == COLOR_SPACE_NAME_DEVICE_GRAY || name == COLOR_SPACE_NAME_ABBREVIATION_DEVICE_GRAY)

View File

@ -34,6 +34,7 @@ class PDFPattern;
class PDFDocument;
class PDFDictionary;
class PDFAbstractColorSpace;
class PDFPatternColorSpace;
using PDFColorComponent = float;
using PDFColor = PDFFlatArray<PDFColorComponent, 4>;
@ -211,7 +212,7 @@ public:
virtual QColor getColor(const PDFColor& color) const = 0;
virtual size_t getColorComponentCount() const = 0;
virtual QImage getImage(const PDFImageData& imageData) const;
virtual const PDFPattern* getPattern() const { return nullptr; }
virtual const PDFPatternColorSpace* asPatternColorSpace() const { return nullptr; }
/// Checks, if number of color components is OK, and if yes, converts them to the QColor value.
/// If they are not OK, exception is thrown.
@ -592,17 +593,29 @@ private:
class PDFPatternColorSpace : public PDFAbstractColorSpace
{
public:
explicit PDFPatternColorSpace(std::shared_ptr<PDFPattern>&& pattern) : m_pattern(qMove(pattern)) { }
explicit PDFPatternColorSpace(std::shared_ptr<PDFPattern>&& pattern, PDFColorSpacePointer&& uncoloredPatternColorSpace, PDFColor uncoloredPatternColor) :
m_pattern(qMove(pattern)),
m_uncoloredPatternColorSpace(qMove(uncoloredPatternColorSpace)),
m_uncoloredPatternColor(qMove(uncoloredPatternColor))
{
}
virtual ~PDFPatternColorSpace() override = default;
virtual QColor getDefaultColor() const override;
virtual QColor getColor(const PDFColor& color) const override;
virtual size_t getColorComponentCount() const override;
virtual const PDFPatternColorSpace* asPatternColorSpace() const override { return this; }
virtual const PDFPattern* getPattern() const override { return m_pattern.get(); }
const PDFPattern* getPattern() const { return m_pattern.get(); }
PDFColorSpacePointer getUncoloredPatternColorSpace() const { return m_uncoloredPatternColorSpace; }
PDFColor getUncoloredPatternColor() const { return m_uncoloredPatternColor; }
private:
std::shared_ptr<PDFPattern> m_pattern;
PDFColorSpacePointer m_uncoloredPatternColorSpace;
PDFColor m_uncoloredPatternColor;
};
} // namespace pdf

View File

@ -594,15 +594,15 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool
if (fill)
{
const PDFPattern* pattern = getGraphicState()->getFillColorSpace()->getPattern();
if (pattern)
if (const PDFPatternColorSpace* patternColorSpace = getGraphicState()->getFillColorSpace()->asPatternColorSpace())
{
const PDFPattern* pattern = patternColorSpace->getPattern();
switch (pattern->getType())
{
case PatternType::Tiling:
{
const PDFTilingPattern* tilingPattern = pattern->getTilingPattern();
processTillingPatternPainting(tilingPattern, path);
processTillingPatternPainting(tilingPattern, path, patternColorSpace->getUncoloredPatternColorSpace(), patternColorSpace->getUncoloredPatternColor());
break;
}
@ -653,9 +653,9 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool
if (stroke)
{
const PDFPattern* pattern = getGraphicState()->getStrokeColorSpace()->getPattern();
if (pattern)
if (const PDFPatternColorSpace* patternColorSpace = getGraphicState()->getFillColorSpace()->asPatternColorSpace())
{
const PDFPattern* pattern = patternColorSpace->getPattern();
switch (pattern->getType())
{
case PatternType::Tiling:
@ -676,7 +676,7 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool
stroker.setDashOffset(lineDashPattern.getDashOffset());
}
QPainterPath strokedPath = stroker.createStroke(path);
processTillingPatternPainting(tilingPattern, strokedPath);
processTillingPatternPainting(tilingPattern, strokedPath, patternColorSpace->getUncoloredPatternColorSpace(), patternColorSpace->getUncoloredPatternColor());
break;
}
@ -745,7 +745,10 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool
}
}
void PDFPageContentProcessor::processTillingPatternPainting(const PDFTilingPattern* tilingPattern, const QPainterPath& path)
void PDFPageContentProcessor::processTillingPatternPainting(const PDFTilingPattern* tilingPattern,
const QPainterPath& path,
PDFColorSpacePointer uncoloredPatternColorSpace,
PDFColor uncoloredPatternColor)
{
PDFPageContentProcessorStateGuard guard(this);
performClipping(path, path.fillRule());
@ -764,6 +767,33 @@ void PDFPageContentProcessor::processTillingPatternPainting(const PDFTilingPatte
QMatrix matrix = patternMatrix * m_pagePointToDevicePointMatrix.inverted();
QMatrix pathTransformationMatrix = m_graphicState.getCurrentTransformationMatrix() * matrix.inverted();
m_graphicState.setCurrentTransformationMatrix(matrix);
// Initialize colors for uncolored color space pattern
if (tilingPattern->getPaintingType() == PDFTilingPattern::PaintType::Uncolored)
{
if (!uncoloredPatternColorSpace)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Uncolored tiling pattern has not underlying color space."));
}
m_graphicState.setStrokeColorSpace(uncoloredPatternColorSpace);
m_graphicState.setFillColorSpace(uncoloredPatternColorSpace);
QColor color = uncoloredPatternColorSpace->getCheckedColor(uncoloredPatternColor);
m_graphicState.setStrokeColor(color);
m_graphicState.setFillColor(color);
}
else
{
// Jakub Melka: According the specification, we set default color space and default color
m_graphicState.setStrokeColorSpace(m_deviceGrayColorSpace);
m_graphicState.setFillColorSpace(m_deviceGrayColorSpace);
QColor color = m_deviceGrayColorSpace->getDefaultColor();
m_graphicState.setStrokeColor(color);
m_graphicState.setFillColor(color);
}
updateGraphicState();
// Tiling parameters
@ -1951,17 +1981,25 @@ void PDFPageContentProcessor::operatorColorSetStrokingColorN()
// but default operator can use them (with exception of Pattern color space). For pattern color space,
// we treat this differently.
const PDFAbstractColorSpace* colorSpace = m_graphicState.getStrokeColorSpace();
if (colorSpace->getPattern())
if (const PDFPatternColorSpace* patternColorSpace = colorSpace->asPatternColorSpace())
{
if (m_operands.size() > 0)
const size_t operandCount = m_operands.size();
if (operandCount > 0)
{
// TODO: Implement tiling pattern colors
PDFOperandName name = readOperand<PDFOperandName>(m_operands.size() - 1);
PDFColorSpacePointer uncoloredColorSpace = patternColorSpace->getUncoloredPatternColorSpace();
PDFColor uncoloredPatternColor;
for (size_t i = 0; i < operandCount - 1; ++i)
{
uncoloredPatternColor.push_back(readOperand<PDFReal>(i));
}
PDFOperandName name = readOperand<PDFOperandName>(operandCount - 1);
if (m_patternDictionary && m_patternDictionary->hasKey(name.name))
{
// Create the pattern
PDFPatternPtr pattern = PDFPattern::createPattern(m_colorSpaceDictionary, m_document, m_patternDictionary->get(name.name));
m_graphicState.setStrokeColorSpace(QSharedPointer<PDFAbstractColorSpace>(new PDFPatternColorSpace(qMove(pattern))));
m_graphicState.setStrokeColorSpace(PDFColorSpacePointer(new PDFPatternColorSpace(qMove(pattern), qMove(uncoloredColorSpace), qMove(uncoloredPatternColor))));
updateGraphicState();
return;
}
@ -2009,17 +2047,25 @@ void PDFPageContentProcessor::operatorColorSetFillingColorN()
// but default operator can use them (with exception of Pattern color space). For pattern color space,
// we treat this differently.
const PDFAbstractColorSpace* colorSpace = m_graphicState.getFillColorSpace();
if (colorSpace->getPattern())
if (const PDFPatternColorSpace* patternColorSpace = colorSpace->asPatternColorSpace())
{
if (m_operands.size() > 0)
const size_t operandCount = m_operands.size();
if (operandCount > 0)
{
// TODO: Implement tiling pattern colors
PDFOperandName name = readOperand<PDFOperandName>(m_operands.size() - 1);
PDFColorSpacePointer uncoloredColorSpace = patternColorSpace->getUncoloredPatternColorSpace();
PDFColor uncoloredPatternColor;
for (size_t i = 0; i < operandCount - 1; ++i)
{
uncoloredPatternColor.push_back(readOperand<PDFReal>(i));
}
PDFOperandName name = readOperand<PDFOperandName>(operandCount - 1);
if (m_patternDictionary && m_patternDictionary->hasKey(name.name))
{
// Create the pattern
PDFPatternPtr pattern = PDFPattern::createPattern(m_colorSpaceDictionary, m_document, m_patternDictionary->get(name.name));
m_graphicState.setFillColorSpace(QSharedPointer<PDFAbstractColorSpace>(new PDFPatternColorSpace(qMove(pattern))));
m_graphicState.setFillColorSpace(QSharedPointer<PDFAbstractColorSpace>(new PDFPatternColorSpace(qMove(pattern), qMove(uncoloredColorSpace), qMove(uncoloredPatternColor))));
updateGraphicState();
return;
}
@ -2359,7 +2405,7 @@ void PDFPageContentProcessor::operatorShadingPaintShape(PDFPageContentProcessor:
// We will do a trick: we will set current fill color space, and then paint
// bounding rectangle in the color pattern.
m_graphicState.setFillColorSpace(PDFColorSpacePointer(new PDFPatternColorSpace(qMove(pattern))));
m_graphicState.setFillColorSpace(PDFColorSpacePointer(new PDFPatternColorSpace(qMove(pattern), nullptr, PDFColor())));
updateGraphicState();
Q_ASSERT(matrix.isInvertible());

View File

@ -468,7 +468,12 @@ private:
/// Performs tiling pattern painting
/// \param tilingPattern Tiling pattern to be painted
/// \param path Clipping path
void processTillingPatternPainting(const PDFTilingPattern* tilingPattern, const QPainterPath& path);
/// \param uncoloredPatternColorSpace Color space for uncolored color patterns
/// \param uncoloredPatternColor Uncolored color pattern color
void processTillingPatternPainting(const PDFTilingPattern* tilingPattern,
const QPainterPath& path,
PDFColorSpacePointer uncoloredPatternColorSpace,
PDFColor uncoloredPatternColor);
enum class MarkedContentKind
{

View File

@ -50,6 +50,8 @@ PDFPainter::PDFPainter(QPainter* painter,
m_painter->setClipPath(path, Qt::IntersectClip);
}
}
m_painter->setRenderHint(QPainter::SmoothPixmapTransform, features.testFlag(PDFRenderer::SmoothImages));
}
PDFPainter::~PDFPainter()

View File

@ -156,7 +156,7 @@ PDFPatternPtr PDFPattern::createShadingPattern(const PDFDictionary* colorSpaceDi
// Parse common data for all shadings
PDFColorSpacePointer colorSpace = PDFAbstractColorSpace::createColorSpace(colorSpaceDictionary, document, document->getObject(shadingDictionary->get("ColorSpace")));
if (colorSpace->getPattern())
if (colorSpace->asPatternColorSpace())
{
throw PDFParserException(PDFTranslationContext::tr("Pattern color space is not valid for shading patterns."));
}

View File

@ -250,16 +250,16 @@ public:
enum class PaintType
{
Colored,
Uncolored,
Invalid
Colored = 1,
Uncolored = 2,
Invalid = 3
};
enum class TilingType
{
ConstantSpacing,
NoDistortion,
ConstantSpacingAndFasterTiling,
ConstantSpacing = 1,
NoDistortion = 2,
ConstantSpacingAndFasterTiling = 3,
Invalid
};