Annotations

This commit is contained in:
Jakub Melka 2020-03-03 19:58:51 +01:00
parent 7db167eea3
commit de9e6b9807
3 changed files with 373 additions and 0 deletions

View File

@ -37,6 +37,7 @@ DESTDIR = $$OUT_PWD/..
SOURCES += \
sources/pdfaction.cpp \
sources/pdfannotation.cpp \
sources/pdfblendfunction.cpp \
sources/pdfccittfaxdecoder.cpp \
sources/pdfcms.cpp \
@ -81,6 +82,7 @@ SOURCES += \
HEADERS += \
sources/pdfaction.h \
sources/pdfannotation.h \
sources/pdfblendfunction.h \
sources/pdfccittfaxdecoder.h \
sources/pdfcms.h \

View File

@ -0,0 +1,153 @@
// Copyright (C) 2020 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/>.
#include "pdfannotation.h"
#include "pdfdocument.h"
namespace pdf
{
PDFAnnotation::PDFAnnotation() :
m_structParent(0)
{
}
PDFAnnotationBorder PDFAnnotationBorder::parseBorder(const PDFDocument* document, PDFObject object)
{
PDFAnnotationBorder result;
object = document->getObject(object);
if (object.isArray())
{
const PDFArray* array = object.getArray();
if (array->getCount() >= 3)
{
PDFDocumentDataLoaderDecorator loader(document);
result.m_definition = Definition::Simple;
result.m_hCornerRadius = loader.readNumber(array->getItem(0), 0.0);
result.m_vCornerRadius = loader.readNumber(array->getItem(1), 0.0);
result.m_width = loader.readNumber(array->getItem(2), 1.0);
if (array->getCount() >= 4)
{
result.m_dashPattern = loader.readNumberArray(array->getItem(3));
}
}
}
return result;
}
PDFAnnotationBorder PDFAnnotationBorder::parseBS(const PDFDocument* document, PDFObject object)
{
PDFAnnotationBorder result;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object))
{
PDFDocumentDataLoaderDecorator loader(document);
result.m_definition = Definition::BorderStyle;
result.m_width = loader.readNumberFromDictionary(dictionary, "W", 1.0);
constexpr const std::array<std::pair<const char*, Style>, 6> styles = {
std::pair<const char*, Style>{ "S", Style::Solid },
std::pair<const char*, Style>{ "D", Style::Dashed },
std::pair<const char*, Style>{ "B", Style::Beveled },
std::pair<const char*, Style>{ "I", Style::Inset },
std::pair<const char*, Style>{ "U", Style::Underline }
};
result.m_style = loader.readEnumByName(dictionary->get("S"), styles.begin(), styles.end(), Style::Solid);
}
return result;
}
PDFAnnotationBorderEffect PDFAnnotationBorderEffect::parse(const PDFDocument* document, PDFObject object)
{
PDFAnnotationBorderEffect result;
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object))
{
PDFDocumentDataLoaderDecorator loader(document);
result.m_intensity = loader.readNumberFromDictionary(dictionary, "I", 0.0);
constexpr const std::array<std::pair<const char*, Effect>, 2> effects = {
std::pair<const char*, Effect>{ "S", Effect::None },
std::pair<const char*, Effect>{ "C", Effect::Cloudy }
};
result.m_effect = loader.readEnumByName(dictionary->get("S"), effects.begin(), effects.end(), Effect::None);
}
return result;
}
PDFAppeareanceStreams PDFAppeareanceStreams::parse(const PDFDocument* document, PDFObject object)
{
PDFAppeareanceStreams result;
auto processSubdicitonary = [&result, document](Appearance appearance, PDFObject subdictionaryObject)
{
if (const PDFDictionary* subdictionary = document->getDictionaryFromObject(subdictionaryObject))
{
for (size_t i = 0; i < subdictionary->getCount(); ++i)
{
result.m_appearanceStreams[std::make_pair(appearance, subdictionary->getKey(i))] = subdictionary->getValue(i);
}
}
else if (!subdictionaryObject.isNull())
{
result.m_appearanceStreams[std::make_pair(appearance, QByteArray())] = subdictionaryObject;
}
};
if (const PDFDictionary* dictionary = document->getDictionaryFromObject(object))
{
processSubdicitonary(Appearance::Normal, dictionary->get("N"));
processSubdicitonary(Appearance::Rollover, dictionary->get("R"));
processSubdicitonary(Appearance::Down, dictionary->get("D"));
}
return result;
}
PDFObject PDFAppeareanceStreams::getAppearance(Appearance appearance, const QByteArray& state) const
{
Key key(appearance, state);
auto it = m_appearanceStreams.find(key);
if (it == m_appearanceStreams.cend() && appearance != Appearance::Normal)
{
key.first = Appearance::Normal;
it = m_appearanceStreams.find(key);
}
if (it == m_appearanceStreams.cend() && !state.isEmpty())
{
key.second = QByteArray();
it = m_appearanceStreams.find(key);
}
if (it != m_appearanceStreams.cend())
{
return it->second;
}
return PDFObject();
}
} // namespace pdf

View File

@ -0,0 +1,218 @@
// Copyright (C) 2020 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 PDFANNOTATION_H
#define PDFANNOTATION_H
#include "pdfglobal.h"
#include "pdfobject.h"
namespace pdf
{
class PDFDocument;
enum class AnnotationType
{
Invalid,
Text,
Link,
FreeText,
Line,
Square,
Circle,
Polygon,
Polyline,
Highlight,
Underline,
Squiggly,
StrikeOut,
Stamp,
Caret,
Ink,
Popup,
FileAttachment,
Sound,
Moview,
Widget,
Screen,
PrinterMark,
TrapNet,
Watermark,
_3D
};
/// 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
{
public:
explicit inline PDFAnnotationBorder() = default;
enum class Definition
{
Invalid,
Simple,
BorderStyle
};
enum class Style
{
Solid,
Dashed,
Beveled,
Inset,
Underline
};
/// Parses the annotation border from the array. If object contains invalid annotation border,
/// then default annotation border is returned. If object is empty, empty annotation border is returned.
/// \param document Document
/// \param object Border object
static PDFAnnotationBorder parseBorder(const PDFDocument* document, PDFObject object);
/// Parses the annotation border from the BS dictionary. If object contains invalid annotation border,
/// then default annotation border is returned. If object is empty, empty annotation border is returned.
/// \param document Document
/// \param object Border object
static PDFAnnotationBorder parseBS(const PDFDocument* document, PDFObject object);
/// Returns true, if object is correctly defined
bool isValid() const { return m_definition != Definition::Invalid; }
Definition getDefinition() const { return m_definition; }
Style getStyle() const { return m_style; }
PDFReal getHorizontalCornerRadius() const { return m_hCornerRadius; }
PDFReal getVerticalCornerRadius() const { return m_vCornerRadius; }
PDFReal getWidth() const { return m_width; }
const std::vector<PDFReal>& getDashPattern() const { return m_dashPattern; }
private:
Definition m_definition = Definition::Invalid;
Style m_style = Style::Solid;
PDFReal m_hCornerRadius = 0.0;
PDFReal m_vCornerRadius = 0.0;
PDFReal m_width = 1.0;
std::vector<PDFReal> m_dashPattern;
};
/// Annotation border effect
class PDFAnnotationBorderEffect
{
public:
explicit inline PDFAnnotationBorderEffect() = default;
enum class Effect
{
None,
Cloudy
};
/// Parses the annotation border effect from the object. If object contains invalid annotation border effect,
/// then default annotation border effect is returned. If object is empty, also default annotation border effect is returned.
/// \param document Document
/// \param object Border effect object
static PDFAnnotationBorderEffect parse(const PDFDocument* document, PDFObject object);
private:
Effect m_effect = Effect::None;
PDFReal m_intensity = 0.0;
};
/// Storage which handles appearance streams of annotations. Appeareance streams are divided
/// to three main categories - normal, rollower and down. Each category can have different
/// states, for example, checkbox can have on/off state. This container can also resolve
/// queries to obtain appropriate appearance stream.
class PDFAppeareanceStreams
{
public:
explicit inline PDFAppeareanceStreams() = default;
enum class Appearance
{
Normal,
Rollover,
Down
};
using Key = std::pair<Appearance, QByteArray>;
/// Parses annotation appearance streams from the object. If object is invalid, then
/// empty appearance stream is constructed.
/// \param document Document
/// \param object Appearance streams object
static PDFAppeareanceStreams parse(const PDFDocument* document, PDFObject object);
/// Tries to search for appearance stream for given appearance. If no appearance is found,
/// then null object is returned.
/// \param appearance Appearance type
PDFObject getAppearance(Appearance appearance = Appearance::Normal) const { return getAppearance(appearance, QByteArray()); }
/// Tries to resolve appearance stream for given appearance and state. If no appearance is found,
/// then null object is returned.
/// \param appearance Appearance type
/// \param state State name
PDFObject getAppearance(Appearance appearance, const QByteArray& state) const;
private:
std::map<Key, PDFObject> m_appearanceStreams;
};
/// 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,
/// videos and 3D annotations.
class PDFAnnotation
{
public:
explicit PDFAnnotation();
virtual ~PDFAnnotation() = default;
enum Flag : uint
{
None = 0x0000,
Invisible = 0x0001, ///< If set, do not display unknown annotations using their AP dictionary
Hidden = 0x0002, ///< If set, do not display annotation and do not show popup windows (completely hidden)
Print = 0x0004, ///< If set, print annotation
NoZoom = 0x0008, ///< Do not apply page zoom while displaying annotation rectangle
NoRotate = 0x0010, ///< Do not rotate annotation's appearance to match orientation of the page
NoView = 0x0020, ///< Do not display annotation on the screen (it still can be printed)
ReadOnly = 0x0040, ///< Do not allow interacting with the user (and disallow also mouse interaction)
Locked = 0x0080, ///< Do not allow to delete/modify annotation by user
ToggleNoView = 0x0100, ///< If set, invert the interpretation of NoView flag
LockedContents = 0x0200, ///< Do not allow to modify contents of the annotation
};
virtual AnnotationType getType() const = 0;
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
PDFObjectReference m_pageReference; ///< Reference to annotation's page, "P" entry
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
PDFAppeareanceStreams m_appearanceStreams; ///< Appearance streams, "AP" entry
QByteArray m_appearanceState; ///< Appearance state, "AS" entry
PDFAnnotationBorder m_annotationBorder; ///< Annotation border, "Border" entry
std::vector<PDFReal> m_color; ///< Color (for example, title bar of popup window), "C" entry
PDFInteger m_structParent; ///< Structural parent identifier, "StructParent" entry
PDFObjectReference m_optionalContentReference; ///< Reference to optional content, "OC" entry
};
} // namespace pdf
#endif // PDFANNOTATION_H