PDF4QT/PdfForQtLib/sources/pdfrenderer.h

370 lines
14 KiB
C
Raw Normal View History

2020-02-09 16:06:29 +01:00
// Copyright (C) 2019-2020 Jakub Melka
2019-02-09 18:40:56 +01:00
//
// 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 PDFRENDERER_H
#define PDFRENDERER_H
#include "pdfpage.h"
2019-04-29 17:03:19 +02:00
#include "pdfexception.h"
2019-09-28 18:26:31 +02:00
#include "pdfmeshqualitysettings.h"
2019-02-09 18:40:56 +01:00
2020-02-09 16:06:29 +01:00
#include <QMutex>
#include <QSemaphore>
2020-02-08 18:09:46 +01:00
#include <QImageWriter>
2019-12-15 16:45:49 +01:00
#include <QSurfaceFormat>
2019-02-14 19:45:07 +01:00
class QPainter;
2019-12-15 16:45:49 +01:00
class QOpenGLContext;
class QOffscreenSurface;
class QOpenGLFramebufferObject;
2019-02-09 18:40:56 +01:00
namespace pdf
{
2019-12-25 17:56:17 +01:00
class PDFCMS;
2020-02-09 16:06:29 +01:00
class PDFProgress;
2019-04-12 19:17:19 +02:00
class PDFFontCache;
2020-04-11 13:56:05 +02:00
class PDFCMSManager;
2019-12-14 14:39:43 +01:00
class PDFPrecompiledPage;
2020-04-11 13:56:05 +02:00
class PDFAnnotationManager;
class PDFOptionalContentActivity;
2019-02-09 18:40:56 +01:00
/// Renders the PDF page on the painter, or onto an image.
2020-02-03 19:45:17 +01:00
class PDFFORQTLIBSHARED_EXPORT PDFRenderer
2019-02-09 18:40:56 +01:00
{
public:
enum Feature
{
2019-07-06 15:55:37 +02:00
Antialiasing = 0x0001, ///< Antialiasing for lines, shapes, etc.
TextAntialiasing = 0x0002, ///< Antialiasing for drawing text
SmoothImages = 0x0004, ///< Adjust images to the device space using smooth transformation (slower, but better image quality)
IgnoreOptionalContent = 0x0008, ///< Ignore optional content (so all is drawn ignoring settings of optional content)
ClipToCropBox = 0x0010, ///< Clip page content to crop box (items outside crop box will not be visible)
DisplayTimes = 0x0020, ///< Display page compile/draw time
2019-12-29 17:25:18 +01:00
DebugTextBlocks = 0x0040, ///< Debug text block layout algorithm
2020-01-28 19:17:45 +01:00
DebugTextLines = 0x0080, ///< Debug text line layout algorithm
InvertColors = 0x0100, ///< Invert colors
DenyExtraGraphics = 0x0200, ///< Do not display additional graphics, for example from tools
2020-04-11 13:56:05 +02:00
DisplayAnnotations = 0x0400, ///< Display annotations
2019-02-09 18:40:56 +01:00
};
Q_DECLARE_FLAGS(Features, Feature)
2019-12-25 17:56:17 +01:00
explicit PDFRenderer(const PDFDocument* document,
const PDFFontCache* fontCache,
const PDFCMS* cms,
const PDFOptionalContentActivity* optionalContentActivity,
Features features,
const PDFMeshQualitySettings& meshQualitySettings);
2019-07-06 15:55:37 +02:00
2019-02-09 18:40:56 +01:00
/// 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
/// are reported and returned in the error list. If no error occured, empty list is returned.
/// \param painter Painter
/// \param rectangle Paint area for the page
/// \param pageIndex Index of the page to be painted
QList<PDFRenderError> render(QPainter* painter, const QRectF& rectangle, size_t pageIndex) const;
2019-02-24 17:48:37 +01:00
/// Paints desired page onto the painter. Page is painted using \p matrix, which maps page coordinates
/// to the device coordinates. If the page doesn't exist, then error is returned. No exception is thrown.
/// Rendering errors are reported and returned in the error list. If no error occured, empty list is returned.
QList<PDFRenderError> render(QPainter* painter, const QMatrix& matrix, size_t pageIndex) const;
2019-12-14 14:39:43 +01:00
/// Compiles page (i.e. prepares compiled page). \p page should be empty page, onto which
/// are graphics commands written. No exception is thrown. Rendering errors are reported and written
/// to the compiled page.
/// \param precompiledPage Precompiled page pointer
/// \param pageIndex Index of page to be compiled
void compile(PDFPrecompiledPage* precompiledPage, size_t pageIndex) const;
/// Creates page point to device point matrix for the given rectangle. It creates transformation
/// from page's media box to the target rectangle.
/// \param page Page, for which we want to create matrix
/// \param rectangle Page rectangle, to which is page media box transformed
static QMatrix createPagePointToDevicePointMatrix(const PDFPage* page, const QRectF& rectangle);
2019-12-14 14:39:43 +01:00
2019-07-06 15:55:37 +02:00
/// Returns default renderer features
2020-04-11 13:56:05 +02:00
static constexpr Features getDefaultFeatures() { return Antialiasing | TextAntialiasing | ClipToCropBox | DisplayAnnotations; }
2019-07-06 15:55:37 +02:00
2019-02-09 18:40:56 +01:00
private:
const PDFDocument* m_document;
2019-04-12 19:17:19 +02:00
const PDFFontCache* m_fontCache;
2019-12-25 17:56:17 +01:00
const PDFCMS* m_cms;
const PDFOptionalContentActivity* m_optionalContentActivity;
2019-02-09 18:40:56 +01:00
Features m_features;
2019-09-28 18:26:31 +02:00
PDFMeshQualitySettings m_meshQualitySettings;
2019-02-09 18:40:56 +01:00
};
2019-12-15 16:45:49 +01:00
/// Renders PDF pages to bitmap images (QImage). It can use OpenGL for painting,
/// if it is enabled, if this is the case, offscreen rendering to framebuffer
/// is used.
2020-02-09 16:06:29 +01:00
/// \note Construct this object only in main GUI thread
2019-12-15 16:45:49 +01:00
class PDFRasterizer : public QObject
{
Q_OBJECT
private:
using BaseClass = QObject;
public:
explicit PDFRasterizer(QObject* parent);
2020-02-09 16:06:29 +01:00
virtual ~PDFRasterizer() override;
2019-12-15 16:45:49 +01:00
/// Resets the renderer. This function must be called from main GUI thread,
/// it cannot be called from deferred threads, because it can create hidden
/// window (offscreen surface).
/// \param useOpenGL Use OpenGL for rendering
/// \param surfaceFormat Surface format to render
void reset(bool useOpenGL, const QSurfaceFormat& surfaceFormat);
enum Feature
{
UseOpenGL = 0x0001, ///< Use OpenGL for rendering
ValidOpenGL = 0x0002, ///< OpenGL is initialized and valid
FailedOpenGL = 0x0004, ///< OpenGL creation has failed
};
Q_DECLARE_FLAGS(Features, Feature)
/// Renders page to the image of given size. If some error occurs, then
/// empty image is returned. Warning: this function can modify this object,
2020-04-11 13:56:05 +02:00
/// so it is not const and is not thread safe. We can also draw annotations,
/// if \p annotationManager is not nullptr and annotations are enabled.
/// \param pageIndex Page index
2019-12-15 16:45:49 +01:00
/// \param page Page
/// \param compiledPage Compiled page contents
/// \param size Size of the target image
/// \param features Renderer features
2020-04-11 13:56:05 +02:00
/// \param annotationManager Annotation manager (can be nullptr)
QImage render(PDFInteger pageIndex,
const PDFPage* page,
2019-12-15 16:45:49 +01:00
const PDFPrecompiledPage* compiledPage,
QSize size,
2020-04-11 13:56:05 +02:00
PDFRenderer::Features features,
const PDFAnnotationManager* annotationManager);
2019-12-15 16:45:49 +01:00
private:
void initializeOpenGL();
void releaseOpenGL();
Features m_features;
QSurfaceFormat m_surfaceFormat;
QOffscreenSurface* m_surface;
QOpenGLContext* m_context;
QOpenGLFramebufferObject* m_fbo;
};
2020-02-09 16:06:29 +01:00
/// Pool of page image renderers. It can use predefined number of renderers to
/// render page images asynchronously. You can use this object in two ways -
/// first one is as standard object pool, second one is to directly render
/// page images asynchronously.
class PDFFORQTLIBSHARED_EXPORT PDFRasterizerPool : public QObject
{
Q_OBJECT
private:
using BaseClass = QObject;
public:
using PageImageSizeGetter = std::function<QSize(const PDFPage*)>;
using ProcessImageMethod = std::function<void(PDFInteger, QImage&&)>;
/// Creates new rasterizer pool
/// \param document Document
/// \param fontCache Font cache
2020-04-11 13:56:05 +02:00
/// \param cmsManager Color management system manager
2020-02-09 16:06:29 +01:00
/// \param optionalContentActivity Optional content activity
/// \param features Renderer features
/// \param meshQualitySettings Mesh quality settings
/// \param rasterizerCount Number of rasterizers
/// \param useOpenGL Use OpenGL for rendering?
/// \param surfaceFormat Surface format
/// \param parent Parent object
explicit PDFRasterizerPool(const PDFDocument* document,
2020-04-11 13:56:05 +02:00
PDFFontCache* fontCache,
const PDFCMSManager* cmsManager,
2020-02-09 16:06:29 +01:00
const PDFOptionalContentActivity* optionalContentActivity,
PDFRenderer::Features features,
const PDFMeshQualitySettings& meshQualitySettings,
int rasterizerCount,
bool useOpenGL,
const QSurfaceFormat& surfaceFormat,
QObject* parent);
/// Acquire rasterizer. This function is thread safe.
PDFRasterizer* acquire();
/// Return back (release) rasterizer into rasterizer pool
/// This function is thread safe.
/// \param rasterizer Rasterizer
void release(PDFRasterizer* rasterizer);
/// Renders pages asynchronously to images, using given page indices,
/// function which returns rendered size and process image function,
/// which processes rendered images.
/// \param pageIndices Page indices for rendered pages
/// \param imageSizeGetter Getter, which computes image size from page index
/// \param processImage Method, which processes rendered page images
/// \param progress Progress indicator
void render(const std::vector<PDFInteger>& pageIndices,
const PageImageSizeGetter& imageSizeGetter,
const ProcessImageMethod& processImage,
PDFProgress* progress);
/// Returns default rasterizer count
static int getDefaultRasterizerCount();
signals:
void renderError(PDFRenderError error);
private:
const PDFDocument* m_document;
2020-04-11 13:56:05 +02:00
PDFFontCache* m_fontCache;
const PDFCMSManager* m_cmsManager;
2020-02-09 16:06:29 +01:00
const PDFOptionalContentActivity* m_optionalContentActivity;
PDFRenderer::Features m_features;
const PDFMeshQualitySettings& m_meshQualitySettings;
QSemaphore m_semaphore;
QMutex m_mutex;
std::vector<PDFRasterizer*> m_rasterizers;
};
2020-02-08 18:09:46 +01:00
/// Settings object for image writer
class PDFFORQTLIBSHARED_EXPORT PDFImageWriterSettings
{
public:
explicit PDFImageWriterSettings();
/// Returns true, if image option is supported
bool isOptionSupported(QImageIOHandler::ImageOption option) const { return m_supportedOptions.count(option); }
/// Returns a list of available image formats
const QList<QByteArray>& getFormats() const { return m_formats; }
/// Returns a list of available subtypes
const QList<QByteArray>& getSubtypes() const { return m_subtypes; }
/// Selects image format (and initializes default values)
void selectFormat(const QByteArray& format);
int getCompression() const;
void setCompression(int compression);
int getQuality() const;
void setQuality(int quality);
float getGamma() const;
void setGamma(float gamma);
bool hasOptimizedWrite() const;
void setOptimizedWrite(bool optimizedWrite);
bool hasProgressiveScanWrite() const;
void setProgressiveScanWrite(bool progressiveScanWrite);
QByteArray getCurrentFormat() const;
QByteArray getCurrentSubtype() const;
void setCurrentSubtype(const QByteArray& currentSubtype);
private:
int m_compression = 9;
int m_quality = 100;
float m_gamma = 1.0;
bool m_optimizedWrite = false;
bool m_progressiveScanWrite = false;
QByteArray m_currentFormat;
QByteArray m_currentSubtype;
std::set<QImageIOHandler::ImageOption> m_supportedOptions;
QList<QByteArray> m_formats;
QList<QByteArray> m_subtypes;
};
/// This class is for setup of page image exporter
class PDFFORQTLIBSHARED_EXPORT PDFPageImageExportSettings
{
public:
2020-02-09 16:06:29 +01:00
explicit PDFPageImageExportSettings(const PDFDocument* document);
2020-02-08 18:09:46 +01:00
enum class PageSelectionMode
{
All,
Selection
};
enum class ResolutionMode
{
DPI,
Pixels
};
ResolutionMode getResolutionMode() const;
void setResolutionMode(ResolutionMode resolution);
PageSelectionMode getPageSelectionMode() const;
void setPageSelectionMode(PageSelectionMode pageSelectionMode);
QString getDirectory() const;
void setDirectory(const QString& directory);
QString getFileTemplate() const;
void setFileTemplate(const QString& fileTemplate);
QString getPageSelection() const;
void setPageSelection(const QString& pageSelection);
int getDpiResolution() const;
void setDpiResolution(int dpiResolution);
int getPixelResolution() const;
void setPixelResolution(int pixelResolution);
2020-02-09 16:06:29 +01:00
/// Validates the settings, if they can be used for image generation
bool validate(QString* errorMessagePtr);
/// Returns list of selected pages
std::vector<PDFInteger> getPages() const;
2020-02-09 17:17:14 +01:00
/// Returns output file name for given page
QString getOutputFileName(PDFInteger pageIndex, const QByteArray& outputFormat);
2020-02-09 16:06:29 +01:00
static constexpr int getMinDPIResolution() { return 72; }
static constexpr int getMaxDPIResolution() { return 6000; }
static constexpr int getMinPixelResolution() { return 100; }
static constexpr int getMaxPixelResolution() { return 16384; }
2020-02-08 18:09:46 +01:00
private:
2020-02-09 16:06:29 +01:00
const PDFDocument* m_document;
2020-02-08 18:09:46 +01:00
ResolutionMode m_resolutionMode = ResolutionMode::DPI;
PageSelectionMode m_pageSelectionMode = PageSelectionMode::All;
QString m_directory;
QString m_fileTemplate;
QString m_pageSelection;
int m_dpiResolution = 300;
int m_pixelResolution = 100;
};
2019-02-09 18:40:56 +01:00
} // namespace pdf
Q_DECLARE_OPERATORS_FOR_FLAGS(pdf::PDFRenderer::Features)
#endif // PDFRENDERER_H