mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	Sampling - free gourad triangle mesh
This commit is contained in:
		| @@ -45,6 +45,11 @@ QMatrix PDFShadingPattern::getPatternSpaceToDeviceSpaceMatrix(const PDFMeshQuali | |||||||
|     return m_matrix * settings.userSpaceToDeviceSpaceMatrix; |     return m_matrix * settings.userSpaceToDeviceSpaceMatrix; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | QMatrix PDFShadingPattern::getPatternSpaceToDeviceSpaceMatrix(const QMatrix& userSpaceToDeviceSpaceMatrix) const | ||||||
|  | { | ||||||
|  |     return m_matrix * userSpaceToDeviceSpaceMatrix; | ||||||
|  | } | ||||||
|  |  | ||||||
| PDFShadingSampler* PDFShadingPattern::createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const | PDFShadingSampler* PDFShadingPattern::createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const | ||||||
| { | { | ||||||
|     Q_UNUSED(userSpaceToDeviceSpaceMatrix); |     Q_UNUSED(userSpaceToDeviceSpaceMatrix); | ||||||
| @@ -1968,16 +1973,151 @@ PDFShadingSampler* PDFRadialShading::createSampler(QMatrix userSpaceToDeviceSpac | |||||||
|     return new PDFRadialShadingSampler(this, userSpaceToDeviceSpaceMatrix); |     return new PDFRadialShadingSampler(this, userSpaceToDeviceSpaceMatrix); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | class PDFTriangleShadingSampler : public PDFShadingSampler | ||||||
|  | { | ||||||
|  | private: | ||||||
|  |     struct Triangle | ||||||
|  |     { | ||||||
|  |         std::array<uint32_t, 3> vertexIndices = { }; | ||||||
|  |         std::array<PDFColor, 3> vertexColors; | ||||||
|  |         QMatrix barycentricCoordinateMatrix; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     PDFTriangleShadingSampler(const PDFType4567Shading* shadingPattern, QMatrix userSpaceToDeviceSpaceMatrix) : | ||||||
|  |         PDFShadingSampler(shadingPattern), | ||||||
|  |         m_type4567ShadingPattern(shadingPattern) | ||||||
|  |     { | ||||||
|  |         Q_UNUSED(userSpaceToDeviceSpaceMatrix); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     virtual bool sample(const QPointF& devicePoint, PDFColorBuffer outputBuffer, int limit) const override | ||||||
|  |     { | ||||||
|  |         Q_UNUSED(limit); | ||||||
|  |  | ||||||
|  |         for (const Triangle& triangle : m_triangles) | ||||||
|  |         { | ||||||
|  |             // Calculate barycentric coordinates | ||||||
|  |             QPointF p3 = m_vertices[triangle.vertexIndices[2]]; | ||||||
|  |             QPointF b1b2 = triangle.barycentricCoordinateMatrix.map(devicePoint - p3); | ||||||
|  |  | ||||||
|  |             const qreal b1 = b1b2.x(); | ||||||
|  |             const qreal b2 = b1b2.y(); | ||||||
|  |             const qreal b3 = 1.0 - b1 - b2; | ||||||
|  |  | ||||||
|  |             if (b1 >= 0.0 && b2 >= 0.0 && b3 >= 0.0 && qFuzzyCompare(b1 + b2 + b3, 1.0)) | ||||||
|  |             { | ||||||
|  |                 // Jakub Melka: we got hit, we are in the triangle. Using the barycentric | ||||||
|  |                 // coordinates, we can calculate result color. | ||||||
|  |  | ||||||
|  |                 const PDFColor& c1 = triangle.vertexColors[0]; | ||||||
|  |                 const PDFColor& c2 = triangle.vertexColors[1]; | ||||||
|  |                 const PDFColor& c3 = triangle.vertexColors[2]; | ||||||
|  |  | ||||||
|  |                 Q_ASSERT(c1.size() == c2.size()); | ||||||
|  |                 Q_ASSERT(c2.size() == c3.size()); | ||||||
|  |  | ||||||
|  |                 const size_t inputColorSize = c1.size(); | ||||||
|  |                 PDFColor interpolatedColor; | ||||||
|  |                 interpolatedColor.resize(inputColorSize); | ||||||
|  |                 for (size_t i = 0; i < inputColorSize; ++i) | ||||||
|  |                 { | ||||||
|  |                     interpolatedColor[i] = c1[i] * b1 + c2[i] * b2 + c3[i] * b3; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 interpolatedColor = m_type4567ShadingPattern->getColor(interpolatedColor); | ||||||
|  |  | ||||||
|  |                 if (interpolatedColor.size() != outputBuffer.size()) | ||||||
|  |                 { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 for (size_t i = 0; i < outputBuffer.size(); ++i) | ||||||
|  |                 { | ||||||
|  |                     outputBuffer[i] = interpolatedColor[i]; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void addTriangle(std::array<uint32_t, 3> vertexIndices, std::array<PDFColor, 3> vertexColors) | ||||||
|  |     { | ||||||
|  |         Triangle triangle; | ||||||
|  |         triangle.vertexIndices = qMove(vertexIndices); | ||||||
|  |         triangle.vertexColors = qMove(vertexColors); | ||||||
|  |  | ||||||
|  |         // Compute barycentric coordinate matrix, which will tranform cartesian coordinates of given | ||||||
|  |         // point in the plane into the barycentric coordinates in the triangle. Barycentric coordinate system | ||||||
|  |         // is three point coordinates (b1, b2, b3), where b1,b2,b3 >= 0 and b1 + b2 + b3 = 1.0, such that | ||||||
|  |         // | ||||||
|  |         // (x, y) = b1 * p1 + b2 * p2 + b3 * p3, where | ||||||
|  |         // triangle consists of vertices p1, p2, p3 and (x, y) is point inside triangle. If requirements | ||||||
|  |         // of b1, b2, b3 are not met, then point doesn't lie in the triangle. | ||||||
|  |         // | ||||||
|  |         // We will use following transformation from caresian plane to barycentric coordinate system: | ||||||
|  |         // Usign equation b1 + b2 + b3 = 1.0 we get b3 = 1.0 - b1 - b2, so we will get following system | ||||||
|  |         // of equations: | ||||||
|  |         // | ||||||
|  |         // x = b1 * x1 + b2 * x2 + (1.0 - b1 - b2) * x3 | ||||||
|  |         // y = b1 * y1 + b2 * y2 + (1.0 - b1 - b2) * y3 | ||||||
|  |         // | ||||||
|  |         // b1 * (x1 - x3) + b2 * (x2 - x3) = x - x3 | ||||||
|  |         // b1 * (y1 - y3) + b2 * (y2 - y3) = y - y3 | ||||||
|  |         // | ||||||
|  |         // Now, we have system of two linear equation of two variables (b1, b2) and b3 can be computed | ||||||
|  |         // easily from equation b1 + b2 + b3 = 1.0. Now, we will introduce matrix B: | ||||||
|  |         // | ||||||
|  |         // B = ( x1 - x3, x2 - x3) | ||||||
|  |         //     ( y1 - y3, y2 - y3) | ||||||
|  |         // | ||||||
|  |         // And we will have final equation: | ||||||
|  |         // | ||||||
|  |         // (b1, b2) = B^-1 * (p - p3) | ||||||
|  |         // | ||||||
|  |  | ||||||
|  |         QPointF p1 = m_vertices[triangle.vertexIndices[0]]; | ||||||
|  |         QPointF p2 = m_vertices[triangle.vertexIndices[1]]; | ||||||
|  |         QPointF p3 = m_vertices[triangle.vertexIndices[2]]; | ||||||
|  |  | ||||||
|  |         QPointF p1p3 = p1 - p3; | ||||||
|  |         QPointF p2p3 = p2 - p3; | ||||||
|  |  | ||||||
|  |         QMatrix B(p1p3.x(), p2p3.x(), p1p3.y(), p2p3.y(), 0.0, 0.0); | ||||||
|  |  | ||||||
|  |         if (!B.isInvertible()) | ||||||
|  |         { | ||||||
|  |             // Jakub Melka: B is is not invertible, triangle is degenerated | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         triangle.barycentricCoordinateMatrix = B.inverted(); | ||||||
|  |         m_triangles.emplace_back(qMove(triangle)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void setVertexArray(std::vector<QPointF>&& vertices) { m_vertices = qMove(vertices); } | ||||||
|  |     void reserveSpaceForTriangles(size_t triangleCount) { m_triangles.reserve(triangleCount); } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     const PDFType4567Shading* m_type4567ShadingPattern; | ||||||
|  |     std::vector<QPointF> m_vertices; | ||||||
|  |     std::vector<Triangle> m_triangles; | ||||||
|  | }; | ||||||
|  |  | ||||||
| ShadingType PDFFreeFormGouradTriangleShading::getShadingType() const | ShadingType PDFFreeFormGouradTriangleShading::getShadingType() const | ||||||
| { | { | ||||||
|     return ShadingType::FreeFormGouradTriangle; |     return ShadingType::FreeFormGouradTriangle; | ||||||
| } | } | ||||||
|  |  | ||||||
| PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const | bool PDFFreeFormGouradTriangleShading::processTriangles(InitializeFunction initializeMeshFunction, | ||||||
|  |                                                         AddTriangleFunction addTriangle, | ||||||
|  |                                                         const QMatrix& userSpaceToDeviceSpaceMatrix, | ||||||
|  |                                                         bool convertColors) const | ||||||
| { | { | ||||||
|     PDFMesh mesh; |     QMatrix patternSpaceToDeviceSpaceMatrix = getPatternSpaceToDeviceSpaceMatrix(userSpaceToDeviceSpaceMatrix); | ||||||
|  |  | ||||||
|     QMatrix patternSpaceToDeviceSpaceMatrix = getPatternSpaceToDeviceSpaceMatrix(settings); |  | ||||||
|     size_t bitsPerVertex = m_bitsPerFlag + 2 * m_bitsPerCoordinate + m_colorComponentCount * m_bitsPerComponent; |     size_t bitsPerVertex = m_bitsPerFlag + 2 * m_bitsPerCoordinate + m_colorComponentCount * m_bitsPerComponent; | ||||||
|     size_t remainder = (8 - (bitsPerVertex % 8)) % 8; |     size_t remainder = (8 - (bitsPerVertex % 8)) % 8; | ||||||
|     bitsPerVertex += remainder; |     bitsPerVertex += remainder; | ||||||
| @@ -1987,21 +2127,12 @@ PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySetting | |||||||
|     if (vertexCount < 3) |     if (vertexCount < 3) | ||||||
|     { |     { | ||||||
|         // No mesh produced |         // No mesh produced | ||||||
|         return mesh; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // We have 3 vertices for start triangle, then for each new vertex, we get |     // We have 3 vertices for start triangle, then for each new vertex, we get | ||||||
|     // a new triangle, or, based on flags, no triangle (if new triangle is processed) |     // a new triangle, or, based on flags, no triangle (if new triangle is processed) | ||||||
|     size_t triangleCount = vertexCount - 2; |     size_t triangleCount = vertexCount - 2; | ||||||
|     mesh.reserve(0, triangleCount); |  | ||||||
|  |  | ||||||
|     struct VertexData |  | ||||||
|     { |  | ||||||
|         uint32_t index = 0; |  | ||||||
|         uint8_t flags = 0; |  | ||||||
|         QPointF position; |  | ||||||
|         PDFColor color; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     const PDFReal vertexScaleRatio = 1.0 / double((static_cast<uint64_t>(1) << m_bitsPerCoordinate) - 1); |     const PDFReal vertexScaleRatio = 1.0 / double((static_cast<uint64_t>(1) << m_bitsPerCoordinate) - 1); | ||||||
|     const PDFReal xScaleRatio = (m_xmax - m_xmin) * vertexScaleRatio; |     const PDFReal xScaleRatio = (m_xmax - m_xmin) * vertexScaleRatio; | ||||||
| @@ -2013,7 +2144,7 @@ PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySetting | |||||||
|     std::vector<QPointF> meshVertices; |     std::vector<QPointF> meshVertices; | ||||||
|     meshVertices.resize(vertexCount); |     meshVertices.resize(vertexCount); | ||||||
|  |  | ||||||
|     auto readVertex = [this, &vertices, &patternSpaceToDeviceSpaceMatrix, &meshVertices, bytesPerVertex, xScaleRatio, yScaleRatio, colorScaleRatio](size_t index) |     auto readVertex = [this, &vertices, &patternSpaceToDeviceSpaceMatrix, &meshVertices, bytesPerVertex, xScaleRatio, yScaleRatio, colorScaleRatio, convertColors](size_t index) | ||||||
|     { |     { | ||||||
|         PDFBitReader reader(&m_data, 8); |         PDFBitReader reader(&m_data, 8); | ||||||
|         reader.seek(index * bytesPerVertex); |         reader.seek(index * bytesPerVertex); | ||||||
| @@ -2034,14 +2165,17 @@ PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySetting | |||||||
|             data.color[i] = cMin + (reader.read(m_bitsPerComponent)) * (cMax - cMin) * colorScaleRatio; |             data.color[i] = cMin + (reader.read(m_bitsPerComponent)) * (cMax - cMin) * colorScaleRatio; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         data.color = getColor(data.color); |         if (convertColors) | ||||||
|  |         { | ||||||
|  |             data.color = getColor(data.color); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         vertices[index] = qMove(data); |         vertices[index] = qMove(data); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     PDFIntegerRange indices(size_t(0), vertexCount); |     PDFIntegerRange indices(size_t(0), vertexCount); | ||||||
|     PDFExecutionPolicy::execute(PDFExecutionPolicy::Scope::Content, indices.begin(), indices.end(), readVertex); |     PDFExecutionPolicy::execute(PDFExecutionPolicy::Scope::Content, indices.begin(), indices.end(), readVertex); | ||||||
|     mesh.setVertices(qMove(meshVertices)); |     initializeMeshFunction(qMove(meshVertices), triangleCount); | ||||||
|  |  | ||||||
|     vertices.front().flags = 0; |     vertices.front().flags = 0; | ||||||
|  |  | ||||||
| @@ -2050,15 +2184,6 @@ PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySetting | |||||||
|     const VertexData* vc = nullptr; |     const VertexData* vc = nullptr; | ||||||
|     const VertexData* vd = nullptr; |     const VertexData* vd = nullptr; | ||||||
|  |  | ||||||
|     auto addTriangle = [this, &settings, &mesh, cms, intent, reporter](const VertexData* va, const VertexData* vb, const VertexData* vc) |  | ||||||
|     { |  | ||||||
|         const uint32_t via = va->index; |  | ||||||
|         const uint32_t vib = vb->index; |  | ||||||
|         const uint32_t vic = vc->index; |  | ||||||
|  |  | ||||||
|         addSubdividedTriangles(settings, mesh, via, vib, vic, va->color, vb->color, vc->color, cms, intent, reporter); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < vertexCount;) |     for (size_t i = 0; i < vertexCount;) | ||||||
|     { |     { | ||||||
|         vd = &vertices[i]; |         vd = &vertices[i]; | ||||||
| @@ -2069,7 +2194,7 @@ PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySetting | |||||||
|             { |             { | ||||||
|                 if (i + 2 >= vertexCount) |                 if (i + 2 >= vertexCount) | ||||||
|                 { |                 { | ||||||
|                     throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid free form gourad triangle data stream - not enough vertices.")); |                     return false; | ||||||
|                 } |                 } | ||||||
|                 va = vd; |                 va = vd; | ||||||
|                 vb = &vertices[i + 1]; |                 vb = &vertices[i + 1]; | ||||||
| @@ -2101,11 +2226,37 @@ PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySetting | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             default: |             default: | ||||||
|                 throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid free form gourad triangle data stream - invalid vertex flag %1.").arg(vd->flags)); |                 return false; | ||||||
|                 break; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const | ||||||
|  | { | ||||||
|  |     PDFMesh mesh; | ||||||
|  |  | ||||||
|  |     auto addTriangle = [this, &settings, &mesh, cms, intent, reporter](const VertexData* va, const VertexData* vb, const VertexData* vc) | ||||||
|  |     { | ||||||
|  |         const uint32_t via = va->index; | ||||||
|  |         const uint32_t vib = vb->index; | ||||||
|  |         const uint32_t vic = vc->index; | ||||||
|  |  | ||||||
|  |         addSubdividedTriangles(settings, mesh, via, vib, vic, va->color, vb->color, vc->color, cms, intent, reporter); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     auto initializeMeshFunction = [&mesh](std::vector<QPointF>&& vertices, size_t triangleCount) | ||||||
|  |     { | ||||||
|  |         mesh.reserve(0, triangleCount); | ||||||
|  |         mesh.setVertices(qMove(vertices)); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     if (!processTriangles(initializeMeshFunction, addTriangle, settings.userSpaceToDeviceSpaceMatrix, true)) | ||||||
|  |     { | ||||||
|  |         throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid free form gourad triangle data stream.")); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (m_backgroundColor.isValid()) |     if (m_backgroundColor.isValid()) | ||||||
|     { |     { | ||||||
|         QPainterPath path; |         QPainterPath path; | ||||||
| @@ -2117,6 +2268,35 @@ PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySetting | |||||||
|     return mesh; |     return mesh; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | PDFShadingSampler* PDFFreeFormGouradTriangleShading::createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const | ||||||
|  | { | ||||||
|  |     PDFTriangleShadingSampler* sampler = new PDFTriangleShadingSampler(this, userSpaceToDeviceSpaceMatrix); | ||||||
|  |  | ||||||
|  |     auto addTriangle = [sampler](const VertexData* va, const VertexData* vb, const VertexData* vc) | ||||||
|  |     { | ||||||
|  |         const uint32_t via = va->index; | ||||||
|  |         const uint32_t vib = vb->index; | ||||||
|  |         const uint32_t vic = vc->index; | ||||||
|  |  | ||||||
|  |         sampler->addTriangle({ via, vib, vic }, { va->color, vb->color, vc->color }); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     auto initializeMeshFunction = [sampler](std::vector<QPointF>&& vertices, size_t triangleCount) | ||||||
|  |     { | ||||||
|  |         sampler->setVertexArray(qMove(vertices)); | ||||||
|  |         sampler->reserveSpaceForTriangles(triangleCount); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     if (!processTriangles(initializeMeshFunction, addTriangle, userSpaceToDeviceSpaceMatrix, false)) | ||||||
|  |     { | ||||||
|  |         // Just delete the sampler, data are invalid | ||||||
|  |         delete sampler; | ||||||
|  |         sampler = nullptr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return sampler; | ||||||
|  | } | ||||||
|  |  | ||||||
| ShadingType PDFLatticeFormGouradTriangleShading::getShadingType() const | ShadingType PDFLatticeFormGouradTriangleShading::getShadingType() const | ||||||
| { | { | ||||||
|     return ShadingType::LatticeFormGouradTriangle; |     return ShadingType::LatticeFormGouradTriangle; | ||||||
|   | |||||||
| @@ -335,6 +335,9 @@ public: | |||||||
|     /// Returns matrix transforming pattern space to device space |     /// Returns matrix transforming pattern space to device space | ||||||
|     QMatrix getPatternSpaceToDeviceSpaceMatrix(const PDFMeshQualitySettings& settings) const; |     QMatrix getPatternSpaceToDeviceSpaceMatrix(const PDFMeshQualitySettings& settings) const; | ||||||
|  |  | ||||||
|  |     /// Returns matrix transforming pattern space to device space | ||||||
|  |     QMatrix getPatternSpaceToDeviceSpaceMatrix(const QMatrix& userSpaceToDeviceSpaceMatrix) const; | ||||||
|  |  | ||||||
|     /// Create sampler which can compute shading colors in device space coordinates. If sampler can't |     /// Create sampler which can compute shading colors in device space coordinates. If sampler can't | ||||||
|     /// be created (or shading is invalid), then nullptr is returned. |     /// be created (or shading is invalid), then nullptr is returned. | ||||||
|     /// \param userSpaceToDeviceSpaceMatrix Matrix, which transforms user space points |     /// \param userSpaceToDeviceSpaceMatrix Matrix, which transforms user space points | ||||||
| @@ -434,12 +437,12 @@ class PDFType4567Shading : public PDFShadingPattern | |||||||
| public: | public: | ||||||
|     explicit PDFType4567Shading() = default; |     explicit PDFType4567Shading() = default; | ||||||
|  |  | ||||||
| protected: |  | ||||||
|     friend class PDFPattern; |  | ||||||
|  |  | ||||||
|     /// Returns color for given color or function parameter |     /// Returns color for given color or function parameter | ||||||
|     PDFColor getColor(PDFColor colorOrFunctionParameter) const; |     PDFColor getColor(PDFColor colorOrFunctionParameter) const; | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     friend class PDFPattern; | ||||||
|  |  | ||||||
|     void addSubdividedTriangles(const PDFMeshQualitySettings& settings, |     void addSubdividedTriangles(const PDFMeshQualitySettings& settings, | ||||||
|                                 PDFMesh& mesh, |                                 PDFMesh& mesh, | ||||||
|                                 uint32_t v1, |                                 uint32_t v1, | ||||||
| @@ -477,9 +480,26 @@ public: | |||||||
|  |  | ||||||
|     virtual ShadingType getShadingType() const override; |     virtual ShadingType getShadingType() const override; | ||||||
|     virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override; |     virtual PDFMesh createMesh(const PDFMeshQualitySettings& settings, const PDFCMS* cms, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override; | ||||||
|  |     virtual PDFShadingSampler* createSampler(QMatrix userSpaceToDeviceSpaceMatrix) const override; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  |     struct VertexData | ||||||
|  |     { | ||||||
|  |         uint32_t index = 0; | ||||||
|  |         uint8_t flags = 0; | ||||||
|  |         QPointF position; | ||||||
|  |         PDFColor color; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     friend class PDFPattern; |     friend class PDFPattern; | ||||||
|  |  | ||||||
|  |     using InitializeFunction = std::function<void(std::vector<QPointF>&&, size_t)>; | ||||||
|  |     using AddTriangleFunction = std::function<void(const VertexData*, const VertexData*, const VertexData*)>; | ||||||
|  |  | ||||||
|  |     bool processTriangles(InitializeFunction initializeMeshFunction, | ||||||
|  |                           AddTriangleFunction addTriangle, | ||||||
|  |                           const QMatrix& userSpaceToDeviceSpaceMatrix, | ||||||
|  |                           bool convertColors) const; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class PDFLatticeFormGouradTriangleShading : public PDFType4567Shading | class PDFLatticeFormGouradTriangleShading : public PDFType4567Shading | ||||||
|   | |||||||
| @@ -53,12 +53,18 @@ PDFFloatBitmap::PDFFloatBitmap(size_t width, size_t height, PDFPixelFormat forma | |||||||
|  |  | ||||||
| PDFColorBuffer PDFFloatBitmap::getPixel(size_t x, size_t y) | PDFColorBuffer PDFFloatBitmap::getPixel(size_t x, size_t y) | ||||||
| { | { | ||||||
|  |     Q_ASSERT(x < m_width); | ||||||
|  |     Q_ASSERT(y < m_height); | ||||||
|  |  | ||||||
|     const size_t index = getPixelIndex(x, y); |     const size_t index = getPixelIndex(x, y); | ||||||
|     return PDFColorBuffer(m_data.data() + index, m_pixelSize); |     return PDFColorBuffer(m_data.data() + index, m_pixelSize); | ||||||
| } | } | ||||||
|  |  | ||||||
| PDFConstColorBuffer PDFFloatBitmap::getPixel(size_t x, size_t y) const | PDFConstColorBuffer PDFFloatBitmap::getPixel(size_t x, size_t y) const | ||||||
| { | { | ||||||
|  |     Q_ASSERT(x < m_width); | ||||||
|  |     Q_ASSERT(y < m_height); | ||||||
|  |  | ||||||
|     const size_t index = getPixelIndex(x, y); |     const size_t index = getPixelIndex(x, y); | ||||||
|     return PDFConstColorBuffer(m_data.data() + index, m_pixelSize); |     return PDFConstColorBuffer(m_data.data() + index, m_pixelSize); | ||||||
| } | } | ||||||
| @@ -1912,7 +1918,10 @@ bool PDFTransparencyRenderer::performPathPaintingUsingShading(const QPainterPath | |||||||
|         { |         { | ||||||
|             for (int y = fillRect.top(); y <= fillRect.bottom(); ++y) |             for (int y = fillRect.top(); y <= fillRect.bottom(); ++y) | ||||||
|             { |             { | ||||||
|                 PDFColorBuffer buffer = texture.getPixel(x, y); |                 const int texelCoordinateX = x - fillRect.left(); | ||||||
|  |                 const int texelCoordinateY = y - fillRect.top(); | ||||||
|  |  | ||||||
|  |                 PDFColorBuffer buffer = texture.getPixel(texelCoordinateX, texelCoordinateY); | ||||||
|                 bool isSampled = sampler->sample(QPointF(x, y) + offset, buffer.resized(shadingColorComponentCount), m_settings.shadingAlgorithmLimit); |                 bool isSampled = sampler->sample(QPointF(x, y) + offset, buffer.resized(shadingColorComponentCount), m_settings.shadingAlgorithmLimit); | ||||||
|                 const PDFColorComponent textureSampleShape = isSampled ? 1.0f : 0.0f; |                 const PDFColorComponent textureSampleShape = isSampled ? 1.0f : 0.0f; | ||||||
|                 buffer[textureShapeChannel] = textureSampleShape; |                 buffer[textureShapeChannel] = textureSampleShape; | ||||||
| @@ -1929,7 +1938,10 @@ bool PDFTransparencyRenderer::performPathPaintingUsingShading(const QPainterPath | |||||||
|         { |         { | ||||||
|             for (int x = fillRect.left(); x <= fillRect.right(); ++x) |             for (int x = fillRect.left(); x <= fillRect.right(); ++x) | ||||||
|             { |             { | ||||||
|                 PDFColorBuffer buffer = texture.getPixel(x, y); |                 const int texelCoordinateX = x - fillRect.left(); | ||||||
|  |                 const int texelCoordinateY = y - fillRect.top(); | ||||||
|  |  | ||||||
|  |                 PDFColorBuffer buffer = texture.getPixel(texelCoordinateX, texelCoordinateY); | ||||||
|                 bool isSampled = sampler->sample(QPointF(x, y) + offset, buffer.resized(shadingColorComponentCount), m_settings.shadingAlgorithmLimit); |                 bool isSampled = sampler->sample(QPointF(x, y) + offset, buffer.resized(shadingColorComponentCount), m_settings.shadingAlgorithmLimit); | ||||||
|                 const PDFColorComponent textureSampleShape = isSampled ? 1.0f : 0.0f; |                 const PDFColorComponent textureSampleShape = isSampled ? 1.0f : 0.0f; | ||||||
|                 buffer[textureShapeChannel] = textureSampleShape; |                 buffer[textureShapeChannel] = textureSampleShape; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user