Separation color space, some bugfixing

This commit is contained in:
Jakub Melka 2019-03-17 16:12:36 +01:00
parent 2964637949
commit 8c417b2afb
5 changed files with 130 additions and 23 deletions

View File

@ -168,6 +168,11 @@ PDFColorSpacePointer PDFAbstractColorSpace::createColorSpaceImpl(const PDFDictio
return PDFIndexedColorSpace::createIndexedColorSpace(colorSpaceDictionary, document, array, recursion);
}
if (name == COLOR_SPACE_NAME_SEPARATION && count == 4)
{
return PDFSeparationColorSpace::createSeparationColorSpace(colorSpaceDictionary, document, array, recursion);
}
// Try to just load by standard way - we can have "standard" color space stored in array
return createColorSpaceImpl(colorSpaceDictionary, document, colorSpaceIdentifier, recursion);
}
@ -628,4 +633,79 @@ PDFColorSpacePointer PDFIndexedColorSpace::createIndexedColorSpace(const PDFDict
return PDFColorSpacePointer(new PDFIndexedColorSpace(qMove(baseColorSpace), qMove(colors), maxValue));
}
PDFSeparationColorSpace::PDFSeparationColorSpace(QByteArray&& colorName, PDFColorSpacePointer alternateColorSpace, PDFFunctionPtr tintTransform) :
m_colorName(qMove(colorName)),
m_alternateColorSpace(qMove(alternateColorSpace)),
m_tintTransform(qMove(tintTransform))
{
}
QColor PDFSeparationColorSpace::getDefaultColor() const
{
return getColor(PDFColor(0.0f));
}
QColor PDFSeparationColorSpace::getColor(const PDFColor& color) const
{
// Separation color space value must have exactly one component!
Q_ASSERT(color.size() == 1);
// Input value
double tint = color.back();
// Output values
std::vector<double> outputColor;
outputColor.resize(m_alternateColorSpace->getColorComponentCount(), 0.0);
PDFFunction::FunctionResult result = m_tintTransform->apply(&tint, &tint + 1, outputColor.data(), outputColor.data() + outputColor.size());
if (result)
{
PDFColor color;
std::for_each(outputColor.cbegin(), outputColor.cend(), [&color](double value) { color.push_back(static_cast<float>(value)); });
return m_alternateColorSpace->getColor(color);
}
else
{
// Return invalid color
return QColor();
}
}
size_t PDFSeparationColorSpace::getColorComponentCount() const
{
return 1;
}
PDFColorSpacePointer PDFSeparationColorSpace::createSeparationColorSpace(const PDFDictionary* colorSpaceDictionary,
const PDFDocument* document,
const PDFArray* array,
int recursion)
{
Q_ASSERT(array->getCount() == 4);
// Read color name
const PDFObject& colorNameObject = document->getObject(array->getItem(1));
if (!colorNameObject.isName())
{
throw PDFParserException(PDFTranslationContext::tr("Can't determine color name for separation color space."));
}
QByteArray colorName = colorNameObject.getString();
// Read alternate color space
PDFColorSpacePointer alternateColorSpace = PDFAbstractColorSpace::createColorSpaceImpl(colorSpaceDictionary, document, document->getObject(array->getItem(2)), recursion);
if (!alternateColorSpace)
{
throw PDFParserException(PDFTranslationContext::tr("Can't determine alternate color space for separation color space."));
}
PDFFunctionPtr tintTransform = PDFFunction::createFunction(document, array->getItem(3));
if (!tintTransform)
{
throw PDFParserException(PDFTranslationContext::tr("Can't determine tint transform for separation color space."));
}
return PDFColorSpacePointer(new PDFSeparationColorSpace(qMove(colorName), qMove(alternateColorSpace), qMove(tintTransform)));
}
} // namespace pdf

View File

@ -19,6 +19,7 @@
#define PDFCOLORSPACES_H
#include "pdfflatarray.h"
#include "pdffunction.h"
#include <QColor>
#include <QSharedPointer>
@ -57,6 +58,7 @@ static constexpr const char* COLOR_SPACE_NAME_CAL_RGB = "CalRGB";
static constexpr const char* COLOR_SPACE_NAME_LAB = "Lab";
static constexpr const char* COLOR_SPACE_NAME_ICCBASED = "ICCBased";
static constexpr const char* COLOR_SPACE_NAME_INDEXED = "Indexed";
static constexpr const char* COLOR_SPACE_NAME_SEPARATION = "Separation";
static constexpr const char* CAL_WHITE_POINT = "WhitePoint";
static constexpr const char* CAL_BLACK_POINT = "BlackPoint";
@ -284,7 +286,7 @@ protected:
class PDFCalGrayColorSpace : public PDFXYZColorSpace
{
public:
explicit inline PDFCalGrayColorSpace(PDFColor3 whitePoint, PDFColor3 blackPoint, PDFColorComponent gamma);
explicit PDFCalGrayColorSpace(PDFColor3 whitePoint, PDFColor3 blackPoint, PDFColorComponent gamma);
virtual ~PDFCalGrayColorSpace() = default;
virtual QColor getColor(const PDFColor& color) const override;
@ -303,7 +305,7 @@ private:
class PDFCalRGBColorSpace : public PDFXYZColorSpace
{
public:
explicit inline PDFCalRGBColorSpace(PDFColor3 whitePoint, PDFColor3 blackPoint, PDFColor3 gamma, PDFColorComponentMatrix_3x3 matrix);
explicit PDFCalRGBColorSpace(PDFColor3 whitePoint, PDFColor3 blackPoint, PDFColor3 gamma, PDFColorComponentMatrix_3x3 matrix);
virtual ~PDFCalRGBColorSpace() = default;
virtual QColor getColor(const PDFColor& color) const override;
@ -323,7 +325,7 @@ private:
class PDFLabColorSpace : public PDFXYZColorSpace
{
public:
explicit inline PDFLabColorSpace(PDFColor3 whitePoint, PDFColor3 blackPoint, PDFColorComponent aMin, PDFColorComponent aMax, PDFColorComponent bMin, PDFColorComponent bMax);
explicit PDFLabColorSpace(PDFColor3 whitePoint, PDFColor3 blackPoint, PDFColorComponent aMin, PDFColorComponent aMax, PDFColorComponent bMin, PDFColorComponent bMax);
virtual ~PDFLabColorSpace() = default;
virtual QColor getColor(const PDFColor& color) const override;
@ -349,7 +351,7 @@ private:
using Ranges = std::array<PDFColorComponent, MAX_COLOR_COMPONENTS * 2>;
public:
explicit inline PDFICCBasedColorSpace(PDFColorSpacePointer alternateColorSpace, Ranges range);
explicit PDFICCBasedColorSpace(PDFColorSpacePointer alternateColorSpace, Ranges range);
virtual ~PDFICCBasedColorSpace() = default;
virtual QColor getDefaultColor() const override;
@ -371,7 +373,7 @@ private:
class PDFIndexedColorSpace : public PDFAbstractColorSpace
{
public:
explicit inline PDFIndexedColorSpace(PDFColorSpacePointer baseColorSpace, QByteArray&& colors, int maxValue);
explicit PDFIndexedColorSpace(PDFColorSpacePointer baseColorSpace, QByteArray&& colors, int maxValue);
virtual ~PDFIndexedColorSpace() = default;
virtual QColor getDefaultColor() const override;
@ -394,7 +396,29 @@ private:
int m_maxValue;
};
// TODO: Implement Separation color space
class PDFSeparationColorSpace : public PDFAbstractColorSpace
{
public:
explicit PDFSeparationColorSpace(QByteArray&& colorName, PDFColorSpacePointer alternateColorSpace, PDFFunctionPtr tintTransform);
virtual ~PDFSeparationColorSpace() = default;
virtual QColor getDefaultColor() const override;
virtual QColor getColor(const PDFColor& color) const override;
virtual size_t getColorComponentCount() const override;
/// Creates separation color space from provided values.
/// \param colorSpaceDictionary Color space dictionary
/// \param document Document
/// \param array Array with separation color space definition
/// \param recursion Recursion guard
static PDFColorSpacePointer createSeparationColorSpace(const PDFDictionary* colorSpaceDictionary, const PDFDocument* document, const PDFArray* array, int recursion);
private:
QByteArray m_colorName;
PDFColorSpacePointer m_alternateColorSpace;
PDFFunctionPtr m_tintTransform;
};
// TODO: Implement DeviceN color space
// TODO: Implement Pattern color space

View File

@ -58,6 +58,8 @@ public:
}
using value_type = T;
/// Returns the size of the array
size_t size() const { return getFlatBlockSize() + m_variableBlock.size(); }

View File

@ -311,10 +311,12 @@ void PDFPageContentProcessor::processContentStream(const PDFStream* stream)
}
catch (PDFParserException exception)
{
m_operands.clear();
m_errorList.append(PDFRenderError(RenderErrorType::Error, exception.getMessage()));
}
catch (PDFRendererException exception)
{
m_operands.clear();
m_errorList.append(exception.getError());
}
}
@ -1061,12 +1063,14 @@ void PDFPageContentProcessor::operatorEndSubpath()
void PDFPageContentProcessor::operatorRectangle(PDFReal x, PDFReal y, PDFReal width, PDFReal height)
{
if (width < 0 || height < 0)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid size of rectangle (%1 x %2).").arg(width).arg(height));
}
const PDFReal xMin = qMin(x, x + width);
const PDFReal xMax = qMax(x, x + width);
const PDFReal yMin = qMin(y, y + height);
const PDFReal yMax = qMax(y, y + height);
const PDFReal correctedWidth = xMax - xMin;
const PDFReal correctedHeight = yMax - yMin;
m_currentPath.addRect(QRectF(x, y, width, height));
m_currentPath.addRect(QRectF(xMin, yMin, correctedWidth, correctedHeight));
}
void PDFPageContentProcessor::operatorPathStroke()
@ -1233,8 +1237,10 @@ void PDFPageContentProcessor::operatorColorSetStrokingColor()
void PDFPageContentProcessor::operatorColorSetStrokingColorN()
{
// TODO: Implement operator SCN
throw PDFRendererException(RenderErrorType::NotImplemented, PDFTranslationContext::tr("Not implemented!"));
// In our implementation, operator 'SC' can also set color using all color spaces
// PDF reference 1.7 allows here Pattern, Separation, DeviceN and ICCBased color spaces here,
// but default operator can use them (with exception of Pattern color space).
operatorColorSetStrokingColor();
}
void PDFPageContentProcessor::operatorColorSetFillingColor()
@ -1261,8 +1267,10 @@ void PDFPageContentProcessor::operatorColorSetFillingColor()
void PDFPageContentProcessor::operatorColorSetFillingColorN()
{
// TODO: Implement operator scn
throw PDFRendererException(RenderErrorType::NotImplemented, PDFTranslationContext::tr("Not implemented!"));
// In our implementation, operator 'sc' can also set color using all color spaces
// PDF reference 1.7 allows here Pattern, Separation, DeviceN and ICCBased color spaces here,
// but default operator can use them (with exception of Pattern color space).
operatorColorSetFillingColor();
}
void PDFPageContentProcessor::operatorColorSetDeviceGrayStroking(PDFReal gray)

View File

@ -75,14 +75,7 @@ void PDFPainter::performPathPainting(const QPainterPath& path, bool stroke, bool
void PDFPainter::performClipping(const QPainterPath& path, Qt::FillRule fillRule)
{
Q_ASSERT(path.fillRule() == fillRule);
if (m_painter->hasClipping())
{
m_painter->setClipPath(path, Qt::IntersectClip);
}
else
{
addError(PDFTranslationContext::tr("The paint device doesn't support clipping. Path was not clipped."));
}
m_painter->setClipPath(path, Qt::IntersectClip);
}
void PDFPainter::performUpdateGraphicsState(const PDFPageContentProcessorState& state)