mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Mesh quality settings
This commit is contained in:
@ -65,6 +65,7 @@ SOURCES += \
|
||||
|
||||
HEADERS += \
|
||||
sources/pdfitemmodels.h \
|
||||
sources/pdfmeshqualitysettings.h \
|
||||
sources/pdfobject.h \
|
||||
sources/pdfoptionalcontent.h \
|
||||
sources/pdfparser.h \
|
||||
|
@ -552,7 +552,7 @@ void PDFDrawWidgetProxy::draw(QPainter* painter, QRect rect)
|
||||
// Clear the page space by white color
|
||||
painter->fillRect(placedRect, Qt::white);
|
||||
|
||||
PDFRenderer renderer(m_controller->getDocument(), m_controller->getFontCache(), m_controller->getOptionalContentActivity(), m_features);
|
||||
PDFRenderer renderer(m_controller->getDocument(), m_controller->getFontCache(), m_controller->getOptionalContentActivity(), m_features, m_meshQualitySettings);
|
||||
QList<PDFRenderError> errors = renderer.render(painter, placedRect, item.pageIndex);
|
||||
|
||||
if (!errors.empty())
|
||||
@ -827,4 +827,31 @@ void PDFDrawWidgetProxy::setFeatures(PDFRenderer::Features features)
|
||||
}
|
||||
}
|
||||
|
||||
void PDFDrawWidgetProxy::setPreferredMeshResolutionRatio(PDFReal ratio)
|
||||
{
|
||||
if (m_meshQualitySettings.preferredMeshResolutionRatio != ratio)
|
||||
{
|
||||
m_meshQualitySettings.preferredMeshResolutionRatio = ratio;
|
||||
emit repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFDrawWidgetProxy::setMinimalMeshResolutionRatio(PDFReal ratio)
|
||||
{
|
||||
if (m_meshQualitySettings.minimalMeshResolutionRatio != ratio)
|
||||
{
|
||||
m_meshQualitySettings.minimalMeshResolutionRatio = ratio;
|
||||
emit repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFDrawWidgetProxy::setColorTolerance(PDFReal colorTolerance)
|
||||
{
|
||||
if (m_meshQualitySettings.tolerance != colorTolerance)
|
||||
{
|
||||
m_meshQualitySettings.tolerance = colorTolerance;
|
||||
emit repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -215,6 +215,9 @@ public:
|
||||
|
||||
PDFRenderer::Features getFeatures() const;
|
||||
void setFeatures(PDFRenderer::Features features);
|
||||
void setPreferredMeshResolutionRatio(PDFReal ratio);
|
||||
void setMinimalMeshResolutionRatio(PDFReal ratio);
|
||||
void setColorTolerance(PDFReal colorTolerance);
|
||||
|
||||
signals:
|
||||
void drawSpaceChanged();
|
||||
@ -332,6 +335,9 @@ private:
|
||||
|
||||
/// Renderer features
|
||||
PDFRenderer::Features m_features;
|
||||
|
||||
/// Mesh quality settings
|
||||
PDFMeshQualitySettings m_meshQualitySettings;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
75
PdfForQtLib/sources/pdfmeshqualitysettings.h
Normal file
75
PdfForQtLib/sources/pdfmeshqualitysettings.h
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (C) 2019 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef PDFMESHQUALITYSETTINGS_H
|
||||
#define PDFMESHQUALITYSETTINGS_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
|
||||
#include <QMatrix>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
struct PDFMeshQualitySettings
|
||||
{
|
||||
/// Initializes default resolution
|
||||
void initResolution();
|
||||
|
||||
/// Value used to compute minimal pxiel size resolution (it is multiplied by whole shading area size)
|
||||
PDFReal minimalMeshResolutionRatio = 0.005;
|
||||
|
||||
/// Value used to compute pixel size resolution (it is multiplied by whole shading area size)
|
||||
PDFReal preferredMeshResolutionRatio = 0.02;
|
||||
|
||||
/// Matrix, which transforms user space points (user space is target space of the shading)
|
||||
/// to the device space of the paint device.
|
||||
QMatrix userSpaceToDeviceSpaceMatrix;
|
||||
|
||||
/// Rectangle in device space coordinate system, onto which is area meshed.
|
||||
QRectF deviceSpaceMeshingArea;
|
||||
|
||||
/// Preferred mesh resolution in device space pixels. Mesh will be created in this
|
||||
/// resolution, if it is smooth enough (no jumps in colors occurs).
|
||||
PDFReal preferredMeshResolution = 1.0;
|
||||
|
||||
/// Minimal mesh resolution in device space pixels. If jumps in colors occurs (jump
|
||||
/// is two colors, that differ more than \p color tolerance), then mesh is meshed to
|
||||
/// minimal mesh resolution.
|
||||
PDFReal minimalMeshResolution = 1.0;
|
||||
|
||||
/// Color tolerance - 1% by default
|
||||
PDFReal tolerance = 0.01;
|
||||
|
||||
/// Test points to determine maximal curvature of the tensor product patch meshes
|
||||
PDFInteger patchTestPoints = 64;
|
||||
|
||||
/// Lower value of the surface curvature meshing resolution mapping. When ratio between
|
||||
/// current curvature at the center of meshed triangle and maximal curvature is below
|
||||
/// this value, then prefered mesh resolution is used. If ratio is higher than this value
|
||||
/// and lower than \p patchResolutionMappingRatioHigh, then target length is linearly mapped.
|
||||
/// If value is higher, than \p patchResolutionMappingRatioHigh, then minimal mesh resolution
|
||||
/// is used when generating triangles on the patch.
|
||||
PDFReal patchResolutionMappingRatioLow = 0.3;
|
||||
|
||||
/// Highter value of the surface curvature meshing resolution mapping. \sa patchResolutionMappingRatioLow
|
||||
PDFReal patchResolutionMappingRatioHigh = 0.9;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFMESHQUALITYSETTINGS_H
|
@ -184,7 +184,8 @@ PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page,
|
||||
const PDFDocument* document,
|
||||
const PDFFontCache* fontCache,
|
||||
const PDFOptionalContentActivity* optionalContentActivity,
|
||||
QMatrix pagePointToDevicePointMatrix) :
|
||||
QMatrix pagePointToDevicePointMatrix,
|
||||
const PDFMeshQualitySettings& meshQualitySettings) :
|
||||
m_page(page),
|
||||
m_document(document),
|
||||
m_fontCache(fontCache),
|
||||
@ -201,7 +202,8 @@ PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page,
|
||||
m_drawingUncoloredTilingPatternState(0),
|
||||
m_isWarningColorOperatorsInUncoloredTilingPatternReported(false),
|
||||
m_patternBaseMatrix(pagePointToDevicePointMatrix),
|
||||
m_pagePointToDevicePointMatrix(pagePointToDevicePointMatrix)
|
||||
m_pagePointToDevicePointMatrix(pagePointToDevicePointMatrix),
|
||||
m_meshQualitySettings(meshQualitySettings)
|
||||
{
|
||||
Q_ASSERT(page);
|
||||
Q_ASSERT(document);
|
||||
@ -628,10 +630,10 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool
|
||||
}
|
||||
|
||||
// We must create a mesh and then draw pattern
|
||||
PDFMeshQualitySettings settings;
|
||||
PDFMeshQualitySettings settings = m_meshQualitySettings;
|
||||
settings.deviceSpaceMeshingArea = getPageBoundingRectDeviceSpace();
|
||||
settings.userSpaceToDeviceSpaceMatrix = getPatternBaseMatrix();
|
||||
settings.initDefaultResolution();
|
||||
settings.initResolution();
|
||||
|
||||
PDFMesh mesh = shadingPattern->createMesh(settings);
|
||||
|
||||
@ -717,10 +719,10 @@ void PDFPageContentProcessor::processPathPainting(const QPainterPath& path, bool
|
||||
}
|
||||
|
||||
// We must create a mesh and then draw pattern
|
||||
PDFMeshQualitySettings settings;
|
||||
PDFMeshQualitySettings settings = m_meshQualitySettings;
|
||||
settings.deviceSpaceMeshingArea = getPageBoundingRectDeviceSpace();
|
||||
settings.userSpaceToDeviceSpaceMatrix = getPatternBaseMatrix();
|
||||
settings.initDefaultResolution();
|
||||
settings.initResolution();
|
||||
|
||||
PDFMesh mesh = shadingPattern->createMesh(settings);
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "pdfparser.h"
|
||||
#include "pdffont.h"
|
||||
#include "pdfutils.h"
|
||||
#include "pdfmeshqualitysettings.h"
|
||||
|
||||
#include <QMatrix>
|
||||
#include <QPainterPath>
|
||||
@ -48,7 +49,8 @@ public:
|
||||
const PDFDocument* document,
|
||||
const PDFFontCache* fontCache,
|
||||
const PDFOptionalContentActivity* optionalContentActivity,
|
||||
QMatrix pagePointToDevicePointMatrix);
|
||||
QMatrix pagePointToDevicePointMatrix,
|
||||
const PDFMeshQualitySettings& meshQualitySettings);
|
||||
virtual ~PDFPageContentProcessor();
|
||||
|
||||
enum class Operator
|
||||
@ -814,6 +816,9 @@ private:
|
||||
/// Bounding rectangle of pages media box in device space coordinates. If drawing rotation
|
||||
/// is zero, then it corresponds to the scaled media box of the page.
|
||||
QRectF m_pageBoundingRectDeviceSpace;
|
||||
|
||||
/// Mesh quality settings
|
||||
PDFMeshQualitySettings m_meshQualitySettings;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -29,8 +29,9 @@ PDFPainter::PDFPainter(QPainter* painter,
|
||||
const PDFPage* page,
|
||||
const PDFDocument* document,
|
||||
const PDFFontCache* fontCache,
|
||||
const PDFOptionalContentActivity* optionalContentActivity) :
|
||||
PDFPageContentProcessor(page, document, fontCache, optionalContentActivity, pagePointToDevicePointMatrix),
|
||||
const PDFOptionalContentActivity* optionalContentActivity,
|
||||
const PDFMeshQualitySettings& meshQualitySettings) :
|
||||
PDFPageContentProcessor(page, document, fontCache, optionalContentActivity, pagePointToDevicePointMatrix, meshQualitySettings),
|
||||
m_painter(painter),
|
||||
m_features(features)
|
||||
{
|
||||
|
@ -41,13 +41,15 @@ public:
|
||||
/// \param document Document owning the page
|
||||
/// \param fontCache Font cache
|
||||
/// \param optionalContentActivity Activity of optional content
|
||||
/// \param meshQualitySettings Mesh quality settings
|
||||
explicit PDFPainter(QPainter* painter,
|
||||
PDFRenderer::Features features,
|
||||
QMatrix pagePointToDevicePointMatrix,
|
||||
const PDFPage* page,
|
||||
const PDFDocument* document,
|
||||
const PDFFontCache* fontCache,
|
||||
const PDFOptionalContentActivity* optionalContentActivity);
|
||||
const PDFOptionalContentActivity* optionalContentActivity,
|
||||
const PDFMeshQualitySettings& meshQualitySettings);
|
||||
virtual ~PDFPainter() override;
|
||||
|
||||
protected:
|
||||
|
@ -903,7 +903,7 @@ PDFMesh PDFAxialShading::createMesh(const PDFMeshQualitySettings& settings) cons
|
||||
{
|
||||
// We will skip this coordinate, if both of meshing criteria have been met:
|
||||
// 1) Color difference is small (lesser than tolerance)
|
||||
// 2) Distance from previous and next point is less than preffered meshing resolution OR colors are equal
|
||||
// 2) Distance from previous and next point is less than preferred meshing resolution OR colors are equal
|
||||
|
||||
if (it != coloredCoordinates.cbegin() && std::next(it) != coloredCoordinates.cend())
|
||||
{
|
||||
@ -1083,15 +1083,12 @@ QPointF PDFMesh::getTriangleCenter(const PDFMesh::Triangle& triangle) const
|
||||
return (m_vertices[triangle.v1] + m_vertices[triangle.v2] + m_vertices[triangle.v3]) / 3.0;
|
||||
}
|
||||
|
||||
void PDFMeshQualitySettings::initDefaultResolution()
|
||||
void PDFMeshQualitySettings::initResolution()
|
||||
{
|
||||
// We will take 0.5% percent of device space meshing area as minimal resolution (it is ~1.5 mm for
|
||||
// A4 page) and default resolution 4x number of that.
|
||||
|
||||
Q_ASSERT(deviceSpaceMeshingArea.isValid());
|
||||
PDFReal size = qMax(deviceSpaceMeshingArea.width(), deviceSpaceMeshingArea.height());
|
||||
minimalMeshResolution = size * 0.005;
|
||||
preferredMeshResolution = minimalMeshResolution * 4;
|
||||
minimalMeshResolution = size * minimalMeshResolutionRatio;
|
||||
preferredMeshResolution = size * qMax(preferredMeshResolutionRatio, minimalMeshResolutionRatio);
|
||||
}
|
||||
|
||||
ShadingType PDFRadialShading::getShadingType() const
|
||||
@ -1272,7 +1269,7 @@ PDFMesh PDFRadialShading::createMesh(const PDFMeshQualitySettings& settings) con
|
||||
{
|
||||
// We will skip this coordinate, if both of meshing criteria have been met:
|
||||
// 1) Color difference is small (lesser than tolerance)
|
||||
// 2) Distance from previous and next point is less than preffered meshing resolution OR colors are equal
|
||||
// 2) Distance from previous and next point is less than preferred meshing resolution OR colors are equal
|
||||
|
||||
if (it != coloredCoordinates.cbegin() && std::next(it) != coloredCoordinates.cend())
|
||||
{
|
||||
@ -2610,6 +2607,4 @@ PDFMesh PDFCoonsPatchShading::createMesh(const PDFMeshQualitySettings& settings)
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// TODO: Implement settings of meshing in the settings dialog
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "pdfobject.h"
|
||||
#include "pdffunction.h"
|
||||
#include "pdfcolorspaces.h"
|
||||
#include "pdfmeshqualitysettings.h"
|
||||
|
||||
#include <QMatrix>
|
||||
|
||||
@ -53,45 +54,6 @@ enum class ShadingType
|
||||
TensorProductPatchMesh = 7
|
||||
};
|
||||
|
||||
struct PDFMeshQualitySettings
|
||||
{
|
||||
/// Initializes default resolution
|
||||
void initDefaultResolution();
|
||||
|
||||
/// Matrix, which transforms user space points (user space is target space of the shading)
|
||||
/// to the device space of the paint device.
|
||||
QMatrix userSpaceToDeviceSpaceMatrix;
|
||||
|
||||
/// Rectangle in device space coordinate system, onto which is area meshed.
|
||||
QRectF deviceSpaceMeshingArea;
|
||||
|
||||
/// Preferred mesh resolution in device space pixels. Mesh will be created in this
|
||||
/// resolution, if it is smooth enough (no jumps in colors occurs).
|
||||
PDFReal preferredMeshResolution = 1.0;
|
||||
|
||||
/// Minimal mesh resolution in device space pixels. If jumps in colors occurs (jump
|
||||
/// is two colors, that differ more than \p color tolerance), then mesh is meshed to
|
||||
/// minimal mesh resolution.
|
||||
PDFReal minimalMeshResolution = 1.0;
|
||||
|
||||
/// Color tolerance - 1% by default
|
||||
PDFReal tolerance = 0.01;
|
||||
|
||||
/// Test points to determine maximal curvature of the tensor product patch meshes
|
||||
PDFInteger patchTestPoints = 64;
|
||||
|
||||
/// Lower value of the surface curvature meshing resolution mapping. When ratio between
|
||||
/// current curvature at the center of meshed triangle and maximal curvature is below
|
||||
/// this value, then prefered mesh resolution is used. If ratio is higher than this value
|
||||
/// and lower than \p patchResolutionMappingRatioHigh, then target length is linearly mapped.
|
||||
/// If value is higher, than \p patchResolutionMappingRatioHigh, then minimal mesh resolution
|
||||
/// is used when generating triangles on the patch.
|
||||
PDFReal patchResolutionMappingRatioLow = 0.3;
|
||||
|
||||
/// Highter value of the surface curvature meshing resolution mapping. \sa patchResolutionMappingRatioLow
|
||||
PDFReal patchResolutionMappingRatioHigh = 0.9;
|
||||
};
|
||||
|
||||
/// Mesh consisting of triangles
|
||||
class PDFMesh
|
||||
{
|
||||
|
@ -22,11 +22,16 @@
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFRenderer::PDFRenderer(const PDFDocument* document, const PDFFontCache* fontCache, const PDFOptionalContentActivity* optionalContentActivity, Features features) :
|
||||
PDFRenderer::PDFRenderer(const PDFDocument* document,
|
||||
const PDFFontCache* fontCache,
|
||||
const PDFOptionalContentActivity* optionalContentActivity,
|
||||
Features features,
|
||||
const PDFMeshQualitySettings& meshQualitySettings) :
|
||||
m_document(document),
|
||||
m_fontCache(fontCache),
|
||||
m_optionalContentActivity(optionalContentActivity),
|
||||
m_features(features)
|
||||
m_features(features),
|
||||
m_meshQualitySettings(meshQualitySettings)
|
||||
{
|
||||
Q_ASSERT(document);
|
||||
}
|
||||
@ -88,7 +93,7 @@ QList<PDFRenderError> PDFRenderer::render(QPainter* painter, const QRectF& recta
|
||||
}
|
||||
}
|
||||
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document, m_fontCache, m_optionalContentActivity);
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document, m_fontCache, m_optionalContentActivity, m_meshQualitySettings);
|
||||
return processor.processContents();
|
||||
}
|
||||
|
||||
@ -106,7 +111,7 @@ QList<PDFRenderError> PDFRenderer::render(QPainter* painter, const QMatrix& matr
|
||||
const PDFPage* page = catalog->getPage(pageIndex);
|
||||
Q_ASSERT(page);
|
||||
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document, m_fontCache, m_optionalContentActivity);
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document, m_fontCache, m_optionalContentActivity, m_meshQualitySettings);
|
||||
return processor.processContents();
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "pdfpage.h"
|
||||
#include "pdfexception.h"
|
||||
#include "pdfmeshqualitysettings.h"
|
||||
|
||||
class QPainter;
|
||||
|
||||
@ -44,7 +45,7 @@ public:
|
||||
|
||||
Q_DECLARE_FLAGS(Features, Feature)
|
||||
|
||||
explicit PDFRenderer(const PDFDocument* document, const PDFFontCache* fontCache, const PDFOptionalContentActivity* optionalContentActivity, Features features);
|
||||
explicit PDFRenderer(const PDFDocument* document, const PDFFontCache* fontCache, const PDFOptionalContentActivity* optionalContentActivity, Features features, const PDFMeshQualitySettings& meshQualitySettings);
|
||||
|
||||
/// Paints desired page onto the painter. Page is painted in the rectangle using best-fit method.
|
||||
/// If the page doesn't exist, then error is returned. No exception is thrown. Rendering errors
|
||||
@ -67,6 +68,7 @@ private:
|
||||
const PDFFontCache* m_fontCache;
|
||||
const PDFOptionalContentActivity* m_optionalContentActivity;
|
||||
Features m_features;
|
||||
PDFMeshQualitySettings m_meshQualitySettings;
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user