From 8865f9d68f7ba1b52f3fbbcf42000bfadc8eebd4 Mon Sep 17 00:00:00 2001 From: Dileep Sankhla Date: Sat, 4 Aug 2018 15:48:45 +0530 Subject: [PATCH] Add FreeText font color in Poppler Add new public methods TextAnnotation::textColor and TextAnnotation::setTextColor, to adjust the text color of FreeText annotations. We also shift the responsibility for createing and parsing DA strings out of Qt5 frontend and into poppler core. Co-authored-by: Tobias Deiminger --- poppler/Annot.cc | 77 +++++++++++++++++---- poppler/Annot.h | 30 +++++++-- qt5/src/poppler-annotation-helper.h | 2 +- qt5/src/poppler-annotation.cc | 100 ++++++++++++++++------------ qt5/src/poppler-annotation.h | 2 + 5 files changed, 153 insertions(+), 58 deletions(-) diff --git a/poppler/Annot.cc b/poppler/Annot.cc index d37824c1..73536861 100644 --- a/poppler/Annot.cc +++ b/poppler/Annot.cc @@ -791,6 +791,26 @@ Object AnnotColor::writeToObject(XRef *xref) const { } } +//------------------------------------------------------------------------ +// DefaultAppearance +//------------------------------------------------------------------------ + +DefaultAppearance::DefaultAppearance() + : fontPtSize(0), fontColor(nullptr) { + DefaultAppearance::fontTag = new GooString(); +} + +DefaultAppearance::DefaultAppearance(const GooString &fontTag, int fontPtSize, AnnotColor *fontColor) + : fontPtSize(fontPtSize), fontColor(fontColor) { + DefaultAppearance::fontTag = fontTag.copy(); +} + +DefaultAppearance::~DefaultAppearance() { + delete fontTag; + if (fontColor) { + delete fontColor; + } +} //------------------------------------------------------------------------ // AnnotIconFit //------------------------------------------------------------------------ @@ -2593,12 +2613,13 @@ void AnnotLink::draw(Gfx *gfx, GBool printing) { //------------------------------------------------------------------------ // AnnotFreeText //------------------------------------------------------------------------ -AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da) : +AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, const DefaultAppearance &da) : AnnotMarkup(docA, rect) { type = typeFreeText; + GooString *daStr = constructAppearanceString(da.getFontTag(), da.getFontPtSize(), da.getFontColor()); annotObj.dictSet ("Subtype", Object(objName, "FreeText")); - annotObj.dictSet("DA", Object(da->copy())); + annotObj.dictSet("DA", Object(daStr)); initialize (docA, annotObj.getDict()); } @@ -2726,14 +2747,10 @@ void AnnotFreeText::setContents(GooString *new_content) { invalidateAppearance(); } -void AnnotFreeText::setAppearanceString(GooString *new_string) { +void AnnotFreeText::setAppearanceString(const DefaultAppearance &da) { delete appearanceString; - if (new_string) { - appearanceString = new GooString(new_string); - } else { - appearanceString = new GooString(); - } + appearanceString = constructAppearanceString(da.getFontTag(), da.getFontPtSize(), da.getFontColor()); update ("DA", Object(appearanceString->copy())); invalidateAppearance(); @@ -2805,7 +2822,17 @@ void AnnotFreeText::setIntent(AnnotFreeTextIntent new_intent) { update ("IT", Object(objName, intentName)); } -static GfxFont * createAnnotDrawFont(XRef * xref, Dict *fontResDict) +DefaultAppearance AnnotFreeText::getAppearanceString() const { + double fontSize; + AnnotColor *fontColor; + GooString *fontTag; + parseAppearanceString(appearanceString, fontSize, fontColor, fontTag); + DefaultAppearance da(*fontTag, fontSize, fontColor); + delete fontTag; + return da; +} + +static GfxFont *createAnnotDrawFont(XRef * xref, Dict *fontResDict) { const Ref dummyRef = { -1, -1 }; @@ -2822,16 +2849,41 @@ static GfxFont * createAnnotDrawFont(XRef * xref, Dict *fontResDict) return GfxFont::makeFont(xref, "AnnotDrawFont", dummyRef, fontDict); } -void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor) { +GooString *AnnotFreeText::constructAppearanceString(const GooString &fontTag, double fontSize, const AnnotColor *fontColor) { + const double *colorData = fontColor->getValues(); + GooString * cstr = nullptr; + switch(fontColor->getSpace()) + { + case AnnotColor::AnnotColorSpace::colorTransparent: // =0 + cstr = new GooString(); + break; + case AnnotColor::AnnotColorSpace::colorGray: //=1 + cstr = GooString::format("{0:.2f} g ", colorData[0]); + break; + case AnnotColor::AnnotColorSpace::colorRGB: //=3 + cstr = GooString::format("{0:.2f} {1:.2f} {2:.2f} rg ", colorData[0], colorData[1], colorData[2]); + break; + case AnnotColor::AnnotColorSpace::colorCMYK: //=4 + cstr = GooString::format("{0:.2f} {1:.2f} {2:.2f} {3:.2f} k ", colorData[0], colorData[1], colorData[2], colorData[3]); + break; + } + const GooString * str = GooString::format("/{0:s} {1:.2f} Tf", &fontTag, fontSize); + return cstr->append( str ); +} + +void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor, GooString* &fontTag) { fontsize = -1; fontcolor = nullptr; + fontTag = nullptr; if (da) { GooList * daToks = new GooList(); int i = FormFieldText::tokenizeDA(da, daToks, "Tf"); if (i >= 1) { fontsize = gatof(( (GooString *)daToks->get(i-1) )->getCString()); - // TODO: Font name + } + if (i >= 2) { + fontTag = new GooString(( (GooString *)daToks->get(i-2) )->getCString()); } // Scan backwards: we are looking for the last set value for (i = daToks->getLength()-1; i >= 0; --i) { @@ -2872,7 +2924,8 @@ void AnnotFreeText::generateFreeTextAppearance() // Parse some properties from the appearance string double fontsize; AnnotColor *fontcolor; - parseAppearanceString(appearanceString, fontsize, fontcolor); + GooString *fontTag; + parseAppearanceString(appearanceString, fontsize, fontcolor, fontTag); // Default values if (fontsize <= 0) fontsize = 10; diff --git a/poppler/Annot.h b/poppler/Annot.h index 83c10b39..b8c82bcf 100644 --- a/poppler/Annot.h +++ b/poppler/Annot.h @@ -347,6 +347,27 @@ private: int length; }; +//------------------------------------------------------------------------ +// DefaultAppearance +//------------------------------------------------------------------------ + +class DefaultAppearance { +public: + + DefaultAppearance(); + DefaultAppearance(const GooString &fontTag, int fontPtSize, AnnotColor *fontColor = nullptr); + const GooString &getFontTag() const { return *fontTag; } + int getFontPtSize() const { return fontPtSize; } + const AnnotColor *getFontColor() const { return fontColor; } + ~DefaultAppearance(); + +private: + + GooString *fontTag; + int fontPtSize; + AnnotColor *fontColor; +}; + //------------------------------------------------------------------------ // AnnotIconFit //------------------------------------------------------------------------ @@ -969,7 +990,7 @@ public: intentFreeTextTypeWriter // FreeTextTypeWriter }; - AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da); + AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, const DefaultAppearance &da); AnnotFreeText(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotFreeText(); @@ -977,14 +998,14 @@ public: Object getAppearanceResDict() override; void setContents(GooString *new_content) override; - void setAppearanceString(GooString *new_string); + void setAppearanceString(const DefaultAppearance &da); void setQuadding(AnnotFreeTextQuadding new_quadding); void setStyleString(GooString *new_string); void setCalloutLine(AnnotCalloutLine *line); void setIntent(AnnotFreeTextIntent new_intent); // getters - const GooString *getAppearanceString() const { return appearanceString; } + DefaultAppearance getAppearanceString() const; AnnotFreeTextQuadding getQuadding() const { return quadding; } // return rc const GooString *getStyleString() const { return styleString; } @@ -997,7 +1018,8 @@ public: protected: void initialize(PDFDoc *docA, Dict *dict); - static void parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor); + static GooString *constructAppearanceString(const GooString &fontTag, double fontSize, const AnnotColor *fontColor); + static void parseAppearanceString(GooString *da, double &fontSize, AnnotColor* &fontColor, GooString* &fontTag); void generateFreeTextAppearance(); // required diff --git a/qt5/src/poppler-annotation-helper.h b/qt5/src/poppler-annotation-helper.h index 3150569c..669b98ee 100644 --- a/qt5/src/poppler-annotation-helper.h +++ b/qt5/src/poppler-annotation-helper.h @@ -175,7 +175,7 @@ void XPDFReader::invTransform( double * M, const QPointF &p, double &x, double & y = invM[1] * xt + invM[3] * yt; } -QColor convertAnnotColor( AnnotColor *color ); +QColor convertAnnotColor( const AnnotColor *color ); AnnotColor* convertQColor( const QColor &color ); } diff --git a/qt5/src/poppler-annotation.cc b/qt5/src/poppler-annotation.cc index 5550efcd..0b14ad69 100644 --- a/qt5/src/poppler-annotation.cc +++ b/qt5/src/poppler-annotation.cc @@ -1816,17 +1816,17 @@ class TextAnnotationPrivate : public AnnotationPrivate TextAnnotationPrivate(); Annotation * makeAlias() override; Annot* createNativeAnnot(::Page *destPage, DocumentData *doc) override; + void setDefaultAppearanceToNative(); + DefaultAppearance getDefaultAppearanceFromNative() const; // data fields TextAnnotation::TextType textType; QString textIcon; QFont textFont; + QColor textColor; int inplaceAlign; // 0:left, 1:center, 2:right QVector inplaceCallout; TextAnnotation::InplaceIntent inplaceIntent; - - // Helper - static GooString * toAppearanceString(const QFont &font); }; TextAnnotationPrivate::TextAnnotationPrivate() @@ -1841,13 +1841,6 @@ Annotation * TextAnnotationPrivate::makeAlias() return new TextAnnotation(*this); } -GooString * TextAnnotationPrivate::toAppearanceString(const QFont &font) -{ - GooString * s = GooString::format("/Invalid_font {0:d} Tf", font.pointSize()); - // TODO: Font family, style (bold, italic, ...) and pointSize as float - return s; -} - Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc) { // Setters are defined in the public class @@ -1859,15 +1852,11 @@ Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData * // Set pdfAnnot PDFRectangle rect = boundaryToPdfRectangle(boundary, flags); - if (textType == TextAnnotation::Linked) - { - pdfAnnot = new AnnotText(destPage->getDoc(), &rect); - } - else - { - GooString * da = toAppearanceString(textFont); - pdfAnnot = new AnnotFreeText(destPage->getDoc(), &rect, da); - delete da; + if (textType == TextAnnotation::Linked) { + pdfAnnot = new AnnotText(destPage->getDoc(), &rect); + } else { + DefaultAppearance da(GooString("Invalid_font"), textFont.pointSize(), convertQColor(textColor)); + pdfAnnot = new AnnotFreeText(destPage->getDoc(), &rect, da); } // Set properties @@ -1884,6 +1873,26 @@ Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData * return pdfAnnot; } +void TextAnnotationPrivate::setDefaultAppearanceToNative() +{ + if (pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText) { + AnnotFreeText * ftextann = static_cast(pdfAnnot); + AnnotColor *color = convertQColor(textColor); + DefaultAppearance da(GooString("Invalid_font"), textFont.pointSize(), color); + ftextann->setAppearanceString(da); + } +} + +DefaultAppearance TextAnnotationPrivate::getDefaultAppearanceFromNative() const +{ + if (pdfAnnot && pdfAnnot->getType() == Annot::typeFreeText) { + AnnotFreeText * ftextann = static_cast(pdfAnnot); + return ftextann->getAppearanceString(); + } else { + return DefaultAppearance(); + } +} + TextAnnotation::TextAnnotation( TextAnnotation::TextType type ) : Annotation( *new TextAnnotationPrivate() ) { @@ -1916,6 +1925,12 @@ TextAnnotation::TextAnnotation( const QDomNode & node ) QFont font; font.fromString( e.attribute( QStringLiteral("font") ) ); setTextFont(font); + if ( e.hasAttribute( QStringLiteral("fontColor") ) ) + { + QColor color; + color = QColor(e.attribute( QStringLiteral("fontColor") ) ); + setTextColor(color); + } } if ( e.hasAttribute( QStringLiteral("align") ) ) setInplaceAlign(e.attribute( QStringLiteral("align") ).toInt()); @@ -1975,6 +1990,7 @@ void TextAnnotation::store( QDomNode & node, QDomDocument & document ) const textElement.setAttribute( QStringLiteral("intent"), (int)inplaceIntent() ); textElement.setAttribute( QStringLiteral("font"), textFont().toString() ); + textElement.setAttribute( QStringLiteral("fontColor"), textColor().name() ); // Sub-Node-1 - escapedText if ( !contents().isEmpty() ) @@ -2074,17 +2090,8 @@ QFont TextAnnotation::textFont() const if (d->pdfAnnot->getType() == Annot::typeFreeText) { - const AnnotFreeText * ftextann = static_cast(d->pdfAnnot); - const GooString * da = ftextann->getAppearanceString(); - if (da) - { - // At the moment, only font size is parsed - QString style = QString::fromLatin1( da->getCString() ); - QRegExp rx(QStringLiteral("(\\d+)(\\.\\d*)? Tf")); - if (rx.indexIn(style) != -1) - font.setPointSize( rx.cap(1).toInt() ); - // TODO: Other properties - } + DefaultAppearance da = d->getDefaultAppearanceFromNative(); + font.setPointSize( da.getFontPtSize() ); } return font; @@ -2093,20 +2100,31 @@ QFont TextAnnotation::textFont() const void TextAnnotation::setTextFont( const QFont &font ) { Q_D( TextAnnotation ); + d->textFont = font; + d->textColor = Qt::black; + + d->setDefaultAppearanceToNative(); +} + +QColor TextAnnotation::textColor() const +{ + Q_D( const TextAnnotation ); if (!d->pdfAnnot) - { - d->textFont = font; - return; - } + return d->textColor; - if (d->pdfAnnot->getType() != Annot::typeFreeText) - return; + QColor color; + DefaultAppearance da = d->getDefaultAppearanceFromNative(); + color = convertAnnotColor(da.getFontColor()); + return color; +} - AnnotFreeText * ftextann = static_cast(d->pdfAnnot); - GooString * da = TextAnnotationPrivate::toAppearanceString(font); - ftextann->setAppearanceString(da); - delete da; +void TextAnnotation::setTextColor( const QColor &color ) +{ + Q_D( TextAnnotation ); + d->textColor = color; + + d->setDefaultAppearanceToNative(); } int TextAnnotation::inplaceAlign() const @@ -5055,7 +5073,7 @@ RichMediaAnnotation::Content* RichMediaAnnotation::content() const //BEGIN utility annotation functions -QColor convertAnnotColor( AnnotColor *color ) +QColor convertAnnotColor( const AnnotColor *color ) { if ( !color ) return QColor(); diff --git a/qt5/src/poppler-annotation.h b/qt5/src/poppler-annotation.h index a70cbe4f..63bf79ae 100644 --- a/qt5/src/poppler-annotation.h +++ b/qt5/src/poppler-annotation.h @@ -484,6 +484,8 @@ class POPPLER_QT5_EXPORT TextAnnotation : public Annotation QFont textFont() const; void setTextFont( const QFont &font ); + QColor textColor() const; + void setTextColor( const QColor &color ); int inplaceAlign() const; void setInplaceAlign( int align ); -- 2.17.1