From 41a6ddbc409dc8db93df786b84013b3f495b9d5b Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Sun, 15 Sep 2019 18:01:13 +0200 Subject: [PATCH] Lattice form gourad triangle meshing --- PdfForQtLib/sources/pdffont.cpp | 2 +- .../sources/pdfpagecontentprocessor.cpp | 4 +- PdfForQtLib/sources/pdfpattern.cpp | 142 ++++++++++++++++++ PdfForQtLib/sources/pdfpattern.h | 4 +- 4 files changed, 148 insertions(+), 4 deletions(-) diff --git a/PdfForQtLib/sources/pdffont.cpp b/PdfForQtLib/sources/pdffont.cpp index e4d7c93..f8ea96e 100644 --- a/PdfForQtLib/sources/pdffont.cpp +++ b/PdfForQtLib/sources/pdffont.cpp @@ -127,7 +127,7 @@ QByteArray PDFSystemFontInfoStorage::loadFont(const FontDescriptor* descriptor, case StandardFontType::CourierOblique: case StandardFontType::CourierBoldOblique: { - fontName = "Courier"; + fontName = "CourierNew"; break; } diff --git a/PdfForQtLib/sources/pdfpagecontentprocessor.cpp b/PdfForQtLib/sources/pdfpagecontentprocessor.cpp index 90ebb35..9dd1bcd 100644 --- a/PdfForQtLib/sources/pdfpagecontentprocessor.cpp +++ b/PdfForQtLib/sources/pdfpagecontentprocessor.cpp @@ -613,7 +613,7 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool // We must create a mesh and then draw pattern PDFMeshQualitySettings settings; settings.deviceSpaceMeshingArea = getPageBoundingRectDeviceSpace(); - settings.userSpaceToDeviceSpaceMatrix = getCurrentWorldMatrix(); + settings.userSpaceToDeviceSpaceMatrix = getPatternBaseMatrix(); settings.initDefaultResolution(); PDFMesh mesh = shadingPatern->createMesh(settings); @@ -665,7 +665,7 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool // We must create a mesh and then draw pattern PDFMeshQualitySettings settings; settings.deviceSpaceMeshingArea = getPageBoundingRectDeviceSpace(); - settings.userSpaceToDeviceSpaceMatrix = getCurrentWorldMatrix(); + settings.userSpaceToDeviceSpaceMatrix = getPatternBaseMatrix(); settings.initDefaultResolution(); PDFMesh mesh = shadingPatern->createMesh(settings); diff --git a/PdfForQtLib/sources/pdfpattern.cpp b/PdfForQtLib/sources/pdfpattern.cpp index 6010ab2..e257344 100644 --- a/PdfForQtLib/sources/pdfpattern.cpp +++ b/PdfForQtLib/sources/pdfpattern.cpp @@ -362,6 +362,15 @@ PDFPatternPtr PDFPattern::createShadingPattern(const PDFDictionary* colorSpaceDi freeFormGouradTriangleShading->m_bitsPerFlag = bitsPerFlag; } + if (shadingType == ShadingType::LatticeFormGouradTriangle) + { + latticeFormGouradTriangleShading->m_verticesPerRow = loader.readIntegerFromDictionary(shadingDictionary, "VerticesPerRow", -1); + if (latticeFormGouradTriangleShading->m_verticesPerRow < 2) + { + throw PDFParserException(PDFTranslationContext::tr("Invalid vertices per row (%1) for gourad triangle meshing.").arg(latticeFormGouradTriangleShading->m_verticesPerRow)); + } + } + return result; } @@ -1428,6 +1437,14 @@ PDFMesh PDFFreeFormGouradTriangleShading::createMesh(const PDFMeshQualitySetting } } + if (m_backgroundColor.isValid()) + { + QPainterPath path; + path.addRect(settings.deviceSpaceMeshingArea); + mesh.setBackgroundPath(path); + mesh.setBackgroundColor(m_backgroundColor); + } + return mesh; } @@ -1439,6 +1456,131 @@ ShadingType PDFLatticeFormGouradTriangleShading::getShadingType() const PDFMesh PDFLatticeFormGouradTriangleShading::createMesh(const PDFMeshQualitySettings& settings) const { PDFMesh mesh; + + size_t bitsPerVertex = 2 * m_bitsPerCoordinate + m_colorComponentCount * m_bitsPerComponent; + size_t remainder = (8 - (bitsPerVertex % 8)) % 8; + bitsPerVertex += remainder; + size_t bytesPerVertex = bitsPerVertex / 8; + size_t vertexCount = m_data.size() / bytesPerVertex; + size_t columnCount = static_cast(m_verticesPerRow); + size_t rowCount = vertexCount / columnCount; + + if (rowCount < 2) + { + // No mesh produced + return mesh; + } + + // We have 2 triangles for each quad. We have (columnCount - 1) quads + // in single line and we have (rowCount - 1) lines. + size_t triangleCount = (rowCount - 1) * (columnCount - 1) * 2; + mesh.reserve(0, triangleCount); + + struct VertexData + { + uint32_t index = 0; + QPointF position; + PDFColor color; + }; + + const PDFReal vertexScaleRatio = 1.0 / double((static_cast(1) << m_bitsPerCoordinate) - 1); + const PDFReal xScaleRatio = (m_xmax - m_xmin) * vertexScaleRatio; + const PDFReal yScaleRatio = (m_ymax - m_ymin) * vertexScaleRatio; + const PDFReal colorScaleRatio = 1.0 / double((static_cast(1) << m_bitsPerComponent) - 1); + + std::vector vertices; + vertices.resize(vertexCount); + std::vector indices(vertexCount, 0); + std::iota(indices.begin(), indices.end(), static_cast(0)); + std::vector meshVertices; + meshVertices.resize(vertexCount); + + auto readVertex = [this, &vertices, &settings, &meshVertices, bytesPerVertex, xScaleRatio, yScaleRatio, colorScaleRatio](size_t index) + { + PDFBitReader reader(&m_data, 8); + reader.seek(index * bytesPerVertex); + + VertexData data; + data.index = static_cast(index); + const PDFReal x = m_xmin + (reader.read(m_bitsPerCoordinate)) * xScaleRatio; + const PDFReal y = m_ymin + (reader.read(m_bitsPerCoordinate)) * yScaleRatio; + data.position = settings.userSpaceToDeviceSpaceMatrix.map(QPointF(x, y)); + data.color.resize(m_colorComponentCount); + meshVertices[index] = data.position; + + for (size_t i = 0; i < m_colorComponentCount; ++i) + { + const double cMin = m_limits[2 * i + 0]; + const double cMax = m_limits[2 * i + 1]; + data.color[i] = cMin + (reader.read(m_bitsPerComponent)) * (cMax - cMin) * colorScaleRatio; + } + + if (!m_functions.empty()) + { + Q_ASSERT(m_colorComponentCount == 1); + const PDFReal t = data.color[0]; + std::vector colorBuffer(m_colorSpace->getColorComponentCount(), 0.0); + if (m_functions.size() == 1) + { + PDFFunction::FunctionResult result = m_functions.front()->apply(&t, &t + 1, colorBuffer.data(), colorBuffer.data() + colorBuffer.size()); + if (!result) + { + throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Error occured during mesh creation of shading: %1").arg(result.errorMessage)); + } + } + else + { + for (size_t i = 0, count = colorBuffer.size(); i < count; ++i) + { + PDFFunction::FunctionResult result = m_functions[i]->apply(&t, &t + 1, colorBuffer.data() + i, colorBuffer.data() + i + 1); + if (!result) + { + throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Error occured during mesh creation of shading: %1").arg(result.errorMessage)); + } + } + } + + data.color = PDFAbstractColorSpace::convertToColor(colorBuffer); + } + + vertices[index] = qMove(data); + }; + + std::for_each(std::execution::parallel_policy(), indices.begin(), indices.end(), readVertex); + mesh.setVertices(qMove(meshVertices)); + + auto getVertexIndex = [columnCount](size_t row, size_t column) -> size_t + { + return row * columnCount + column; + }; + + for (size_t row = 1; row < rowCount; ++row) + { + for (size_t column = 1; column < columnCount; ++column) + { + const size_t vTopLeft = getVertexIndex(row - 1, column - 1); + const size_t vTopRight = getVertexIndex(row - 1, column); + const size_t vBottomRight = getVertexIndex(row, column); + const size_t vBottomLeft = getVertexIndex(row, column - 1); + + const VertexData& vertexTopLeft = vertices[vTopLeft]; + const VertexData& vertexTopRight = vertices[vTopRight]; + const VertexData& vertexBottomRight = vertices[vBottomRight]; + const VertexData& vertexBottomLeft = vertices[vBottomLeft]; + + addSubdividedTriangles(settings, mesh, vertexTopLeft.index, vertexTopRight.index, vertexBottomRight.index, vertexTopLeft.color, vertexTopRight.color, vertexBottomRight.color); + addSubdividedTriangles(settings, mesh, vertexBottomRight.index, vertexBottomLeft.index, vertexTopLeft.index, vertexBottomRight.color, vertexBottomLeft.color, vertexTopLeft.color); + } + } + + if (m_backgroundColor.isValid()) + { + QPainterPath path; + path.addRect(settings.deviceSpaceMeshingArea); + mesh.setBackgroundPath(path); + mesh.setBackgroundColor(m_backgroundColor); + } + return mesh; } diff --git a/PdfForQtLib/sources/pdfpattern.h b/PdfForQtLib/sources/pdfpattern.h index b231ae8..7fc5d6f 100644 --- a/PdfForQtLib/sources/pdfpattern.h +++ b/PdfForQtLib/sources/pdfpattern.h @@ -329,7 +329,7 @@ protected: PDFReal m_ymin = 0.0; PDFReal m_ymax = 0.0; std::vector m_limits; - size_t m_colorComponentCount; + size_t m_colorComponentCount = 0; /// Color functions. This array can be empty. If it is empty, /// then colors should be determined directly from color space. @@ -363,6 +363,8 @@ public: private: friend class PDFPattern; + + PDFInteger m_verticesPerRow = 0; }; } // namespace pdf