mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
File attachment annotation graphics
This commit is contained in:
@ -447,14 +447,14 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject
|
||||
|
||||
annotation->m_fileSpecification = PDFFileSpecification::parse(storage, dictionary->get("FS"));
|
||||
|
||||
constexpr const std::array<std::pair<const char*, PDFFileAttachmentAnnotation::Icon>, 4> icons = {
|
||||
std::pair<const char*, PDFFileAttachmentAnnotation::Icon>{ "Graph", PDFFileAttachmentAnnotation::Icon::Graph },
|
||||
std::pair<const char*, PDFFileAttachmentAnnotation::Icon>{ "Paperclip", PDFFileAttachmentAnnotation::Icon::Paperclip },
|
||||
std::pair<const char*, PDFFileAttachmentAnnotation::Icon>{ "PushPin", PDFFileAttachmentAnnotation::Icon::PushPin },
|
||||
std::pair<const char*, PDFFileAttachmentAnnotation::Icon>{ "Tag", PDFFileAttachmentAnnotation::Icon::Tag }
|
||||
constexpr const std::array<std::pair<const char*, FileAttachmentIcon>, 4> icons = {
|
||||
std::pair<const char*, FileAttachmentIcon>{ "Graph", FileAttachmentIcon::Graph },
|
||||
std::pair<const char*, FileAttachmentIcon>{ "Paperclip", FileAttachmentIcon::Paperclip },
|
||||
std::pair<const char*, FileAttachmentIcon>{ "PushPin", FileAttachmentIcon::PushPin },
|
||||
std::pair<const char*, FileAttachmentIcon>{ "Tag", FileAttachmentIcon::Tag }
|
||||
};
|
||||
|
||||
annotation->m_icon = loader.readEnumByName(dictionary->get("Name"), icons.begin(), icons.end(), PDFFileAttachmentAnnotation::Icon::PushPin);
|
||||
annotation->m_icon = loader.readEnumByName(dictionary->get("Name"), icons.begin(), icons.end(), FileAttachmentIcon::PushPin);
|
||||
}
|
||||
else if (subtype == "Sound")
|
||||
{
|
||||
@ -2121,4 +2121,49 @@ void PDFStampAnnotation::draw(AnnotationDrawParameters& parameters) const
|
||||
parameters.boundingRectangle.adjust(-penWidth, -penWidth, penWidth, penWidth);
|
||||
}
|
||||
|
||||
void PDFFileAttachmentAnnotation::draw(AnnotationDrawParameters& parameters) const
|
||||
{
|
||||
QString text = "?";
|
||||
switch (getIcon())
|
||||
{
|
||||
case FileAttachmentIcon::Graph:
|
||||
text = QString::fromUtf16(u"\U0001F4C8");
|
||||
break;
|
||||
case FileAttachmentIcon::Paperclip:
|
||||
text = QString::fromUtf16(u"\U0001F4CE");
|
||||
break;
|
||||
case FileAttachmentIcon::PushPin:
|
||||
text = QString::fromUtf16(u"\U0001F4CC");
|
||||
break;
|
||||
case FileAttachmentIcon::Tag:
|
||||
text = QString::fromUtf16(u"\U0001F3F7");
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
const PDFReal opacity = getOpacity();
|
||||
QColor strokeColor = QColor::fromRgbF(0.0, 0.0, 0.0, opacity);
|
||||
|
||||
constexpr const PDFReal rectSize = 24.0;
|
||||
QPainter& painter = *parameters.painter;
|
||||
QRectF rectangle = getRectangle();
|
||||
rectangle.setSize(QSizeF(rectSize, rectSize));
|
||||
|
||||
QFont font = QApplication::font();
|
||||
font.setPixelSize(16.0);
|
||||
|
||||
QPainterPath textPath;
|
||||
textPath.addText(0.0, 0.0, font, text);
|
||||
textPath = QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0).map(textPath);
|
||||
QRectF textBoundingRect = textPath.boundingRect();
|
||||
QPointF offset = rectangle.center() - textBoundingRect.center();
|
||||
textPath.translate(offset);
|
||||
painter.fillPath(textPath, QBrush(strokeColor, Qt::SolidPattern));
|
||||
|
||||
parameters.boundingRectangle = rectangle;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
@ -1001,6 +1001,14 @@ private:
|
||||
bool m_opened = false;
|
||||
};
|
||||
|
||||
enum class FileAttachmentIcon
|
||||
{
|
||||
Graph,
|
||||
Paperclip,
|
||||
PushPin,
|
||||
Tag
|
||||
};
|
||||
|
||||
/// File attachment annotation contains reference to (embedded or external) file.
|
||||
/// So it is a link to specified file. Activating annotation enables user to view
|
||||
/// or store attached file in the filesystem.
|
||||
@ -1009,24 +1017,17 @@ class PDFFileAttachmentAnnotation : public PDFMarkupAnnotation
|
||||
public:
|
||||
inline explicit PDFFileAttachmentAnnotation() = default;
|
||||
|
||||
enum class Icon
|
||||
{
|
||||
Graph,
|
||||
Paperclip,
|
||||
PushPin,
|
||||
Tag
|
||||
};
|
||||
|
||||
virtual AnnotationType getType() const override { return AnnotationType::FileAttachment; }
|
||||
virtual void draw(AnnotationDrawParameters& parameters) const override;
|
||||
|
||||
const PDFFileSpecification& getFileSpecification() const { return m_fileSpecification; }
|
||||
Icon getIcon() const { return m_icon; }
|
||||
FileAttachmentIcon getIcon() const { return m_icon; }
|
||||
|
||||
private:
|
||||
friend static PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject object);
|
||||
|
||||
PDFFileSpecification m_fileSpecification;
|
||||
Icon m_icon = Icon::PushPin;
|
||||
FileAttachmentIcon m_icon = FileAttachmentIcon::PushPin;
|
||||
};
|
||||
|
||||
/// Sound annotation contains sound, which is played, when
|
||||
|
@ -219,6 +219,34 @@ void PDFObjectFactory::endDictionaryItem()
|
||||
std::get<PDFDictionary>(dictionaryItem.object).addEntry(qMove(topItem.itemName), qMove(std::get<PDFObject>(topItem.object)));
|
||||
}
|
||||
|
||||
PDFObjectFactory& PDFObjectFactory::operator<<(FileAttachmentIcon icon)
|
||||
{
|
||||
switch (icon)
|
||||
{
|
||||
case FileAttachmentIcon::Graph:
|
||||
*this << WrapName("Graph");
|
||||
break;
|
||||
|
||||
case FileAttachmentIcon::Paperclip:
|
||||
*this << WrapName("Paperclip");
|
||||
break;
|
||||
|
||||
case FileAttachmentIcon::PushPin:
|
||||
*this << WrapName("PushPin");
|
||||
break;
|
||||
|
||||
case FileAttachmentIcon::Tag:
|
||||
*this << WrapName("Tag");
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PDFObjectFactory& PDFObjectFactory::operator<<(Stamp stamp)
|
||||
{
|
||||
switch (stamp)
|
||||
@ -1310,6 +1338,56 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationCircle(PDFObjectReference
|
||||
}
|
||||
|
||||
|
||||
PDFObjectReference PDFDocumentBuilder::createAnnotationFileAttachment(PDFObjectReference page,
|
||||
QPointF position,
|
||||
PDFObjectReference fileSpecification,
|
||||
FileAttachmentIcon icon,
|
||||
QString title,
|
||||
QString description)
|
||||
{
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("Type");
|
||||
objectBuilder << WrapName("Annot");
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("Subtype");
|
||||
objectBuilder << WrapName("FileAttachment");
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("P");
|
||||
objectBuilder << page;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("Rect");
|
||||
objectBuilder << QRectF(position, QSizeF(32, 32));
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("FS");
|
||||
objectBuilder << fileSpecification;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("Name");
|
||||
objectBuilder << icon;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("T");
|
||||
objectBuilder << title;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("Contents");
|
||||
objectBuilder << description;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObjectReference annotationReference = addObject(objectBuilder.takeObject());
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("Annots");
|
||||
objectBuilder.beginArray();
|
||||
objectBuilder << annotationReference;
|
||||
objectBuilder.endArray();
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObject pageAnnots = objectBuilder.takeObject();
|
||||
appendTo(page, pageAnnots);
|
||||
updateAnnotationAppearanceStreams(annotationReference);
|
||||
return annotationReference;
|
||||
}
|
||||
|
||||
|
||||
PDFObjectReference PDFDocumentBuilder::createAnnotationFreeText(PDFObjectReference page,
|
||||
QRectF rectangle,
|
||||
QString title,
|
||||
@ -2638,6 +2716,55 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationText(PDFObjectReference p
|
||||
}
|
||||
|
||||
|
||||
PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectReference page,
|
||||
QRectF rectangle,
|
||||
QColor color)
|
||||
{
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("Type");
|
||||
objectBuilder << WrapName("Annot");
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("Subtype");
|
||||
objectBuilder << WrapName("Underline");
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("Rect");
|
||||
objectBuilder << rectangle;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("P");
|
||||
objectBuilder << page;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("CreationDate");
|
||||
objectBuilder << WrapCurrentDateTime();
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("C");
|
||||
objectBuilder << color;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("QuadPoints");
|
||||
objectBuilder.beginArray();
|
||||
objectBuilder << rectangle.bottomLeft();
|
||||
objectBuilder << rectangle.bottomRight();
|
||||
objectBuilder << rectangle.topLeft();
|
||||
objectBuilder << rectangle.topRight();
|
||||
objectBuilder.endArray();
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("Annots");
|
||||
objectBuilder.beginArray();
|
||||
objectBuilder << annotationObject;
|
||||
objectBuilder.endArray();
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObject pageAnnots = objectBuilder.takeObject();
|
||||
appendTo(page, pageAnnots);
|
||||
updateAnnotationAppearanceStreams(annotationObject);
|
||||
return annotationObject;
|
||||
}
|
||||
|
||||
|
||||
PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectReference page,
|
||||
QRectF rectangle,
|
||||
QColor color,
|
||||
@ -2702,55 +2829,6 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectRefere
|
||||
}
|
||||
|
||||
|
||||
PDFObjectReference PDFDocumentBuilder::createAnnotationUnderline(PDFObjectReference page,
|
||||
QRectF rectangle,
|
||||
QColor color)
|
||||
{
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("Type");
|
||||
objectBuilder << WrapName("Annot");
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("Subtype");
|
||||
objectBuilder << WrapName("Underline");
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("Rect");
|
||||
objectBuilder << rectangle;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("P");
|
||||
objectBuilder << page;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("CreationDate");
|
||||
objectBuilder << WrapCurrentDateTime();
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("C");
|
||||
objectBuilder << color;
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.beginDictionaryItem("QuadPoints");
|
||||
objectBuilder.beginArray();
|
||||
objectBuilder << rectangle.bottomLeft();
|
||||
objectBuilder << rectangle.bottomRight();
|
||||
objectBuilder << rectangle.topLeft();
|
||||
objectBuilder << rectangle.topRight();
|
||||
objectBuilder.endArray();
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
|
||||
objectBuilder.beginDictionary();
|
||||
objectBuilder.beginDictionaryItem("Annots");
|
||||
objectBuilder.beginArray();
|
||||
objectBuilder << annotationObject;
|
||||
objectBuilder.endArray();
|
||||
objectBuilder.endDictionaryItem();
|
||||
objectBuilder.endDictionary();
|
||||
PDFObject pageAnnots = objectBuilder.takeObject();
|
||||
appendTo(page, pageAnnots);
|
||||
updateAnnotationAppearanceStreams(annotationObject);
|
||||
return annotationObject;
|
||||
}
|
||||
|
||||
|
||||
PDFObjectReference PDFDocumentBuilder::createCatalog()
|
||||
{
|
||||
PDFObjectFactory objectBuilder;
|
||||
|
@ -112,6 +112,7 @@ public:
|
||||
PDFObjectFactory& operator<<(AnnotationBorderStyle style);
|
||||
PDFObjectFactory& operator<<(const PDFObject& object);
|
||||
PDFObjectFactory& operator<<(Stamp stamp);
|
||||
PDFObjectFactory& operator<<(FileAttachmentIcon icon);
|
||||
|
||||
/// Treat containers - write them as array
|
||||
template<typename Container, typename ValueType = decltype(*std::begin(std::declval<Container>()))>
|
||||
@ -331,6 +332,21 @@ public:
|
||||
QString contents);
|
||||
|
||||
|
||||
/// Creates a new file attachment annotation. This annotation needs file specification as parameter.
|
||||
/// \param page Page to which is annotation added
|
||||
/// \param position Position
|
||||
/// \param fileSpecification File specification
|
||||
/// \param icon Icon
|
||||
/// \param title Title
|
||||
/// \param description Description
|
||||
PDFObjectReference createAnnotationFileAttachment(PDFObjectReference page,
|
||||
QPointF position,
|
||||
PDFObjectReference fileSpecification,
|
||||
FileAttachmentIcon icon,
|
||||
QString title,
|
||||
QString description);
|
||||
|
||||
|
||||
/// Free text annotation displays text directly on a page. Text appears directly on the page, in the
|
||||
/// same way, as standard text in PDF document. Free text annotations are usually used to comment
|
||||
/// the document. Free text annotation can also have callout line, with, or without a knee.
|
||||
@ -742,6 +758,16 @@ public:
|
||||
bool open);
|
||||
|
||||
|
||||
/// Text markup annotation is used to underline text. It is a markup annotation, so it can contain
|
||||
/// window to be opened (and commented).
|
||||
/// \param page Page to which is annotation added
|
||||
/// \param rectangle Area in which is markup displayed
|
||||
/// \param color Color
|
||||
PDFObjectReference createAnnotationUnderline(PDFObjectReference page,
|
||||
QRectF rectangle,
|
||||
QColor color);
|
||||
|
||||
|
||||
/// Text markup annotation is used to underline text. It is a markup annotation, so it can contain
|
||||
/// window to be opened (and commented).
|
||||
/// \param page Page to which is annotation added
|
||||
@ -758,16 +784,6 @@ public:
|
||||
QString contents);
|
||||
|
||||
|
||||
/// Text markup annotation is used to underline text. It is a markup annotation, so it can contain
|
||||
/// window to be opened (and commented).
|
||||
/// \param page Page to which is annotation added
|
||||
/// \param rectangle Area in which is markup displayed
|
||||
/// \param color Color
|
||||
PDFObjectReference createAnnotationUnderline(PDFObjectReference page,
|
||||
QRectF rectangle,
|
||||
QColor color);
|
||||
|
||||
|
||||
/// Creates empty catalog. This function is used, when a new document is being created. Do not call
|
||||
/// this function manually.
|
||||
PDFObjectReference createCatalog();
|
||||
|
Reference in New Issue
Block a user