Color spaces - update according to the PDF 2.0 specification

This commit is contained in:
Jakub Melka
2020-08-11 17:46:03 +02:00
parent c033de6917
commit 8eedb45576
3 changed files with 43 additions and 7 deletions

View File

@ -726,7 +726,7 @@ PDFColorSpacePointer PDFAbstractColorSpace::createDeviceColorSpaceByNameImpl(con
return PDFColorSpacePointer(new PDFDeviceRGBColorSpace()); return PDFColorSpacePointer(new PDFDeviceRGBColorSpace());
} }
} }
else if (name == COLOR_SPACE_NAME_DEVICE_CMYK || name == COLOR_SPACE_NAME_ABBREVIATION_DEVICE_CMYK) else if (name == COLOR_SPACE_NAME_DEVICE_CMYK || name == COLOR_SPACE_NAME_ABBREVIATION_DEVICE_CMYK || name == COLOR_SPACE_NAME_ABBREVIATION_CAL_CMYK)
{ {
if (colorSpaceDictionary && colorSpaceDictionary->hasKey(COLOR_SPACE_NAME_DEFAULT_CMYK) && !isNameAlreadyProcessed) if (colorSpaceDictionary && colorSpaceDictionary->hasKey(COLOR_SPACE_NAME_DEFAULT_CMYK) && !isNameAlreadyProcessed)
{ {
@ -1053,10 +1053,11 @@ PDFColorSpacePointer PDFLabColorSpace::createLabColorSpace(const PDFDocument* do
return PDFColorSpacePointer(new PDFLabColorSpace(whitePoint, blackPoint, minMax[0], minMax[1], minMax[2], minMax[3])); return PDFColorSpacePointer(new PDFLabColorSpace(whitePoint, blackPoint, minMax[0], minMax[1], minMax[2], minMax[3]));
} }
PDFICCBasedColorSpace::PDFICCBasedColorSpace(PDFColorSpacePointer alternateColorSpace, Ranges range, QByteArray iccProfileData) : PDFICCBasedColorSpace::PDFICCBasedColorSpace(PDFColorSpacePointer alternateColorSpace, Ranges range, QByteArray iccProfileData, PDFObjectReference metadata) :
m_alternateColorSpace(qMove(alternateColorSpace)), m_alternateColorSpace(qMove(alternateColorSpace)),
m_range(range), m_range(range),
m_iccProfileData(qMove(iccProfileData)) m_iccProfileData(qMove(iccProfileData)),
m_metadata(metadata)
{ {
// Compute checksum // Compute checksum
m_iccProfileDataChecksum = QCryptographicHash::hash(m_iccProfileData, QCryptographicHash::Md5); m_iccProfileDataChecksum = QCryptographicHash::hash(m_iccProfileData, QCryptographicHash::Md5);
@ -1190,7 +1191,7 @@ PDFColorSpacePointer PDFICCBasedColorSpace::createICCBasedColorSpace(const PDFDi
auto itEnd = std::next(itStart, rangeSize); auto itEnd = std::next(itStart, rangeSize);
loader.readNumberArrayFromDictionary(dictionary, ICCBASED_RANGE, itStart, itEnd); loader.readNumberArrayFromDictionary(dictionary, ICCBASED_RANGE, itStart, itEnd);
return PDFColorSpacePointer(new PDFICCBasedColorSpace(qMove(alternateColorSpace), ranges, qMove(iccProfileData))); return PDFColorSpacePointer(new PDFICCBasedColorSpace(qMove(alternateColorSpace), ranges, qMove(iccProfileData), loader.readReferenceFromDictionary(dictionary, "Metadata")));
} }
PDFIndexedColorSpace::PDFIndexedColorSpace(PDFColorSpacePointer baseColorSpace, QByteArray&& colors, int maxValue) : PDFIndexedColorSpace::PDFIndexedColorSpace(PDFColorSpacePointer baseColorSpace, QByteArray&& colors, int maxValue) :
@ -1391,7 +1392,9 @@ PDFColorSpacePointer PDFIndexedColorSpace::createIndexedColorSpace(const PDFDict
PDFSeparationColorSpace::PDFSeparationColorSpace(QByteArray&& colorName, PDFColorSpacePointer alternateColorSpace, PDFFunctionPtr tintTransform) : PDFSeparationColorSpace::PDFSeparationColorSpace(QByteArray&& colorName, PDFColorSpacePointer alternateColorSpace, PDFFunctionPtr tintTransform) :
m_colorName(qMove(colorName)), m_colorName(qMove(colorName)),
m_alternateColorSpace(qMove(alternateColorSpace)), m_alternateColorSpace(qMove(alternateColorSpace)),
m_tintTransform(qMove(tintTransform)) m_tintTransform(qMove(tintTransform)),
m_isNone(m_colorName == "None"),
m_isAll(m_colorName == "All")
{ {
} }
@ -1406,9 +1409,25 @@ QColor PDFSeparationColorSpace::getColor(const PDFColor& color, const PDFCMS* cm
// Separation color space value must have exactly one component! // Separation color space value must have exactly one component!
Q_ASSERT(color.size() == 1); Q_ASSERT(color.size() == 1);
// According to the PDF 2.0 specification, separation color space, with colorant name "None"
// should not produce any visible output.
if (m_isNone)
{
return Qt::transparent;
}
// Input value // Input value
double tint = color.back(); double tint = color.back();
// Jakub Melka: According to the PDF 2.0 specification, separation color space, with colorant name "All"
// should apply tint value to all output colorants, alternate color space and tint function should
// be ignored, and because QColor is aditive, we must invert the tint value.
if (m_isAll)
{
const double inversedTint = qBound(0.0, 1.0 - tint, 1.0);
return QColor::fromRgbF(inversedTint, inversedTint, inversedTint);
}
// Output values // Output values
std::vector<double> outputColor; std::vector<double> outputColor;
outputColor.resize(m_alternateColorSpace->getColorComponentCount(), 0.0); outputColor.resize(m_alternateColorSpace->getColorComponentCount(), 0.0);
@ -1518,6 +1537,14 @@ QColor PDFDeviceNColorSpace::getDefaultColor(const PDFCMS* cms, RenderingIntent
{ {
PDFColor color; PDFColor color;
color.resize(getColorComponentCount()); color.resize(getColorComponentCount());
// Jakub Melka: According to the PDF 2.0 specification, each channel should
// be initially set to 1.0.
for (size_t i = 0, colorComponentCount = color.size(); i < colorComponentCount; ++i)
{
color[i] = 1.0;
}
return getColor(color, cms, intent, reporter); return getColor(color, cms, intent, reporter);
} }

View File

@ -55,6 +55,7 @@ static constexpr const char* COLOR_SPACE_NAME_DEVICE_CMYK = "DeviceCMYK";
static constexpr const char* COLOR_SPACE_NAME_ABBREVIATION_DEVICE_GRAY = "G"; static constexpr const char* COLOR_SPACE_NAME_ABBREVIATION_DEVICE_GRAY = "G";
static constexpr const char* COLOR_SPACE_NAME_ABBREVIATION_DEVICE_RGB = "RGB"; static constexpr const char* COLOR_SPACE_NAME_ABBREVIATION_DEVICE_RGB = "RGB";
static constexpr const char* COLOR_SPACE_NAME_ABBREVIATION_DEVICE_CMYK = "CMYK"; static constexpr const char* COLOR_SPACE_NAME_ABBREVIATION_DEVICE_CMYK = "CMYK";
static constexpr const char* COLOR_SPACE_NAME_ABBREVIATION_CAL_CMYK = "CalCMYK";
static constexpr const char* COLOR_SPACE_NAME_DEFAULT_GRAY = "DefaultGray"; static constexpr const char* COLOR_SPACE_NAME_DEFAULT_GRAY = "DefaultGray";
static constexpr const char* COLOR_SPACE_NAME_DEFAULT_RGB = "DefaultRGB"; static constexpr const char* COLOR_SPACE_NAME_DEFAULT_RGB = "DefaultRGB";
@ -542,7 +543,7 @@ public:
static constexpr const size_t MAX_COLOR_COMPONENTS = 4; static constexpr const size_t MAX_COLOR_COMPONENTS = 4;
using Ranges = std::array<PDFColorComponent, MAX_COLOR_COMPONENTS * 2>; using Ranges = std::array<PDFColorComponent, MAX_COLOR_COMPONENTS * 2>;
explicit PDFICCBasedColorSpace(PDFColorSpacePointer alternateColorSpace, Ranges range, QByteArray iccProfileData); explicit PDFICCBasedColorSpace(PDFColorSpacePointer alternateColorSpace, Ranges range, QByteArray iccProfileData, PDFObjectReference metadata);
virtual ~PDFICCBasedColorSpace() = default; virtual ~PDFICCBasedColorSpace() = default;
virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override; virtual QColor getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
@ -550,6 +551,8 @@ public:
virtual size_t getColorComponentCount() const override; virtual size_t getColorComponentCount() const override;
virtual void fillRGBBuffer(const std::vector<float>& colors, unsigned char* outputBuffer, RenderingIntent intent, const PDFCMS* cms, PDFRenderErrorReporter* reporter) const override; virtual void fillRGBBuffer(const std::vector<float>& colors, unsigned char* outputBuffer, RenderingIntent intent, const PDFCMS* cms, PDFRenderErrorReporter* reporter) const override;
PDFObjectReference getMetadata() const { return m_metadata; }
/// Creates ICC based color space from provided values. /// Creates ICC based color space from provided values.
/// \param colorSpaceDictionary Color space dictionary /// \param colorSpaceDictionary Color space dictionary
/// \param document Document /// \param document Document
@ -567,6 +570,7 @@ private:
Ranges m_range; Ranges m_range;
QByteArray m_iccProfileData; QByteArray m_iccProfileData;
QByteArray m_iccProfileDataChecksum; QByteArray m_iccProfileDataChecksum;
PDFObjectReference m_metadata;
}; };
class PDFIndexedColorSpace : public PDFAbstractColorSpace class PDFIndexedColorSpace : public PDFAbstractColorSpace
@ -615,6 +619,9 @@ public:
virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override; virtual QColor getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
virtual size_t getColorComponentCount() const override; virtual size_t getColorComponentCount() const override;
bool isNone() const { return m_isNone; }
bool isAll() const { return m_isAll; }
/// Creates separation color space from provided values. /// Creates separation color space from provided values.
/// \param colorSpaceDictionary Color space dictionary /// \param colorSpaceDictionary Color space dictionary
/// \param document Document /// \param document Document
@ -631,6 +638,8 @@ private:
QByteArray m_colorName; QByteArray m_colorName;
PDFColorSpacePointer m_alternateColorSpace; PDFColorSpacePointer m_alternateColorSpace;
PDFFunctionPtr m_tintTransform; PDFFunctionPtr m_tintTransform;
bool m_isNone;
bool m_isAll;
}; };
class PDFDeviceNColorSpace : public PDFAbstractColorSpace class PDFDeviceNColorSpace : public PDFAbstractColorSpace

View File

@ -467,7 +467,7 @@ PDFImage PDFImage::createImage(const PDFDocument* document,
{ {
QByteArray iccProfileData(reinterpret_cast<const char*>(jpegImage->icc_profile_buf), jpegImage->icc_profile_len); QByteArray iccProfileData(reinterpret_cast<const char*>(jpegImage->icc_profile_buf), jpegImage->icc_profile_len);
PDFICCBasedColorSpace::Ranges ranges = { 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0 }; PDFICCBasedColorSpace::Ranges ranges = { 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0 };
image.m_colorSpace.reset(new PDFICCBasedColorSpace(image.m_colorSpace, ranges, qMove(iccProfileData))); image.m_colorSpace.reset(new PDFICCBasedColorSpace(image.m_colorSpace, ranges, qMove(iccProfileData), PDFObjectReference()));
} }
} }