From 301c07a23e4376f8bdd40654681fbc7fea7e1234 Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Mon, 8 Mar 2021 19:16:39 +0100 Subject: [PATCH] Function shading sampler --- Pdf4QtLib/sources/pdfpattern.cpp | 100 +++++++++++++++++++++++++++++++ Pdf4QtLib/sources/pdfpattern.h | 5 ++ 2 files changed, 105 insertions(+) diff --git a/Pdf4QtLib/sources/pdfpattern.cpp b/Pdf4QtLib/sources/pdfpattern.cpp index 9957510..7e5dd17 100644 --- a/Pdf4QtLib/sources/pdfpattern.cpp +++ b/Pdf4QtLib/sources/pdfpattern.cpp @@ -502,6 +502,101 @@ PDFPatternPtr PDFPattern::createShadingPattern(const PDFDictionary* colorSpaceDi return PDFPatternPtr(); } +class PDFFunctionShadingSampler : public PDFShadingSampler +{ +public: + PDFFunctionShadingSampler(const PDFFunctionShading* functionShadingPattern, QMatrix userSpaceToDeviceSpaceMatrix) : + PDFShadingSampler(functionShadingPattern), + m_functionShadingPattern(functionShadingPattern), + m_domain(functionShadingPattern->getDomain()) + { + QMatrix patternSpaceToDeviceSpaceMatrix = functionShadingPattern->getMatrix() * userSpaceToDeviceSpaceMatrix; + QMatrix domainToDeviceSpaceMatrix = functionShadingPattern->getDomainToTargetTransform() * patternSpaceToDeviceSpaceMatrix; + + if (domainToDeviceSpaceMatrix.isInvertible()) + { + m_deviceSpaceToDomainMatrix = domainToDeviceSpaceMatrix.inverted(); + } + else + { + m_deviceSpaceToDomainMatrix = QMatrix(); + } + } + + virtual bool sample(const QPointF& devicePoint, PDFColorBuffer outputBuffer, int limit) const override + { + Q_UNUSED(limit); + + if (!m_pattern->getColorSpace() || m_pattern->getColorSpace()->getColorComponentCount() != outputBuffer.size()) + { + // Invalid color space, or invalid color buffer + return false; + } + + QPointF domainPoint = m_deviceSpaceToDomainMatrix.map(devicePoint); + + if (!m_domain.contains(domainPoint)) + { + return fillBackgroundColor(outputBuffer); + } + + const auto& functions = m_functionShadingPattern->getFunctions(); + std::array colorBuffer = { }; + + if (colorBuffer.size() < outputBuffer.size()) + { + // Jakub Melka: Too much colors - we cant process it + return false; + } + + std::array input = { domainPoint.x(), domainPoint.y() }; + + if (functions.size() == 1) + { + Q_ASSERT(outputBuffer.size() <= colorBuffer.size()); + PDFFunction::FunctionResult result = functions.front()->apply(input.data(), input.data() + input.size(), colorBuffer.data(), colorBuffer.data() + outputBuffer.size()); + + if (!result) + { + // Function call failed + return false; + } + } + else + { + if (functions.size() != outputBuffer.size()) + { + // Invalid number of functions + return false; + } + + Q_ASSERT(outputBuffer.size() <= colorBuffer.size()); + for (size_t i = 0, count = outputBuffer.size(); i < count; ++i) + { + PDFFunction::FunctionResult result = functions[i]->apply(input.data(), input.data() + input.size(), colorBuffer.data() + i, colorBuffer.data() + i + 1); + + if (!result) + { + // Function call failed + return false; + } + } + } + + for (size_t i = 0, count = outputBuffer.size(); i < count; ++i) + { + outputBuffer[i] = colorBuffer[i]; + } + + return true; + } + +private: + const PDFFunctionShading* m_functionShadingPattern; + QRectF m_domain; + QMatrix m_deviceSpaceToDomainMatrix; +}; + ShadingType PDFFunctionShading::getShadingType() const { return ShadingType::Function; @@ -810,6 +905,11 @@ PDFMesh PDFFunctionShading::createMesh(const PDFMeshQualitySettings& settings, c return mesh; } +PDFShadingSampler* PDFFunctionShading::createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const +{ + return new PDFFunctionShadingSampler(this, userSpaceToDeviceSpaceMatrix); +} + PDFMesh PDFAxialShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const { PDFMesh mesh; diff --git a/Pdf4QtLib/sources/pdfpattern.h b/Pdf4QtLib/sources/pdfpattern.h index 4e415d4..4e5d767 100644 --- a/Pdf4QtLib/sources/pdfpattern.h +++ b/Pdf4QtLib/sources/pdfpattern.h @@ -383,6 +383,11 @@ public: virtual ShadingType getShadingType() const override; virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override; + virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override; + + const QRectF& getDomain() const { return m_domain; } + const QMatrix& getDomainToTargetTransform() const { return m_domainToTargetTransform; } + const std::vector& getFunctions() const { return m_functions; } private: friend class PDFPattern;