diff --git a/Pdf4QtLib/sources/pdfblendfunction.cpp b/Pdf4QtLib/sources/pdfblendfunction.cpp index 18bf83f..95ad1ec 100644 --- a/Pdf4QtLib/sources/pdfblendfunction.cpp +++ b/Pdf4QtLib/sources/pdfblendfunction.cpp @@ -99,6 +99,7 @@ bool PDFBlendModeInfo::isSeparable(BlendMode mode) case BlendMode::Compatible: case BlendMode::Overprint_SelectBackdrop: case BlendMode::Overprint_SelectNonZeroSourceOrBackdrop: + case BlendMode::Overprint_SelectNonOneSourceOrBackdrop: return true; case BlendMode::Hue: @@ -354,6 +355,16 @@ PDFColorComponent PDFBlendFunction::blend(BlendMode mode, PDFColorComponent Cb, return Cs; } + case BlendMode::Overprint_SelectNonOneSourceOrBackdrop: + { + if (qFuzzyIsNull(1.0f - Cs)) + { + return Cb; + } + + return Cs; + } + default: { Q_ASSERT(false); diff --git a/Pdf4QtLib/sources/pdfblendfunction.h b/Pdf4QtLib/sources/pdfblendfunction.h index dbf9270..ab5a011 100644 --- a/Pdf4QtLib/sources/pdfblendfunction.h +++ b/Pdf4QtLib/sources/pdfblendfunction.h @@ -54,6 +54,7 @@ enum class BlendMode // Special blend modes for handling overprint. Used only internally. Overprint_SelectBackdrop, Overprint_SelectNonZeroSourceOrBackdrop, + Overprint_SelectNonOneSourceOrBackdrop, // Invalid blending mode - for internal purposes only Invalid diff --git a/Pdf4QtLib/sources/pdftransparencyrenderer.cpp b/Pdf4QtLib/sources/pdftransparencyrenderer.cpp index 26bb7e2..4ec443b 100644 --- a/Pdf4QtLib/sources/pdftransparencyrenderer.cpp +++ b/Pdf4QtLib/sources/pdftransparencyrenderer.cpp @@ -215,7 +215,8 @@ void PDFFloatBitmap::blend(const PDFFloatBitmap& source, else { // Color channel is active, but select source color only, if it is nonzero - channelBlendModes[colorChannelIndex] = BlendMode::Overprint_SelectNonZeroSourceOrBackdrop; + channelBlendModes[colorChannelIndex] = pixelFormat.hasSpotColorsSubtractive() ? BlendMode::Overprint_SelectNonOneSourceOrBackdrop + : BlendMode::Overprint_SelectNonZeroSourceOrBackdrop; } } } @@ -752,4 +753,105 @@ bool PDFTransparencyRenderer::isTransparencyGroupKnockout() const return m_transparencyGroupDataStack.back().group.knockout; } +PDFInkMapper::PDFInkMapper(const PDFDocument* document) : + m_document(document) +{ + +} + +void PDFInkMapper::createSpotColors(bool activate) +{ + m_spotColors.clear(); + + const PDFCatalog* catalog = m_document->getCatalog(); + const size_t pageCount = catalog->getPageCount(); + for (size_t i = 0; i < pageCount; ++i) + { + const PDFPage* page = catalog->getPage(i); + PDFObject resources = m_document->getObject(page->getResources()); + + if (resources.isDictionary() && resources.getDictionary()->hasKey("ColorSpace")) + { + const PDFDictionary* colorSpaceDictionary = m_document->getDictionaryFromObject(resources.getDictionary()->get("ColorSpace")); + if (colorSpaceDictionary) + { + std::size_t colorSpaces = colorSpaceDictionary->getCount(); + for (size_t csIndex = 0; csIndex < colorSpaces; ++ csIndex) + { + PDFColorSpacePointer colorSpacePointer = PDFAbstractColorSpace::createColorSpace(colorSpaceDictionary, m_document, colorSpaceDictionary->getValue(csIndex)); + + if (!colorSpacePointer) + { + continue; + } + + switch (colorSpacePointer->getColorSpace()) + { + case PDFAbstractColorSpace::ColorSpace::Separation: + { + const PDFSeparationColorSpace* separationColorSpace = dynamic_cast(colorSpacePointer.data()); + + if (!separationColorSpace->isNone() && !separationColorSpace->isAll() && !separationColorSpace->getColorName().isEmpty()) + { + // Try to add spot color + const QByteArray& colorName = separationColorSpace->getColorName(); + if (!containsSpotColor(colorName)) + { + SpotColorInfo info; + info.name = colorName; + info.colorSpace = colorSpacePointer; + m_spotColors.emplace_back(qMove(info)); + } + } + + break; + } + + case PDFAbstractColorSpace::ColorSpace::DeviceN: + { + const PDFDeviceNColorSpace* deviceNColorSpace = dynamic_cast(colorSpacePointer.data()); + + if (!deviceNColorSpace->isNone()) + { + const PDFDeviceNColorSpace::Colorants& colorants = deviceNColorSpace->getColorants(); + for (size_t i = 0; i < colorants.size(); ++i) + { + const PDFDeviceNColorSpace::ColorantInfo& colorantInfo = colorants[i]; + if (!containsSpotColor(colorantInfo.name)) + { + SpotColorInfo info; + info.name = colorantInfo.name; + info.index = i; + info.colorSpace = colorSpacePointer; + m_spotColors.emplace_back(qMove(info)); + } + } + } + + break; + } + + default: + break; + } + } + } + } + } + + if (activate) + { + size_t minIndex = qMin(m_spotColors.size(), MAX_SPOT_COLOR_COMPONENTS); + for (size_t i = 0; i < minIndex; ++i) + { + m_spotColors[i].active = true; + } + } +} + +bool PDFInkMapper::containsSpotColor(const QByteArray& colorName) const +{ + return getSpotColor(colorName) != nullptr; +} + } // namespace pdf diff --git a/Pdf4QtLib/sources/pdftransparencyrenderer.h b/Pdf4QtLib/sources/pdftransparencyrenderer.h index a78315d..fdf3d43 100644 --- a/Pdf4QtLib/sources/pdftransparencyrenderer.h +++ b/Pdf4QtLib/sources/pdftransparencyrenderer.h @@ -21,6 +21,7 @@ #include "pdfglobal.h" #include "pdfcolorspaces.h" #include "pdfpagecontentprocessor.h" +#include "pdfconstants.h" namespace pdf { @@ -235,6 +236,38 @@ private: PDFColorSpacePointer m_colorSpace; }; +/// Ink mapper for mapping device inks (device colors) and spot inks (spot colors). +class PDFInkMapper +{ +public: + explicit PDFInkMapper(const PDFDocument* document); + + struct SpotColorInfo + { + QByteArray name; + uint32_t index = 0; ///< Index into DeviceN color space (index of colorant) + PDFColorSpacePointer colorSpace; + bool active = false; ///< Is spot color active? + }; + + static constexpr const uint32_t MAX_COLOR_COMPONENTS = PDF_MAX_COLOR_COMPONENTS; + static constexpr const uint32_t MAX_DEVICE_COLOR_COMPONENTS = 4; + static constexpr const uint32_t MAX_SPOT_COLOR_COMPONENTS = MAX_COLOR_COMPONENTS - MAX_DEVICE_COLOR_COMPONENTS - 2; + + /// Scan document for spot colors and fills color info + /// \param activate Set spot colors active? + void createSpotColors(bool activate); + + /// Returns true, if mapper contains given spot color + /// \param colorName Color name + bool containsSpotColor(const QByteArray& colorName) const; + +private: + + const PDFDocument* m_document; + std::vector m_spotColors; +}; + /// 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