mirror of https://github.com/JakubMelka/PDF4QT.git
First few annotations parsing
This commit is contained in:
parent
de9e6b9807
commit
758ed1590f
|
@ -17,16 +17,11 @@
|
|||
|
||||
#include "pdfannotation.h"
|
||||
#include "pdfdocument.h"
|
||||
#include "pdfencoding.h"
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFAnnotation::PDFAnnotation() :
|
||||
m_structParent(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFAnnotationBorder PDFAnnotationBorder::parseBorder(const PDFDocument* document, PDFObject object)
|
||||
{
|
||||
PDFAnnotationBorder result;
|
||||
|
@ -150,4 +145,260 @@ PDFObject PDFAppeareanceStreams::getAppearance(Appearance appearance, const QByt
|
|||
return PDFObject();
|
||||
}
|
||||
|
||||
PDFAnnotation::PDFAnnotation() :
|
||||
m_flags(),
|
||||
m_structParent(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFAnnotationPtr PDFAnnotation::parse(const PDFDocument* document, PDFObject object)
|
||||
{
|
||||
PDFAnnotationPtr result;
|
||||
|
||||
const PDFDictionary* dictionary = document->getDictionaryFromObject(object);
|
||||
if (!dictionary)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFDocumentDataLoaderDecorator loader(document);
|
||||
|
||||
QRectF annotationsRectangle = loader.readRectangle(dictionary->get("Rect"), QRectF());
|
||||
|
||||
// Determine type of annotation
|
||||
QByteArray subtype = loader.readNameFromDictionary(dictionary, "Subtype");
|
||||
if (subtype == "Text")
|
||||
{
|
||||
PDFTextAnnotation* textAnnotation = new PDFTextAnnotation;
|
||||
result.reset(textAnnotation);
|
||||
|
||||
textAnnotation->m_open = loader.readBooleanFromDictionary(dictionary, "Open", false);
|
||||
textAnnotation->m_iconName = loader.readNameFromDictionary(dictionary, "Name");
|
||||
textAnnotation->m_state = loader.readTextStringFromDictionary(dictionary, "State", "Unmarked");
|
||||
textAnnotation->m_stateModel = loader.readTextStringFromDictionary(dictionary, "StateModel", "Marked");
|
||||
}
|
||||
else if (subtype == "Link")
|
||||
{
|
||||
PDFLinkAnnotation* linkAnnotation = new PDFLinkAnnotation;
|
||||
result.reset(linkAnnotation);
|
||||
|
||||
linkAnnotation->m_action = PDFAction::parse(document, dictionary->get("A"));
|
||||
if (!linkAnnotation->m_action)
|
||||
{
|
||||
PDFDestination destination = PDFDestination::parse(document, dictionary->get("Dest"));
|
||||
linkAnnotation->m_action.reset(new PDFActionGoTo(destination));
|
||||
}
|
||||
linkAnnotation->m_previousAction = PDFAction::parse(document, dictionary->get("PA"));
|
||||
|
||||
constexpr const std::array<std::pair<const char*, PDFLinkAnnotation::HighlightMode>, 4> highlightMode = {
|
||||
std::pair<const char*, PDFLinkAnnotation::HighlightMode>{ "N", PDFLinkAnnotation::HighlightMode::None },
|
||||
std::pair<const char*, PDFLinkAnnotation::HighlightMode>{ "I", PDFLinkAnnotation::HighlightMode::Invert },
|
||||
std::pair<const char*, PDFLinkAnnotation::HighlightMode>{ "O", PDFLinkAnnotation::HighlightMode::Outline },
|
||||
std::pair<const char*, PDFLinkAnnotation::HighlightMode>{ "P", PDFLinkAnnotation::HighlightMode::Push }
|
||||
};
|
||||
|
||||
linkAnnotation->m_highlightMode = loader.readEnumByName(dictionary->get("H"), highlightMode.begin(), highlightMode.end(), PDFLinkAnnotation::HighlightMode::Invert);
|
||||
linkAnnotation->m_activationRegion = parseQuadrilaterals(document, dictionary->get("QuadPoints"), annotationsRectangle);
|
||||
}
|
||||
else if (subtype == "FreeText")
|
||||
{
|
||||
PDFFreeTextAnnotation* freeTextAnnotation = new PDFFreeTextAnnotation;
|
||||
result.reset(freeTextAnnotation);
|
||||
|
||||
constexpr const std::array<std::pair<const char*, PDFFreeTextAnnotation::Intent>, 2> intents = {
|
||||
std::pair<const char*, PDFFreeTextAnnotation::Intent>{ "FreeTextCallout", PDFFreeTextAnnotation::Intent::Callout },
|
||||
std::pair<const char*, PDFFreeTextAnnotation::Intent>{ "FreeTextTypeWriter", PDFFreeTextAnnotation::Intent::TypeWriter }
|
||||
};
|
||||
|
||||
freeTextAnnotation->m_defaultAppearance = loader.readStringFromDictionary(dictionary, "DA");
|
||||
freeTextAnnotation->m_justification = static_cast<PDFFreeTextAnnotation::Justification>(loader.readIntegerFromDictionary(dictionary, "Q", 0));
|
||||
freeTextAnnotation->m_defaultStyleString = loader.readTextStringFromDictionary(dictionary, "DS", QString());
|
||||
freeTextAnnotation->m_calloutLine = PDFAnnotationCalloutLine::parse(document, dictionary->get("CL"));
|
||||
freeTextAnnotation->m_intent = loader.readEnumByName(dictionary->get("IT"), intents.begin(), intents.end(), PDFFreeTextAnnotation::Intent::None);
|
||||
freeTextAnnotation->m_effect = PDFAnnotationBorderEffect::parse(document, dictionary->get("BE"));
|
||||
|
||||
std::vector<PDFReal> differenceRectangle = loader.readNumberArrayFromDictionary(dictionary, "RD");
|
||||
if (differenceRectangle.size() == 4)
|
||||
{
|
||||
freeTextAnnotation->m_textRectangle = annotationsRectangle.adjusted(differenceRectangle[0], differenceRectangle[1], -differenceRectangle[2], -differenceRectangle[3]);
|
||||
if (!freeTextAnnotation->m_textRectangle.isValid())
|
||||
{
|
||||
freeTextAnnotation->m_textRectangle = QRectF();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QByteArray> lineEndings = loader.readNameArrayFromDictionary(dictionary, "LE");
|
||||
if (lineEndings.size() == 2)
|
||||
{
|
||||
freeTextAnnotation->m_startLineEnding = convertNameToLineEnding(lineEndings[0]);
|
||||
freeTextAnnotation->m_endLineEnding = convertNameToLineEnding(lineEndings[1]);
|
||||
}
|
||||
}
|
||||
else if (subtype == "Line")
|
||||
{
|
||||
PDFLineAnnotation* lineAnnotation = new PDFLineAnnotation;
|
||||
result.reset(lineAnnotation);
|
||||
|
||||
std::vector<PDFReal> line = loader.readNumberArrayFromDictionary(dictionary, "L");
|
||||
if (line.size() == 4)
|
||||
{
|
||||
lineAnnotation->m_line = QLineF(line[0], line[1], line[2], line[3]);
|
||||
}
|
||||
|
||||
std::vector<QByteArray> lineEndings = loader.readNameArrayFromDictionary(dictionary, "LE");
|
||||
if (lineEndings.size() == 2)
|
||||
{
|
||||
lineAnnotation->m_startLineEnding = convertNameToLineEnding(lineEndings[0]);
|
||||
lineAnnotation->m_endLineEnding = convertNameToLineEnding(lineEndings[1]);
|
||||
}
|
||||
|
||||
lineAnnotation->m_interiorColor = loader.readNumberArrayFromDictionary(dictionary, "IC");
|
||||
lineAnnotation->m_leaderLineLength = loader.readNumberFromDictionary(dictionary, "LL", 0.0);
|
||||
lineAnnotation->m_leaderLineExtension = loader.readNumberFromDictionary(dictionary, "LLE", 0.0);
|
||||
lineAnnotation->m_leaderLineOffset = loader.readNumberFromDictionary(dictionary, "LLO", 0.0);
|
||||
lineAnnotation->m_captionRendered = loader.readBooleanFromDictionary(dictionary, "Cap", false);
|
||||
lineAnnotation->m_intent = (loader.readNameFromDictionary(dictionary, "IT") == "LineDimension") ? PDFLineAnnotation::Intent::Dimension : PDFLineAnnotation::Intent::Arrow;
|
||||
lineAnnotation->m_captionPosition = (loader.readNameFromDictionary(dictionary, "CP") == "Top") ? PDFLineAnnotation::CaptionPosition::Top : PDFLineAnnotation::CaptionPosition::Inline;
|
||||
lineAnnotation->m_measureDictionary = document->getObject(dictionary->get("Measure"));
|
||||
|
||||
std::vector<PDFReal> captionOffset = loader.readNumberArrayFromDictionary(dictionary, "CO");
|
||||
if (captionOffset.size() == 2)
|
||||
{
|
||||
lineAnnotation->m_captionOffset == QPointF(captionOffset[0], captionOffset[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// Invalid annotation type
|
||||
return result;
|
||||
}
|
||||
|
||||
// Load common data for annotation
|
||||
result->m_rectangle = annotationsRectangle;
|
||||
result->m_contents = loader.readTextStringFromDictionary(dictionary, "Contents", QString());
|
||||
result->m_pageReference = loader.readReferenceFromDictionary(dictionary, "P");
|
||||
result->m_name = loader.readTextStringFromDictionary(dictionary, "NM", QString());
|
||||
|
||||
QByteArray string = loader.readStringFromDictionary(dictionary, "M");
|
||||
result->m_lastModified = PDFEncoding::convertToDateTime(string);
|
||||
if (!result->m_lastModified.isValid())
|
||||
{
|
||||
result->m_lastModifiedString = loader.readTextStringFromDictionary(dictionary, "M", QString());
|
||||
}
|
||||
|
||||
result->m_flags = Flags(loader.readIntegerFromDictionary(dictionary, "F", 0));
|
||||
result->m_appearanceStreams = PDFAppeareanceStreams::parse(document, dictionary->get("AP"));
|
||||
result->m_appearanceState = loader.readNameFromDictionary(dictionary, "AS");
|
||||
|
||||
result->m_annotationBorder = PDFAnnotationBorder::parseBS(document, dictionary->get("BS"));
|
||||
if (!result->m_annotationBorder.isValid())
|
||||
{
|
||||
result->m_annotationBorder = PDFAnnotationBorder::parseBorder(document, dictionary->get("Border"));
|
||||
}
|
||||
result->m_color = loader.readNumberArrayFromDictionary(dictionary, "C");
|
||||
result->m_structParent = loader.readIntegerFromDictionary(dictionary, "StructParent", 0);
|
||||
result->m_optionalContentReference = loader.readReferenceFromDictionary(dictionary, "OC");
|
||||
|
||||
if (PDFMarkupAnnotation* markupAnnotation = result->asMarkupAnnotation())
|
||||
{
|
||||
markupAnnotation->m_windowTitle = loader.readTextStringFromDictionary(dictionary, "T", QString());
|
||||
markupAnnotation->m_popupAnnotation = loader.readReferenceFromDictionary(dictionary, "Popup");
|
||||
markupAnnotation->m_opacity = loader.readNumberFromDictionary(dictionary, "CA", 1.0);
|
||||
markupAnnotation->m_richTextString = loader.readTextStringFromDictionary(dictionary, "RC", QString());
|
||||
markupAnnotation->m_creationDate = PDFEncoding::convertToDateTime(loader.readStringFromDictionary(dictionary, "CreationDate"));
|
||||
markupAnnotation->m_inReplyTo = loader.readReferenceFromDictionary(dictionary, "IRT");
|
||||
markupAnnotation->m_subject = loader.readTextStringFromDictionary(dictionary, "Subj", QString());
|
||||
markupAnnotation->m_replyType = (loader.readNameFromDictionary(dictionary, "RT") == "Group") ? PDFMarkupAnnotation::ReplyType::Group : PDFMarkupAnnotation::ReplyType::Reply;
|
||||
markupAnnotation->m_intent = loader.readNameFromDictionary(dictionary, "IT");
|
||||
markupAnnotation->m_externalData = document->getObject(dictionary->get("ExData"));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFAnnotationQuadrilaterals PDFAnnotation::parseQuadrilaterals(const PDFDocument* document, PDFObject quadrilateralsObject, const QRectF annotationRect)
|
||||
{
|
||||
QPainterPath path;
|
||||
std::vector<QLineF> underlines;
|
||||
|
||||
PDFDocumentDataLoaderDecorator loader(document);
|
||||
std::vector<PDFReal> points = loader.readNumberArray(quadrilateralsObject);
|
||||
const size_t quadrilateralCount = points.size() % 8;
|
||||
path.reserve(int(quadrilateralCount) + 5);
|
||||
underlines.reserve(quadrilateralCount);
|
||||
for (size_t i = 0; i < quadrilateralCount; ++i)
|
||||
{
|
||||
const size_t offset = i * 8;
|
||||
QPointF p1(points[offset + 0], points[offset + 1]);
|
||||
QPointF p2(points[offset + 2], points[offset + 3]);
|
||||
QPointF p3(points[offset + 4], points[offset + 5]);
|
||||
QPointF p4(points[offset + 6], points[offset + 7]);
|
||||
|
||||
path.moveTo(p1);
|
||||
path.lineTo(p2);
|
||||
path.lineTo(p3);
|
||||
path.lineTo(p4);
|
||||
path.lineTo(p1);
|
||||
path.closeSubpath();
|
||||
|
||||
underlines.emplace_back(p1, p2);
|
||||
}
|
||||
|
||||
if (path.isEmpty() && annotationRect.isValid())
|
||||
{
|
||||
// Jakub Melka: we are using points at the top, because PDF has inverted y axis
|
||||
// against the Qt's y axis.
|
||||
path.addRect(annotationRect);
|
||||
underlines.emplace_back(annotationRect.topLeft(), annotationRect.topRight());
|
||||
}
|
||||
|
||||
return PDFAnnotationQuadrilaterals(qMove(path), qMove(underlines));
|
||||
}
|
||||
|
||||
AnnotationLineEnding PDFAnnotation::convertNameToLineEnding(const QByteArray& name)
|
||||
{
|
||||
constexpr const std::array<std::pair<AnnotationLineEnding, const char*>, 10> lineEndings = {
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::None, "None" },
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::Square, "Square" },
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::Circle, "Circle" },
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::Diamond, "Diamond" },
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::OpenArrow, "OpenArrow" },
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::ClosedArrow, "ClosedArrow" },
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::Butt, "Butt" },
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::ROpenArrow, "ROpenArrow" },
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::RClosedArrow, "RClosedArrow" },
|
||||
std::pair<AnnotationLineEnding, const char*>{ AnnotationLineEnding::Slash, "Slash" }
|
||||
};
|
||||
|
||||
auto it = std::find_if(lineEndings.cbegin(), lineEndings.cend(), [&name](const auto& item) { return name == item.second; });
|
||||
if (it != lineEndings.cend())
|
||||
{
|
||||
return it->first;
|
||||
}
|
||||
|
||||
return AnnotationLineEnding::None;
|
||||
}
|
||||
|
||||
PDFAnnotationCalloutLine PDFAnnotationCalloutLine::parse(const PDFDocument* document, PDFObject object)
|
||||
{
|
||||
PDFDocumentDataLoaderDecorator loader(document);
|
||||
std::vector<PDFReal> points = loader.readNumberArray(object);
|
||||
|
||||
switch (points.size())
|
||||
{
|
||||
case 4:
|
||||
return PDFAnnotationCalloutLine(QPointF(points[0], points[1]), QPointF(points[2], points[3]));
|
||||
|
||||
case 6:
|
||||
return PDFAnnotationCalloutLine(QPointF(points[0], points[1]), QPointF(points[2], points[3]), QPointF(points[4], points[5]));
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return PDFAnnotationCalloutLine();
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -481,6 +481,18 @@ std::vector<PDFInteger> PDFDocumentDataLoaderDecorator::readIntegerArray(const P
|
|||
return std::vector<PDFInteger>();
|
||||
}
|
||||
|
||||
PDFObjectReference PDFDocumentDataLoaderDecorator::readReferenceFromDictionary(const PDFDictionary* dictionary, const char* key) const
|
||||
{
|
||||
const PDFObject& object = dictionary->get(key);
|
||||
|
||||
if (object.isReference())
|
||||
{
|
||||
return object.getReference();
|
||||
}
|
||||
|
||||
return PDFObjectReference();
|
||||
}
|
||||
|
||||
std::vector<PDFObjectReference> PDFDocumentDataLoaderDecorator::readReferenceArray(const PDFObject& object) const
|
||||
{
|
||||
const PDFObject& dereferencedObject = m_document->getObject(object);
|
||||
|
|
|
@ -248,7 +248,12 @@ public:
|
|||
/// \param object Object containing array of numbers
|
||||
std::vector<PDFInteger> readIntegerArray(const PDFObject& object) const;
|
||||
|
||||
/// Reads reference array from dictionary. Reads all values. If error occurs,
|
||||
/// Reads reference from dictionary. If error occurs, then invalid reference is returned.
|
||||
/// \param dictionary Dictionary containing desired data
|
||||
/// \param key Entry key
|
||||
PDFObjectReference readReferenceFromDictionary(const PDFDictionary* dictionary, const char* key) const;
|
||||
|
||||
/// Reads reference array. Reads all values. If error occurs,
|
||||
/// then empty array is returned.
|
||||
/// \param object Object containing array of references
|
||||
std::vector<PDFObjectReference> readReferenceArray(const PDFObject& object) const;
|
||||
|
|
Loading…
Reference in New Issue