mirror of https://github.com/JakubMelka/PDF4QT.git
Color spaces and images - bugfixing, compliance to PDF 2.0 specification
This commit is contained in:
parent
8eedb45576
commit
7129793109
|
@ -1401,7 +1401,7 @@ PDFSeparationColorSpace::PDFSeparationColorSpace(QByteArray&& colorName, PDFColo
|
|||
|
||||
QColor PDFSeparationColorSpace::getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
{
|
||||
return getColor(PDFColor(0.0f), cms, intent, reporter);
|
||||
return getColor(PDFColor(1.0f), cms, intent, reporter);
|
||||
}
|
||||
|
||||
QColor PDFSeparationColorSpace::getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
|
@ -1528,9 +1528,10 @@ PDFDeviceNColorSpace::PDFDeviceNColorSpace(PDFDeviceNColorSpace::Type type,
|
|||
m_processColorSpace(qMove(processColorSpace)),
|
||||
m_tintTransform(qMove(tintTransform)),
|
||||
m_colorantsPrintingOrder(qMove(colorantsPrintingOrder)),
|
||||
m_processColorSpaceComponents(qMove(processColorSpaceComponents))
|
||||
m_processColorSpaceComponents(qMove(processColorSpaceComponents)),
|
||||
m_isNone(false)
|
||||
{
|
||||
|
||||
m_isNone = std::all_of(m_colorants.cbegin(), m_colorants.cend(), [](const auto& colorant) { return colorant.name == "None"; });
|
||||
}
|
||||
|
||||
QColor PDFDeviceNColorSpace::getDefaultColor(const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
|
@ -1550,6 +1551,13 @@ QColor PDFDeviceNColorSpace::getDefaultColor(const PDFCMS* cms, RenderingIntent
|
|||
|
||||
QColor PDFDeviceNColorSpace::getColor(const PDFColor& color, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
|
||||
{
|
||||
// According to the PDF 2.0 specification, DeviceN color space, with all colorant name "None"
|
||||
// should not produce any visible output.
|
||||
if (m_isNone)
|
||||
{
|
||||
return Qt::transparent;
|
||||
}
|
||||
|
||||
// Input values
|
||||
std::vector<double> inputColor(color.size(), 0.0);
|
||||
for (size_t i = 0, count = inputColor.size(); i < count; ++i)
|
||||
|
|
|
@ -678,6 +678,14 @@ public:
|
|||
/// Returns type of DeviceN color space
|
||||
Type getType() const { return m_type; }
|
||||
|
||||
const Colorants& getColorants() const { return m_colorants; }
|
||||
const PDFColorSpacePointer& getAlternateColorSpace() const { return m_alternateColorSpace; }
|
||||
const PDFColorSpacePointer& getProcessColorSpace() const { return m_processColorSpace; }
|
||||
const PDFFunctionPtr& getTintTransform() const { return m_tintTransform; }
|
||||
const std::vector<QByteArray>& getPrintingOrder() const { return m_colorantsPrintingOrder; }
|
||||
const std::vector<QByteArray>& getProcessColorSpaceComponents() const { return m_processColorSpaceComponents; }
|
||||
bool isNone() const { return m_isNone; }
|
||||
|
||||
/// Creates DeviceN color space from provided values.
|
||||
/// \param colorSpaceDictionary Color space dictionary
|
||||
/// \param document Document
|
||||
|
@ -698,6 +706,7 @@ private:
|
|||
PDFFunctionPtr m_tintTransform;
|
||||
std::vector<QByteArray> m_colorantsPrintingOrder;
|
||||
std::vector<QByteArray> m_processColorSpaceComponents;
|
||||
bool m_isNone;
|
||||
};
|
||||
|
||||
class PDFPatternColorSpace : public PDFAbstractColorSpace
|
||||
|
|
|
@ -73,6 +73,17 @@ PDFImage PDFImage::createImage(const PDFDocument* document,
|
|||
bool imageMask = loader.readBooleanFromDictionary(dictionary, "ImageMask", false);
|
||||
std::vector<PDFReal> matte = loader.readNumberArrayFromDictionary(dictionary, "Matte");
|
||||
PDFInteger sMaskInData = loader.readIntegerFromDictionary(dictionary, "SMaskInData", 0);
|
||||
image.m_interpolate = loader.readBooleanFromDictionary(dictionary, "Interpolate", false);
|
||||
image.m_alternates = loader.readObjectList<PDFAlternateImage>(dictionary->get("Alternates"));
|
||||
image.m_name = loader.readNameFromDictionary(dictionary, "Name");
|
||||
image.m_structuralParent = loader.readIntegerFromDictionary(dictionary, "StructParent", 0);
|
||||
image.m_webCaptureContentSetId = loader.readStringFromDictionary(dictionary, "ID");
|
||||
image.m_OPI = dictionary->get("OPI");
|
||||
image.m_OC = dictionary->get("OC");
|
||||
image.m_metadata = dictionary->get("Metadata");
|
||||
image.m_associatedFiles = dictionary->get("AF");
|
||||
image.m_measure = dictionary->get("Measure");
|
||||
image.m_pointData = dictionary->get("PtData");
|
||||
|
||||
if (isSoftMask && (imageMask || dictionary->hasKey("Mask") || dictionary->hasKey("SMask")))
|
||||
{
|
||||
|
@ -706,9 +717,9 @@ PDFImage PDFImage::createImage(const PDFDocument* document,
|
|||
}
|
||||
else if (imageMask)
|
||||
{
|
||||
// We intentionally have 8 bits in the following code, because if ImageMask is set to true, then "BitsPerComponent"
|
||||
// should have always value of 1.
|
||||
const unsigned int bitsPerComponent = static_cast<unsigned int>(loader.readIntegerFromDictionary(dictionary, "BitsPerComponent", 8));
|
||||
// If ImageMask is set to true, then "BitsPerComponent" should have always value of 1.
|
||||
// If this entry is not specified, then the value should be implicitly 1.
|
||||
const unsigned int bitsPerComponent = static_cast<unsigned int>(loader.readIntegerFromDictionary(dictionary, "BitsPerComponent", 1));
|
||||
|
||||
if (bitsPerComponent != 1)
|
||||
{
|
||||
|
@ -840,6 +851,19 @@ OPJ_OFF_T PDFJPEG2000ImageData::skip(OPJ_OFF_T p_nb_bytes, void* p_user_data)
|
|||
return length;
|
||||
}
|
||||
|
||||
// Implement image rendering intent
|
||||
PDFAlternateImage PDFAlternateImage::parse(const PDFObjectStorage* storage, PDFObject object)
|
||||
{
|
||||
PDFAlternateImage result;
|
||||
|
||||
if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
|
||||
{
|
||||
PDFDocumentDataLoaderDecorator loader(storage);
|
||||
result.m_image = loader.readReferenceFromDictionary(dictionary, "Image");
|
||||
result.m_oc = loader.readReferenceFromDictionary(dictionary, "OC");
|
||||
result.m_defaultForPrinting = loader.readBooleanFromDictionary(dictionary, "DefaultForPrinting", false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#ifndef PDFIMAGE_H
|
||||
#define PDFIMAGE_H
|
||||
|
||||
#include "pdfobject.h"
|
||||
#include "pdfcolorspaces.h"
|
||||
|
||||
#include <QByteArray>
|
||||
|
@ -28,8 +29,31 @@ namespace pdf
|
|||
{
|
||||
class PDFStream;
|
||||
class PDFDocument;
|
||||
class PDFObjectStorage;
|
||||
class PDFRenderErrorReporter;
|
||||
|
||||
/// Alternate image object. Defines alternate image, which
|
||||
/// can be shown in some circumstances instead of main image.
|
||||
class PDFAlternateImage
|
||||
{
|
||||
public:
|
||||
explicit inline PDFAlternateImage() = default;
|
||||
|
||||
/// Parses alternate image dictionary object.
|
||||
/// \param storage Object storage
|
||||
/// \param object Alternate image object
|
||||
static PDFAlternateImage parse(const PDFObjectStorage* storage, PDFObject object);
|
||||
|
||||
PDFObjectReference getImage() const { return m_image; }
|
||||
PDFObjectReference getOc() const { return m_oc; }
|
||||
bool isDefaultForPrinting() const { return m_defaultForPrinting; }
|
||||
|
||||
private:
|
||||
PDFObjectReference m_image;
|
||||
PDFObjectReference m_oc;
|
||||
bool m_defaultForPrinting = false;
|
||||
};
|
||||
|
||||
class PDFImage
|
||||
{
|
||||
public:
|
||||
|
@ -54,6 +78,33 @@ public:
|
|||
/// Returns rendering intent of the image
|
||||
RenderingIntent getRenderingIntent() const { return m_renderingIntent; }
|
||||
|
||||
/// Color space of image samples
|
||||
const PDFColorSpacePointer& getColorSpace() const { return m_colorSpace; }
|
||||
|
||||
/// Should PDF processor perform interpolation on this image?
|
||||
bool isInterpolated() const { return m_interpolate; }
|
||||
|
||||
/// Array of alternate images
|
||||
const std::vector<PDFAlternateImage>& getAlternates() const { return m_alternates; }
|
||||
|
||||
/// Returns name of image, under which is referenced in resources dictionary.
|
||||
/// It was mandatory in PDF 1.0, otherwise it is optional and now it is deprecated
|
||||
/// in PDF 2.0 specification.
|
||||
const QByteArray& getName() const { return m_name; }
|
||||
|
||||
/// Returns idenfitier to structural parent in structure tree
|
||||
PDFInteger getStructuralParent() const { return m_structuralParent; }
|
||||
|
||||
/// Web capture content set identifier
|
||||
const QByteArray& getWebCaptureContentSetID() const { return m_webCaptureContentSetId; }
|
||||
|
||||
const PDFObject& getOPI() const { return m_OPI; }
|
||||
const PDFObject& getOC() const { return m_OC; }
|
||||
const PDFObject& getMetadata() const { return m_metadata; }
|
||||
const PDFObject& getAssociatedFiles() const { return m_associatedFiles; }
|
||||
const PDFObject& getMeasure() const { return m_measure; }
|
||||
const PDFObject& getPointData() const { return m_pointData; }
|
||||
|
||||
private:
|
||||
PDFImage() = default;
|
||||
|
||||
|
@ -61,6 +112,17 @@ private:
|
|||
PDFImageData m_softMask;
|
||||
PDFColorSpacePointer m_colorSpace;
|
||||
RenderingIntent m_renderingIntent = RenderingIntent::Perceptual;
|
||||
bool m_interpolate = false;
|
||||
std::vector<PDFAlternateImage> m_alternates;
|
||||
QByteArray m_name;
|
||||
QByteArray m_webCaptureContentSetId;
|
||||
PDFInteger m_structuralParent = 0;
|
||||
PDFObject m_OPI;
|
||||
PDFObject m_OC;
|
||||
PDFObject m_metadata;
|
||||
PDFObject m_associatedFiles;
|
||||
PDFObject m_measure;
|
||||
PDFObject m_pointData;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
|
|
@ -500,7 +500,11 @@ void PDFPageContentProcessor::processContent(const QByteArray& content)
|
|||
{ "H", "Height" },
|
||||
{ "IM", "ImageMask" },
|
||||
{ "I", "Interpolate" },
|
||||
{ "W", "Width" }
|
||||
{ "W", "Width" },
|
||||
{ "L", "Length" },
|
||||
{ "G", "DeviceGray" },
|
||||
{ "RGB", "DeviceRGB" },
|
||||
{ "CMYK", "DeviceCMYK" }
|
||||
};
|
||||
|
||||
std::shared_ptr<PDFDictionary> dictionarySharedPointer = std::make_shared<PDFDictionary>();
|
||||
|
|
Loading…
Reference in New Issue