mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
First few annotations parsing
This commit is contained in:
@@ -20,6 +20,11 @@
|
||||
|
||||
#include "pdfglobal.h"
|
||||
#include "pdfobject.h"
|
||||
#include "pdfaction.h"
|
||||
|
||||
#include <QPainterPath>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
@@ -55,6 +60,20 @@ enum class AnnotationType
|
||||
_3D
|
||||
};
|
||||
|
||||
enum class AnnotationLineEnding
|
||||
{
|
||||
None,
|
||||
Square,
|
||||
Circle,
|
||||
Diamond,
|
||||
OpenArrow,
|
||||
ClosedArrow,
|
||||
Butt,
|
||||
ROpenArrow,
|
||||
RClosedArrow,
|
||||
Slash
|
||||
};
|
||||
|
||||
/// Represents annotation's border. Two main definition exists, one is older,
|
||||
/// called \p Simple, the other one is defined in BS dictionary of the annotation.
|
||||
class PDFAnnotationBorder
|
||||
@@ -171,6 +190,76 @@ private:
|
||||
std::map<Key, PDFObject> m_appearanceStreams;
|
||||
};
|
||||
|
||||
/// Represents annotation's active region, it is used also to
|
||||
/// determine underline lines.
|
||||
class PDFAnnotationQuadrilaterals
|
||||
{
|
||||
public:
|
||||
inline explicit PDFAnnotationQuadrilaterals() = default;
|
||||
inline explicit PDFAnnotationQuadrilaterals(QPainterPath&& path, std::vector<QLineF>&& underLines) :
|
||||
m_path(qMove(path)),
|
||||
m_underLines(qMove(underLines))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const QPainterPath& getPath() const { return m_path; }
|
||||
const std::vector<QLineF>& getUnderlines() const { return m_underLines; }
|
||||
|
||||
private:
|
||||
QPainterPath m_path;
|
||||
std::vector<QLineF> m_underLines;
|
||||
};
|
||||
|
||||
/// Represents callout line (line from annotation to some point)
|
||||
class PDFAnnotationCalloutLine
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Type
|
||||
{
|
||||
Invalid,
|
||||
StartEnd,
|
||||
StartKneeEnd
|
||||
};
|
||||
|
||||
inline explicit PDFAnnotationCalloutLine() = default;
|
||||
inline explicit PDFAnnotationCalloutLine(QPointF start, QPointF end) :
|
||||
m_type(Type::StartEnd),
|
||||
m_points({start, end})
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline explicit PDFAnnotationCalloutLine(QPointF start, QPointF knee, QPointF end) :
|
||||
m_type(Type::StartKneeEnd),
|
||||
m_points({start, knee, end})
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// Parses annotation callout line from the object. If object is invalid, then
|
||||
/// invalid callout line is constructed.
|
||||
/// \param document Document
|
||||
/// \param object Appearance streams object
|
||||
static PDFAnnotationCalloutLine parse(const PDFDocument* document, PDFObject object);
|
||||
|
||||
bool isValid() const { return m_type != Type::Invalid; }
|
||||
Type getType() const { return m_type; }
|
||||
|
||||
QPointF getPoint(int index) const { return m_points.at(index); }
|
||||
|
||||
private:
|
||||
Type m_type = Type::Invalid;
|
||||
std::array<QPointF, 3> m_points;
|
||||
};
|
||||
|
||||
class PDFAnnotation;
|
||||
class PDFMarkupAnnotation;
|
||||
class PDFTextAnnotation;
|
||||
|
||||
using PDFAnnotationPtr = QSharedPointer<PDFAnnotation>;
|
||||
|
||||
/// Base class for all annotation types. Represents PDF annotation object.
|
||||
/// Annotations are various enhancements to pages graphical representation,
|
||||
/// such as graphics, text, highlight or multimedia content, such as sounds,
|
||||
@@ -195,9 +284,45 @@ public:
|
||||
ToggleNoView = 0x0100, ///< If set, invert the interpretation of NoView flag
|
||||
LockedContents = 0x0200, ///< Do not allow to modify contents of the annotation
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
virtual AnnotationType getType() const = 0;
|
||||
|
||||
virtual PDFMarkupAnnotation* asMarkupAnnotation() { return nullptr; }
|
||||
virtual const PDFMarkupAnnotation* asMarkupAnnotation() const { return nullptr; }
|
||||
|
||||
const QRectF& getRectangle() const { return m_rectangle; }
|
||||
const QString& getContents() const { return m_contents; }
|
||||
PDFObjectReference getPageReference() const { return m_pageReference; }
|
||||
const QString& getName() const { return m_name; }
|
||||
const QDateTime& getLastModifiedDateTime() const { return m_lastModified; }
|
||||
const QString& getLastModifiedString() const { return m_lastModifiedString; }
|
||||
Flags getFlags() const { return m_flags; }
|
||||
const PDFAppeareanceStreams& getAppearanceStreams() const { return m_appearanceStreams; }
|
||||
const QByteArray& getAppearanceState() const { return m_appearanceState; }
|
||||
const PDFAnnotationBorder& getBorder() const { return m_annotationBorder; }
|
||||
const std::vector<PDFReal>& getColor() const { return m_color; }
|
||||
PDFInteger getStructuralParent() const { return m_structParent; }
|
||||
PDFObjectReference getOptionalContent() const { return m_optionalContentReference; }
|
||||
|
||||
/// Parses annotation from the object. If error occurs, then nullptr is returned.
|
||||
/// \param document Document
|
||||
/// \param object Annotation object
|
||||
static PDFAnnotationPtr parse(const PDFDocument* document, PDFObject object);
|
||||
|
||||
/// Parses quadrilaterals and fills them in the painter path. If no quadrilaterals are defined,
|
||||
/// then annotation rectangle is used. If annotation rectangle is also invalid,
|
||||
/// then empty painter path is used.
|
||||
/// \param document Document
|
||||
/// \param quadrilateralsObject Object with quadrilaterals definition
|
||||
/// \param annotationRect Annotation rectangle
|
||||
static PDFAnnotationQuadrilaterals parseQuadrilaterals(const PDFDocument* document, PDFObject quadrilateralsObject, const QRectF annotationRect);
|
||||
|
||||
/// Converts name to line ending. If appropriate line ending for name is not found,
|
||||
/// then None line ending is returned.
|
||||
/// \param name Name of the line ending
|
||||
static AnnotationLineEnding convertNameToLineEnding(const QByteArray& name);
|
||||
|
||||
private:
|
||||
QRectF m_rectangle; ///< Annotation rectangle, in page coordinates, "Rect" entry
|
||||
QString m_contents; ///< Text to be displayed to the user (or alternate text), "Content" entry
|
||||
@@ -205,6 +330,7 @@ private:
|
||||
QString m_name; ///< Unique name (in page context) for the annotation, "NM" entry
|
||||
QDateTime m_lastModified; ///< Date and time, when annotation was last modified, "M" entry
|
||||
QString m_lastModifiedString; ///< Date and time, in text format
|
||||
Flags m_flags; ///< Annotation flags
|
||||
PDFAppeareanceStreams m_appearanceStreams; ///< Appearance streams, "AP" entry
|
||||
QByteArray m_appearanceState; ///< Appearance state, "AS" entry
|
||||
PDFAnnotationBorder m_annotationBorder; ///< Annotation border, "Border" entry
|
||||
@@ -213,6 +339,205 @@ private:
|
||||
PDFObjectReference m_optionalContentReference; ///< Reference to optional content, "OC" entry
|
||||
};
|
||||
|
||||
/// Markup annotation object, used to mark up contents of PDF documents. Markup annotations
|
||||
/// can have various types, as free text (just text displayed on page), annotations with popup
|
||||
/// windows, and special annotations, such as multimedia annotations.
|
||||
class PDFMarkupAnnotation : public PDFAnnotation
|
||||
{
|
||||
public:
|
||||
explicit inline PDFMarkupAnnotation() = default;
|
||||
|
||||
virtual PDFMarkupAnnotation* asMarkupAnnotation() override { return this; }
|
||||
virtual const PDFMarkupAnnotation* asMarkupAnnotation() const override { return this; }
|
||||
|
||||
enum class ReplyType
|
||||
{
|
||||
Reply,
|
||||
Group
|
||||
};
|
||||
|
||||
const QString& getWindowTitle() const { return m_windowTitle; }
|
||||
PDFObjectReference getPopupAnnotation() const { return m_popupAnnotation; }
|
||||
PDFReal getOpacity() const { return m_opacity; }
|
||||
const QString& getRichTextString() const { return m_richTextString; }
|
||||
const QDateTime& getCreationDate() const { return m_creationDate; }
|
||||
PDFObjectReference getInReplyTo() const { return m_inReplyTo; }
|
||||
const QString& getSubject() const { return m_subject; }
|
||||
ReplyType getReplyType() const { return m_replyType; }
|
||||
const QByteArray& getIntent() const { return m_intent; }
|
||||
const PDFObject& getExternalData() const { return m_externalData; }
|
||||
|
||||
private:
|
||||
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
|
||||
|
||||
QString m_windowTitle;
|
||||
PDFObjectReference m_popupAnnotation;
|
||||
PDFReal m_opacity = 1.0;
|
||||
QString m_richTextString;
|
||||
QDateTime m_creationDate;
|
||||
PDFObjectReference m_inReplyTo;
|
||||
QString m_subject;
|
||||
ReplyType m_replyType = ReplyType::Reply;
|
||||
QByteArray m_intent;
|
||||
PDFObject m_externalData;
|
||||
};
|
||||
|
||||
/// Text annotation represents note attached to a specific point in the PDF
|
||||
/// document. It appears as icon, and it is not zoomed, or rotated (behaves
|
||||
/// as if flag NoZoom and NoRotate were set). When this annotation is opened,
|
||||
/// it displays popup window containing the text of the note, font and size
|
||||
/// is implementation dependent by viewer application.
|
||||
class PDFTextAnnotation : public PDFMarkupAnnotation
|
||||
{
|
||||
public:
|
||||
inline explicit PDFTextAnnotation() = default;
|
||||
|
||||
virtual AnnotationType getType() const override { return AnnotationType::Text; }
|
||||
|
||||
bool isOpen() const { return m_open; }
|
||||
const QByteArray& getIconName() const { return m_iconName; }
|
||||
const QString& getState() const { return m_state; }
|
||||
const QString& getStateModel() const { return m_stateModel; }
|
||||
|
||||
private:
|
||||
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
|
||||
|
||||
bool m_open = false;
|
||||
QByteArray m_iconName;
|
||||
QString m_state;
|
||||
QString m_stateModel;
|
||||
};
|
||||
|
||||
/// Link annotation represents hypertext link to a destination to elsewhere
|
||||
/// in the document, or action to be performed.
|
||||
class PDFLinkAnnotation : public PDFAnnotation
|
||||
{
|
||||
public:
|
||||
inline explicit PDFLinkAnnotation() = default;
|
||||
|
||||
virtual AnnotationType getType() const override { return AnnotationType::Link; }
|
||||
|
||||
enum class HighlightMode
|
||||
{
|
||||
None,
|
||||
Invert,
|
||||
Outline,
|
||||
Push
|
||||
};
|
||||
|
||||
const PDFAction* getAction() const { return m_action.data(); }
|
||||
HighlightMode getHighlightMode() const { return m_highlightMode; }
|
||||
const PDFAction* getURIAction() const { return m_previousAction.data(); }
|
||||
const PDFAnnotationQuadrilaterals& getActivationRegion() const { return m_activationRegion; }
|
||||
|
||||
private:
|
||||
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
|
||||
|
||||
PDFActionPtr m_action;
|
||||
HighlightMode m_highlightMode = HighlightMode::Invert;
|
||||
PDFActionPtr m_previousAction;
|
||||
PDFAnnotationQuadrilaterals m_activationRegion;
|
||||
};
|
||||
|
||||
/// Free text annotation displays text directly on the page. Free text doesn't have
|
||||
/// open/close state, text is always visible.
|
||||
class PDFFreeTextAnnotation : public PDFMarkupAnnotation
|
||||
{
|
||||
public:
|
||||
inline explicit PDFFreeTextAnnotation() = default;
|
||||
|
||||
virtual AnnotationType getType() const override { return AnnotationType::FreeText; }
|
||||
|
||||
enum class Justification
|
||||
{
|
||||
Left,
|
||||
Centered,
|
||||
Right
|
||||
};
|
||||
|
||||
enum class Intent
|
||||
{
|
||||
None,
|
||||
Callout,
|
||||
TypeWriter
|
||||
};
|
||||
|
||||
const QByteArray& getDefaultAppearance() const { return m_defaultAppearance; }
|
||||
Justification getJustification() const { return m_justification; }
|
||||
const QString& getDefaultStyle() const { return m_defaultStyleString; }
|
||||
const PDFAnnotationCalloutLine& getCalloutLine() const { return m_calloutLine; }
|
||||
Intent getIntent() const { return m_intent; }
|
||||
const QRectF& getTextRectangle() const { return m_textRectangle; }
|
||||
const PDFAnnotationBorderEffect& getBorderEffect() const { return m_effect; }
|
||||
AnnotationLineEnding getStartLineEnding() const { return m_startLineEnding; }
|
||||
AnnotationLineEnding getEndLineEnding() const { return m_endLineEnding; }
|
||||
|
||||
private:
|
||||
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
|
||||
|
||||
QByteArray m_defaultAppearance;
|
||||
Justification m_justification = Justification::Left;
|
||||
QString m_defaultStyleString;
|
||||
PDFAnnotationCalloutLine m_calloutLine;
|
||||
Intent m_intent = Intent::None;
|
||||
QRectF m_textRectangle;
|
||||
PDFAnnotationBorderEffect m_effect;
|
||||
AnnotationLineEnding m_startLineEnding = AnnotationLineEnding::None;
|
||||
AnnotationLineEnding m_endLineEnding = AnnotationLineEnding::None;
|
||||
};
|
||||
|
||||
/// Line annotation, draws straight line on the page (in most simple form), or
|
||||
/// it can display, for example, dimensions with perpendicular lines at the line
|
||||
/// endings. Caption text can also be displayed.
|
||||
class PDFLineAnnotation : public PDFMarkupAnnotation
|
||||
{
|
||||
public:
|
||||
inline explicit PDFLineAnnotation() = default;
|
||||
|
||||
virtual AnnotationType getType() const override { return AnnotationType::Line; }
|
||||
|
||||
enum class Intent
|
||||
{
|
||||
Arrow,
|
||||
Dimension
|
||||
};
|
||||
|
||||
enum class CaptionPosition
|
||||
{
|
||||
Inline,
|
||||
Top
|
||||
};
|
||||
|
||||
const QLineF& getLine() const { return m_line; }
|
||||
AnnotationLineEnding getStartLineEnding() const { return m_startLineEnding; }
|
||||
AnnotationLineEnding getEndLineEnding() const { return m_endLineEnding; }
|
||||
const std::vector<PDFReal>& getInteriorColor() const { return m_interiorColor; }
|
||||
PDFReal getLeaderLineLength() const { return m_leaderLineLength; }
|
||||
PDFReal getLeaderLineExtension() const { return m_leaderLineExtension; }
|
||||
PDFReal getLeaderLineOffset() const { return m_leaderLineOffset; }
|
||||
bool isCaptionRendered() const { return m_captionRendered; }
|
||||
Intent getIntent() const { return m_intent; }
|
||||
CaptionPosition getCaptionPosition() const { return m_captionPosition; }
|
||||
const PDFObject& getMeasureDictionary() const { return m_measureDictionary; }
|
||||
const QPointF& getCaptionOffset() const { return m_captionOffset; }
|
||||
|
||||
private:
|
||||
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object);
|
||||
|
||||
QLineF m_line;
|
||||
AnnotationLineEnding m_startLineEnding = AnnotationLineEnding::None;
|
||||
AnnotationLineEnding m_endLineEnding = AnnotationLineEnding::None;
|
||||
std::vector<PDFReal> m_interiorColor;
|
||||
PDFReal m_leaderLineLength = 0.0;
|
||||
PDFReal m_leaderLineExtension = 0.0;
|
||||
PDFReal m_leaderLineOffset = 0.0;
|
||||
bool m_captionRendered = false;
|
||||
Intent m_intent = Intent::Arrow;
|
||||
CaptionPosition m_captionPosition = CaptionPosition::Inline;
|
||||
PDFObject m_measureDictionary;
|
||||
QPointF m_captionOffset;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFANNOTATION_H
|
||||
|
Reference in New Issue
Block a user