Stamp annotation graphics

This commit is contained in:
Jakub Melka
2020-04-06 19:58:46 +02:00
parent cc11073d70
commit 33472428e9
7 changed files with 707 additions and 259 deletions

View File

@@ -384,24 +384,24 @@ PDFAnnotationPtr PDFAnnotation::parse(const PDFObjectStorage* storage, PDFObject
PDFStampAnnotation* annotation = new PDFStampAnnotation();
result.reset(annotation);
constexpr const std::array<std::pair<const char*, PDFStampAnnotation::Stamp>, 14> stamps = {
std::pair<const char*, PDFStampAnnotation::Stamp>{ "Approved", PDFStampAnnotation::Stamp::Approved },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "AsIs", PDFStampAnnotation::Stamp::AsIs },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "Confidential", PDFStampAnnotation::Stamp::Confidential },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "Departmental", PDFStampAnnotation::Stamp::Departmental },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "Draft", PDFStampAnnotation::Stamp::Draft },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "Experimental", PDFStampAnnotation::Stamp::Experimental },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "Expired", PDFStampAnnotation::Stamp::Expired },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "Final", PDFStampAnnotation::Stamp::Final },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "ForComment", PDFStampAnnotation::Stamp::ForComment },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "ForPublicRelease", PDFStampAnnotation::Stamp::ForPublicRelease },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "NotApproved", PDFStampAnnotation::Stamp::NotApproved },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "NotForPublicRelease", PDFStampAnnotation::Stamp::NotForPublicRelease },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "Sold", PDFStampAnnotation::Stamp::Sold },
std::pair<const char*, PDFStampAnnotation::Stamp>{ "TopSecret", PDFStampAnnotation::Stamp::TopSecret }
constexpr const std::array<std::pair<const char*, Stamp>, 14> stamps = {
std::pair<const char*, Stamp>{ "Approved", Stamp::Approved },
std::pair<const char*, Stamp>{ "AsIs", Stamp::AsIs },
std::pair<const char*, Stamp>{ "Confidential", Stamp::Confidential },
std::pair<const char*, Stamp>{ "Departmental", Stamp::Departmental },
std::pair<const char*, Stamp>{ "Draft", Stamp::Draft },
std::pair<const char*, Stamp>{ "Experimental", Stamp::Experimental },
std::pair<const char*, Stamp>{ "Expired", Stamp::Expired },
std::pair<const char*, Stamp>{ "Final", Stamp::Final },
std::pair<const char*, Stamp>{ "ForComment", Stamp::ForComment },
std::pair<const char*, Stamp>{ "ForPublicRelease", Stamp::ForPublicRelease },
std::pair<const char*, Stamp>{ "NotApproved", Stamp::NotApproved },
std::pair<const char*, Stamp>{ "NotForPublicRelease", Stamp::NotForPublicRelease },
std::pair<const char*, Stamp>{ "Sold", Stamp::Sold },
std::pair<const char*, Stamp>{ "TopSecret", Stamp::TopSecret }
};
annotation->m_stamp = loader.readEnumByName(dictionary->get("Name"), stamps.begin(), stamps.end(), PDFStampAnnotation::Stamp::Draft);
annotation->m_stamp = loader.readEnumByName(dictionary->get("Name"), stamps.begin(), stamps.end(), Stamp::Draft);
}
else if (subtype == "Ink")
{
@@ -2011,4 +2011,114 @@ void PDFInkAnnotation::draw(AnnotationDrawParameters& parameters) const
parameters.boundingRectangle.adjust(-penWidth, -penWidth, penWidth, penWidth);
}
void PDFStampAnnotation::draw(AnnotationDrawParameters& parameters) const
{
QPainter& painter = *parameters.painter;
QString text;
QColor color(Qt::red);
switch (m_stamp)
{
case Stamp::Approved:
text = PDFTranslationContext::tr("APPROVED");
color = Qt::green;
break;
case Stamp::AsIs:
text = PDFTranslationContext::tr("AS IS");
break;
case Stamp::Confidential:
text = PDFTranslationContext::tr("CONFIDENTIAL");
break;
case Stamp::Departmental:
text = PDFTranslationContext::tr("DEPARTMENTAL");
color = Qt::blue;
break;
case Stamp::Draft:
text = PDFTranslationContext::tr("DRAFT");
break;
case Stamp::Experimental:
text = PDFTranslationContext::tr("EXPERIMENTAL");
color = Qt::blue;
break;
case Stamp::Expired:
text = PDFTranslationContext::tr("EXPIRED");
break;
case Stamp::Final:
text = PDFTranslationContext::tr("FINAL");
break;
case Stamp::ForComment:
text = PDFTranslationContext::tr("FOR COMMENT");
color = Qt::green;
break;
case Stamp::ForPublicRelease:
text = PDFTranslationContext::tr("FOR PUBLIC RELEASE");
color = Qt::green;
break;
case Stamp::NotApproved:
text = PDFTranslationContext::tr("NOT APPROVED");
break;
case Stamp::NotForPublicRelease:
text = PDFTranslationContext::tr("NOT FOR PUBLIC RELEASE");
break;
case Stamp::Sold:
text = PDFTranslationContext::tr("SOLD");
color = Qt::blue;
break;
case Stamp::TopSecret:
text = PDFTranslationContext::tr("TOP SECRET");
break;
default:
Q_ASSERT(false);
break;
}
const PDFReal textHeight = 16;
QFont font("Courier New");
font.setBold(true);
font.setPixelSize(textHeight);
QFontMetricsF fontMetrics(font, painter.device());
const qreal textWidth = fontMetrics.width(text);
const qreal rectangleWidth = textWidth + 10;
const qreal rectangleHeight = textHeight * 1.2;
const qreal penWidth = 2.0;
QRectF rectangle = getRectangle();
rectangle.setSize(QSizeF(rectangleWidth, rectangleHeight));
QPen pen(color);
pen.setWidthF(penWidth);
painter.setPen(pen);
painter.setBrush(Qt::NoBrush);
painter.drawRoundedRect(rectangle, 5, 5, Qt::AbsoluteSize);
// Draw text
QPainterPath textPath;
textPath.addText(0, 0, font, text);
textPath = QMatrix(1, 0, 0, -1, 0, 0).map(textPath);
QPointF center = textPath.boundingRect().center();
textPath.translate(rectangle.center() - center);
painter.fillPath(textPath, QBrush(color, Qt::SolidPattern));
parameters.boundingRectangle = rectangle;
parameters.boundingRectangle.adjust(-penWidth, -penWidth, penWidth, penWidth);
}
} // namespace pdf

View File

@@ -930,6 +930,24 @@ private:
Symbol m_symbol = Symbol::None;
};
enum class Stamp
{
Approved,
AsIs,
Confidential,
Departmental,
Draft,
Experimental,
Expired,
Final,
ForComment,
ForPublicRelease,
NotApproved,
NotForPublicRelease,
Sold,
TopSecret
};
/// Annotation for stamps. Displays text or graphics intended to look
/// as if they were stamped on the paper.
class PDFStampAnnotation : public PDFMarkupAnnotation
@@ -937,25 +955,8 @@ class PDFStampAnnotation : public PDFMarkupAnnotation
public:
inline explicit PDFStampAnnotation() = default;
enum class Stamp
{
Approved,
AsIs,
Confidential,
Departmental,
Draft,
Experimental,
Expired,
Final,
ForComment,
ForPublicRelease,
NotApproved,
NotForPublicRelease,
Sold,
TopSecret
};
virtual AnnotationType getType() const override { return AnnotationType::Stamp; }
virtual void draw(AnnotationDrawParameters& parameters) const override;
Stamp getStamp() const { return m_stamp; }

View File

@@ -219,6 +219,74 @@ void PDFObjectFactory::endDictionaryItem()
std::get<PDFDictionary>(dictionaryItem.object).addEntry(qMove(topItem.itemName), qMove(std::get<PDFObject>(topItem.object)));
}
PDFObjectFactory& PDFObjectFactory::operator<<(Stamp stamp)
{
switch (stamp)
{
case Stamp::Approved:
*this << WrapName("Approved");
break;
case Stamp::AsIs:
*this << WrapName("AsIs");
break;
case Stamp::Confidential:
*this << WrapName("Confidential");
break;
case Stamp::Departmental:
*this << WrapName("Departmental");
break;
case Stamp::Draft:
*this << WrapName("Draft");
break;
case Stamp::Experimental:
*this << WrapName("Experimental");
break;
case Stamp::Expired:
*this << WrapName("Expired");
break;
case Stamp::Final:
*this << WrapName("Final");
break;
case Stamp::ForComment:
*this << WrapName("ForComment");
break;
case Stamp::ForPublicRelease:
*this << WrapName("ForPublicRelease");
break;
case Stamp::NotApproved:
*this << WrapName("NotApproved");
break;
case Stamp::NotForPublicRelease:
*this << WrapName("NotForPublicRelease");
break;
case Stamp::Sold:
*this << WrapName("Sold");
break;
case Stamp::TopSecret:
*this << WrapName("TopSecret");
break;
default:
Q_ASSERT(false);
break;
}
return *this;
}
PDFObjectFactory& PDFObjectFactory::operator<<(const PDFObject& object)
{
addObject(object);
@@ -2201,8 +2269,6 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquare(PDFObjectReference
objectBuilder.endDictionaryItem();
objectBuilder.endDictionary();
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
PDFObjectReference popupAnnotation = createAnnotationPopup(page, annotationObject, getPopupWindowRect(rectangle), false);
objectBuilder.beginDictionary();
objectBuilder.beginDictionaryItem("Annots");
objectBuilder.beginArray();
@@ -2330,6 +2396,62 @@ PDFObjectReference PDFDocumentBuilder::createAnnotationSquiggly(PDFObjectReferen
}
PDFObjectReference PDFDocumentBuilder::createAnnotationStamp(PDFObjectReference page,
QRectF rectangle,
Stamp stampType,
QString title,
QString subject,
QString contents)
{
PDFObjectFactory objectBuilder;
objectBuilder.beginDictionary();
objectBuilder.beginDictionaryItem("Type");
objectBuilder << WrapName("Annot");
objectBuilder.endDictionaryItem();
objectBuilder.beginDictionaryItem("Subtype");
objectBuilder << WrapName("Stamp");
objectBuilder.endDictionaryItem();
objectBuilder.beginDictionaryItem("Rect");
objectBuilder << rectangle;
objectBuilder.endDictionaryItem();
objectBuilder.beginDictionaryItem("P");
objectBuilder << page;
objectBuilder.endDictionaryItem();
objectBuilder.beginDictionaryItem("Name");
objectBuilder << stampType;
objectBuilder.endDictionaryItem();
objectBuilder.beginDictionaryItem("M");
objectBuilder << WrapCurrentDateTime();
objectBuilder.endDictionaryItem();
objectBuilder.beginDictionaryItem("CreationDate");
objectBuilder << WrapCurrentDateTime();
objectBuilder.endDictionaryItem();
objectBuilder.beginDictionaryItem("T");
objectBuilder << title;
objectBuilder.endDictionaryItem();
objectBuilder.beginDictionaryItem("Contents");
objectBuilder << contents;
objectBuilder.endDictionaryItem();
objectBuilder.beginDictionaryItem("Subj");
objectBuilder << subject;
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::createAnnotationStrikeout(PDFObjectReference page,
QRectF rectangle,
QColor color,
@@ -2516,55 +2638,6 @@ 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,
@@ -2629,6 +2702,55 @@ 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;

View File

@@ -111,6 +111,7 @@ public:
PDFObjectFactory& operator<<(const QDateTime& dateTime);
PDFObjectFactory& operator<<(AnnotationBorderStyle style);
PDFObjectFactory& operator<<(const PDFObject& object);
PDFObjectFactory& operator<<(Stamp stamp);
/// Treat containers - write them as array
template<typename Container, typename ValueType = decltype(*std::begin(std::declval<Container>()))>
@@ -679,6 +680,21 @@ public:
QColor color);
/// Stamp annotation
/// \param page Page to which is annotation added
/// \param rectangle Stamp area
/// \param stampType Stamp type
/// \param title Title
/// \param subject Subject
/// \param contents Contents
PDFObjectReference createAnnotationStamp(PDFObjectReference page,
QRectF rectangle,
Stamp stampType,
QString title,
QString subject,
QString contents);
/// Text markup annotation is used to strikeout text. It is a markup annotation, so it can contain
/// window to be opened (and commented).
/// \param page Page to which is annotation added
@@ -726,16 +742,6 @@ 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
@@ -752,6 +758,16 @@ 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();