Annotations in preview

This commit is contained in:
Jakub Melka
2020-04-11 13:56:05 +02:00
parent 0efc4bb40b
commit dc7dd8fe74
12 changed files with 300 additions and 90 deletions

View File

@@ -876,18 +876,28 @@ PDFAnnotationAdditionalActions PDFAnnotationAdditionalActions::parse(const PDFOb
return result;
}
PDFAnnotationManager::PDFAnnotationManager(PDFDrawWidgetProxy* proxy, QObject* parent) :
PDFAnnotationManager::PDFAnnotationManager(PDFFontCache* fontCache,
const PDFCMSManager* cmsManager,
const PDFOptionalContentActivity* optionalActivity,
PDFMeshQualitySettings meshQualitySettings,
PDFRenderer::Features features,
Target target,
QObject* parent) :
BaseClass(parent),
m_document(nullptr),
m_proxy(proxy)
m_fontCache(fontCache),
m_cmsManager(cmsManager),
m_optionalActivity(optionalActivity),
m_meshQualitySettings(meshQualitySettings),
m_features(features),
m_target(target)
{
Q_ASSERT(proxy);
m_proxy->registerDrawInterface(this);
}
PDFAnnotationManager::~PDFAnnotationManager()
{
m_proxy->unregisterDrawInterface(this);
}
void PDFAnnotationManager::drawPage(QPainter* painter,
@@ -905,12 +915,19 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
const PDFPage* page = m_document->getCatalog()->getPage(pageIndex);
Q_ASSERT(page);
PDFRenderer::Features features = m_proxy->getFeatures();
PDFFontCache* fontCache = m_proxy->getFontCache();
const PDFCMSPointer cms = m_proxy->getCMSManager()->getCurrentCMS();
const PDFOptionalContentActivity* optionalActivity = m_proxy->getOptionalContentActivity();
const PDFMeshQualitySettings& meshQualitySettings = m_proxy->getMeshQualitySettings();
fontCache->setCacheShrinkEnabled(this, false);
PDFRenderer::Features features = m_features;
if (!features.testFlag(PDFRenderer::DisplayAnnotations))
{
// Annotation displaying is disabled
return;
}
Q_ASSERT(m_fontCache);
Q_ASSERT(m_cmsManager);
Q_ASSERT(m_optionalActivity);
const PDFCMSPointer cms = m_cmsManager->getCurrentCMS();
m_fontCache->setCacheShrinkEnabled(this, false);
for (PageAnnotation& annotation : annotations.annotations)
{
@@ -925,7 +942,16 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
PDFObject appearanceStreamObject = m_document->getObject(getAppearanceStream(annotation));
if (!appearanceStreamObject.isStream())
{
// Object is not valid appearance stream
// Object is not valid appearance stream. We will try to draw default
// annotation appearance.
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
painter->setWorldMatrix(pagePointToDevicePointMatrix, true);
AnnotationDrawParameters parameters;
parameters.painter = painter;
parameters.key = std::make_pair(annotation.appearance, annotation.annotation->getAppearanceState());
annotation.annotation->draw(parameters);
painter->restore();
continue;
}
@@ -1019,7 +1045,7 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
// Step 3) - compute final matrix AA
QMatrix AA = formMatrix * A;
PDFPainter pdfPainter(painter, features, userSpaceToDeviceSpace, page, m_document, fontCache, cms.get(), optionalActivity, meshQualitySettings);
PDFPainter pdfPainter(painter, features, userSpaceToDeviceSpace, page, m_document, m_fontCache, cms.get(), m_optionalActivity, m_meshQualitySettings);
pdfPainter.initializeProcessor();
// Jakub Melka: we must check, that we do not display annotation disabled by optional content
@@ -1030,15 +1056,16 @@ void PDFAnnotationManager::drawPage(QPainter* painter,
}
}
fontCache->setCacheShrinkEnabled(this, true);
m_fontCache->setCacheShrinkEnabled(this, true);
}
}
void PDFAnnotationManager::setDocument(const PDFDocument* document)
void PDFAnnotationManager::setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity)
{
if (m_document != document)
{
m_document = document;
m_optionalActivity = optionalContentActivity;
m_pageAnnotations.clear();
}
}
@@ -1056,6 +1083,7 @@ PDFAnnotationManager::PageAnnotations& PDFAnnotationManager::getPageAnnotations(
{
Q_ASSERT(m_document);
QMutexLocker lock(&m_mutex);
auto it = m_pageAnnotations.find(pageIndex);
if (it == m_pageAnnotations.cend())
{
@@ -1084,6 +1112,46 @@ PDFAnnotationManager::PageAnnotations& PDFAnnotationManager::getPageAnnotations(
return it->second;
}
PDFRenderer::Features PDFAnnotationManager::getFeatures() const
{
return m_features;
}
void PDFAnnotationManager::setFeatures(PDFRenderer::Features features)
{
m_features = features;
}
PDFMeshQualitySettings PDFAnnotationManager::getMeshQualitySettings() const
{
return m_meshQualitySettings;
}
void PDFAnnotationManager::setMeshQualitySettings(const PDFMeshQualitySettings& meshQualitySettings)
{
m_meshQualitySettings = meshQualitySettings;
}
PDFFontCache* PDFAnnotationManager::getFontCache() const
{
return m_fontCache;
}
void PDFAnnotationManager::setFontCache(PDFFontCache* fontCache)
{
m_fontCache = fontCache;
}
const PDFOptionalContentActivity* PDFAnnotationManager::getOptionalActivity() const
{
return m_optionalActivity;
}
void PDFAnnotationManager::setOptionalActivity(const PDFOptionalContentActivity* optionalActivity)
{
m_optionalActivity = optionalActivity;
}
PDFAnnotationManager::Target PDFAnnotationManager::getTarget() const
{
return m_target;
@@ -1094,6 +1162,19 @@ void PDFAnnotationManager::setTarget(Target target)
m_target = target;
}
PDFWidgetAnnotationManager::PDFWidgetAnnotationManager(PDFDrawWidgetProxy* proxy, QObject* parent) :
BaseClass(proxy->getFontCache(), proxy->getCMSManager(), proxy->getOptionalContentActivity(), proxy->getMeshQualitySettings(), proxy->getFeatures(), Target::View, parent),
m_proxy(proxy)
{
Q_ASSERT(proxy);
m_proxy->registerDrawInterface(this);
}
PDFWidgetAnnotationManager::~PDFWidgetAnnotationManager()
{
m_proxy->unregisterDrawInterface(this);
}
void PDFSimpleGeometryAnnotation::draw(AnnotationDrawParameters& parameters) const
{
Q_ASSERT(parameters.painter);

View File

@@ -22,8 +22,11 @@
#include "pdfobject.h"
#include "pdfaction.h"
#include "pdffile.h"
#include "pdfcms.h"
#include "pdfmultimedia.h"
#include "pdfmeshqualitysettings.h"
#include "pdfdocumentdrawinterface.h"
#include "pdfrenderer.h"
#include <QPainterPath>
@@ -33,6 +36,8 @@ namespace pdf
{
class PDFObjectStorage;
class PDFDrawWidgetProxy;
class PDFFontCache;
class PDFOptionalContentActivity;
using TextAlignment = Qt::Alignment;
using Polygons = std::vector<QPolygonF>;
@@ -1230,9 +1235,8 @@ private:
/// Annotation manager manages annotations for document's pages. Each page
/// can have multiple annotations, and this object caches them. Also,
/// this object builds annotation's appearance streams, if necessary.
/// This object is not thread safe, functions can't be called from another
/// thread.
/// this object builds annotation's appearance streams, if necessary. This
/// manager is intended to non-gui rendering.
class PDFFORQTLIBSHARED_EXPORT PDFAnnotationManager : public QObject, public IDocumentDrawInterface
{
Q_OBJECT
@@ -1248,7 +1252,13 @@ public:
Print
};
explicit PDFAnnotationManager(PDFDrawWidgetProxy* proxy, QObject* parent);
explicit PDFAnnotationManager(PDFFontCache* fontCache,
const PDFCMSManager* cmsManager,
const PDFOptionalContentActivity* optionalActivity,
PDFMeshQualitySettings meshQualitySettings,
PDFRenderer::Features features,
Target target,
QObject* parent);
virtual ~PDFAnnotationManager() override;
virtual void drawPage(QPainter* painter,
@@ -1257,11 +1267,23 @@ public:
PDFTextLayoutGetter& layoutGetter,
const QMatrix& pagePointToDevicePointMatrix) const override;
void setDocument(const PDFDocument* document);
void setDocument(const PDFDocument* document, const PDFOptionalContentActivity* optionalContentActivity);
Target getTarget() const;
void setTarget(Target target);
const PDFOptionalContentActivity* getOptionalActivity() const;
void setOptionalActivity(const PDFOptionalContentActivity* optionalActivity);
PDFFontCache* getFontCache() const;
void setFontCache(PDFFontCache* fontCache);
PDFMeshQualitySettings getMeshQualitySettings() const;
void setMeshQualitySettings(const PDFMeshQualitySettings& meshQualitySettings);
PDFRenderer::Features getFeatures() const;
void setFeatures(PDFRenderer::Features features);
private:
struct PageAnnotation
{
@@ -1287,11 +1309,35 @@ private:
PageAnnotations& getPageAnnotations(PDFInteger pageIndex) const;
const PDFDocument* m_document;
PDFDrawWidgetProxy* m_proxy;
PDFFontCache* m_fontCache;
const PDFCMSManager* m_cmsManager;
const PDFOptionalContentActivity* m_optionalActivity;
PDFMeshQualitySettings m_meshQualitySettings;
PDFRenderer::Features m_features;
mutable QMutex m_mutex;
mutable std::map<PDFInteger, PageAnnotations> m_pageAnnotations;
Target m_target = Target::View;
};
/// Annotation manager for GUI rendering, it also manages annotations widgets
/// for parent widget.
class PDFFORQTLIBSHARED_EXPORT PDFWidgetAnnotationManager : public PDFAnnotationManager
{
Q_OBJECT
private:
using BaseClass = PDFAnnotationManager;
public:
explicit PDFWidgetAnnotationManager(PDFDrawWidgetProxy* proxy, QObject* parent);
virtual ~PDFWidgetAnnotationManager() override;
private:
PDFDrawWidgetProxy* m_proxy;
};
} // namespace pdf
#endif // PDFANNOTATION_H

View File

@@ -23,6 +23,7 @@
#include "pdfcompiler.h"
#include "pdfconstants.h"
#include "pdfcms.h"
#include "pdfannotation.h"
#include <QPainter>
#include <QFontMetrics>
@@ -394,6 +395,7 @@ PDFDrawWidgetProxy::PDFDrawWidgetProxy(QObject* parent) :
m_textLayoutCompiler(new PDFAsynchronousTextLayoutCompiler(this)),
m_rasterizer(new PDFRasterizer(this)),
m_progress(nullptr),
m_annotationManager(nullptr),
m_useOpenGL(false)
{
m_controller = new PDFDrawSpaceController(this);
@@ -824,7 +826,7 @@ QImage PDFDrawWidgetProxy::drawThumbnailImage(PDFInteger pageIndex, int pixelSiz
if (compiledPage && compiledPage->isValid())
{
// Rasterize the image.
image = m_rasterizer->render(page, compiledPage, imageSize, m_features);
image = m_rasterizer->render(pageIndex, page, compiledPage, imageSize, m_features, m_annotationManager);
}
if (image.isNull())
@@ -1286,6 +1288,16 @@ void PDFDrawWidgetProxy::updateVerticalScrollbarFromOffset()
}
}
PDFWidgetAnnotationManager* PDFDrawWidgetProxy::getAnnotationManager() const
{
return m_annotationManager;
}
void PDFDrawWidgetProxy::setAnnotationManager(PDFWidgetAnnotationManager* annotationManager)
{
m_annotationManager = annotationManager;
}
PDFRenderer::Features PDFDrawWidgetProxy::getFeatures() const
{
return m_features;

View File

@@ -38,6 +38,7 @@ class PDFWidget;
class IDrawWidget;
class PDFCMSManager;
class PDFTextLayoutGetter;
class PDFWidgetAnnotationManager;
class PDFAsynchronousPageCompiler;
class PDFAsynchronousTextLayoutCompiler;
@@ -357,6 +358,9 @@ public:
/// Returns snapshot of current view area
PDFWidgetSnapshot getSnapshot() const;
PDFWidgetAnnotationManager* getAnnotationManager() const;
void setAnnotationManager(PDFWidgetAnnotationManager* annotationManager);
signals:
void drawSpaceChanged();
void pageLayoutChanged();
@@ -493,6 +497,9 @@ private:
/// Progress
PDFProgress* m_progress;
/// Annotation manager
PDFWidgetAnnotationManager* m_annotationManager;
/// Additional drawing interfaces
std::set<IDocumentDrawInterface*> m_drawInterfaces;

View File

@@ -20,6 +20,7 @@
#include "pdfdocument.h"
#include "pdfexecutionpolicy.h"
#include "pdfprogress.h"
#include "pdfannotation.h"
#include <QDir>
#include <QElapsedTimer>
@@ -193,7 +194,12 @@ void PDFRasterizer::reset(bool useOpenGL, const QSurfaceFormat& surfaceFormat)
}
}
QImage PDFRasterizer::render(const PDFPage* page, const PDFPrecompiledPage* compiledPage, QSize size, PDFRenderer::Features features)
QImage PDFRasterizer::render(PDFInteger pageIndex,
const PDFPage* page,
const PDFPrecompiledPage* compiledPage,
QSize size,
PDFRenderer::Features features,
const PDFAnnotationManager* annotationManager)
{
QImage image;
@@ -228,6 +234,12 @@ QImage PDFRasterizer::render(const PDFPage* page, const PDFPrecompiledPage* comp
QPainter painter(&device);
painter.fillRect(QRect(QPoint(0, 0), size), compiledPage->getPaperColor());
compiledPage->draw(&painter, page->getCropBox(), matrix, features);
if (annotationManager)
{
PDFTextLayoutGetter textLayoutGetter(nullptr, pageIndex);
annotationManager->drawPage(&painter, pageIndex, compiledPage, textLayoutGetter, matrix);
}
}
m_fbo->release();
@@ -253,6 +265,12 @@ QImage PDFRasterizer::render(const PDFPage* page, const PDFPrecompiledPage* comp
QPainter painter(&image);
compiledPage->draw(&painter, page->getCropBox(), matrix, features);
if (annotationManager)
{
PDFTextLayoutGetter textLayoutGetter(nullptr, pageIndex);
annotationManager->drawPage(&painter, pageIndex, compiledPage, textLayoutGetter, matrix);
}
}
// Jakub Melka: Convert the image into format Format_ARGB32_Premultiplied for fast drawing.
@@ -405,7 +423,8 @@ void PDFRasterizerPool::render(const std::vector<PDFInteger>& pageIndices,
// Precompile the page
PDFPrecompiledPage precompiledPage;
PDFRenderer renderer(m_document, m_fontCache, m_cms, m_optionalContentActivity, m_features, m_meshQualitySettings);
PDFCMSPointer cms = m_cmsManager->getCurrentCMS();
PDFRenderer renderer(m_document, m_fontCache, cms.data(), m_optionalContentActivity, m_features, m_meshQualitySettings);
renderer.compile(&precompiledPage, pageIndex);
for (const PDFRenderError error : precompiledPage.getErrors())
@@ -413,9 +432,13 @@ void PDFRasterizerPool::render(const std::vector<PDFInteger>& pageIndices,
emit renderError(PDFRenderError(error.type, PDFTranslationContext::tr("Page %1: %2").arg(pageIndex + 1).arg(error.message)));
}
// Annotation manager
PDFAnnotationManager annotationManager(m_fontCache, m_cmsManager, m_optionalContentActivity, m_meshQualitySettings, m_features, PDFAnnotationManager::Target::Print, nullptr);
annotationManager.setDocument(m_document, m_optionalContentActivity);
// Render page to image
PDFRasterizer* rasterizer = acquire();
QImage image = rasterizer->render(page, &precompiledPage, imageSizeGetter(page), m_features);
QImage image = rasterizer->render(pageIndex, page, &precompiledPage, imageSizeGetter(page), m_features, &annotationManager);
release(rasterizer);
// Now, process the image
@@ -812,8 +835,8 @@ QString PDFPageImageExportSettings::getOutputFileName(PDFInteger pageIndex, cons
}
PDFRasterizerPool::PDFRasterizerPool(const PDFDocument* document,
const PDFFontCache* fontCache,
const PDFCMS* cms,
PDFFontCache* fontCache,
const PDFCMSManager* cmsManager,
const PDFOptionalContentActivity* optionalContentActivity,
PDFRenderer::Features features,
const PDFMeshQualitySettings& meshQualitySettings,
@@ -824,7 +847,7 @@ PDFRasterizerPool::PDFRasterizerPool(const PDFDocument* document,
BaseClass(parent),
m_document(document),
m_fontCache(fontCache),
m_cms(cms),
m_cmsManager(cmsManager),
m_optionalContentActivity(optionalContentActivity),
m_features(features),
m_meshQualitySettings(meshQualitySettings),

View File

@@ -37,7 +37,9 @@ namespace pdf
class PDFCMS;
class PDFProgress;
class PDFFontCache;
class PDFCMSManager;
class PDFPrecompiledPage;
class PDFAnnotationManager;
class PDFOptionalContentActivity;
/// Renders the PDF page on the painter, or onto an image.
@@ -57,6 +59,7 @@ public:
DebugTextLines = 0x0080, ///< Debug text line layout algorithm
InvertColors = 0x0100, ///< Invert colors
DenyExtraGraphics = 0x0200, ///< Do not display additional graphics, for example from tools
DisplayAnnotations = 0x0400, ///< Display annotations
};
Q_DECLARE_FLAGS(Features, Feature)
@@ -95,7 +98,7 @@ public:
static QMatrix createPagePointToDevicePointMatrix(const PDFPage* page, const QRectF& rectangle);
/// Returns default renderer features
static constexpr Features getDefaultFeatures() { return Antialiasing | TextAntialiasing | ClipToCropBox; }
static constexpr Features getDefaultFeatures() { return Antialiasing | TextAntialiasing | ClipToCropBox | DisplayAnnotations; }
private:
const PDFDocument* m_document;
@@ -139,15 +142,20 @@ public:
/// Renders page to the image of given size. If some error occurs, then
/// empty image is returned. Warning: this function can modify this object,
/// so it is not const and is not thread safe.
/// 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
/// \param page Page
/// \param compiledPage Compiled page contents
/// \param size Size of the target image
/// \param features Renderer features
QImage render(const PDFPage* page,
/// \param annotationManager Annotation manager (can be nullptr)
QImage render(PDFInteger pageIndex,
const PDFPage* page,
const PDFPrecompiledPage* compiledPage,
QSize size,
PDFRenderer::Features features);
PDFRenderer::Features features,
const PDFAnnotationManager* annotationManager);
private:
void initializeOpenGL();
@@ -179,7 +187,7 @@ public:
/// Creates new rasterizer pool
/// \param document Document
/// \param fontCache Font cache
/// \param cms Color management system
/// \param cmsManager Color management system manager
/// \param optionalContentActivity Optional content activity
/// \param features Renderer features
/// \param meshQualitySettings Mesh quality settings
@@ -188,8 +196,8 @@ public:
/// \param surfaceFormat Surface format
/// \param parent Parent object
explicit PDFRasterizerPool(const PDFDocument* document,
const PDFFontCache* fontCache,
const PDFCMS* cms,
PDFFontCache* fontCache,
const PDFCMSManager* cmsManager,
const PDFOptionalContentActivity* optionalContentActivity,
PDFRenderer::Features features,
const PDFMeshQualitySettings& meshQualitySettings,
@@ -226,8 +234,8 @@ signals:
private:
const PDFDocument* m_document;
const PDFFontCache* m_fontCache;
const PDFCMS* m_cms;
PDFFontCache* m_fontCache;
const PDFCMSManager* m_cmsManager;
const PDFOptionalContentActivity* m_optionalContentActivity;
PDFRenderer::Features m_features;
const PDFMeshQualitySettings& m_meshQualitySettings;