I confirm that patches 0001 to 0006 in the parent message are final.
I slightly changed 0007 and added another patch to fix the invalid font 
reference. I'm attaching these new two patches                                  
  
From 247c3b1c6a73716c922a02c6f07f3c6e091984b5 Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Fri, 23 Mar 2012 20:54:58 +0100
Subject: [PATCH 1/2] Basic AnnotFreeText rendering (hardcoded font, WinAnsi
 characters only)

This patch also moves layoutText and writeString from AnnotWidget to Annot
---
 poppler/Annot.cc |  137 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 poppler/Annot.h  |   11 +++--
 2 files changed, 142 insertions(+), 6 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index fec112b..8828525 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -2549,6 +2549,139 @@ void AnnotFreeText::setIntent(AnnotFreeTextIntent new_intent) {
   update ("IT", &obj1);
 }
 
+static GfxFont * createAnnotDrawFont(XRef * xref, Object *fontResDict)
+{
+  Ref dummyRef = { -1, -1 };
+
+  Object baseFontObj, subtypeObj, encodingObj;
+  baseFontObj.initName("Helvetica");
+  subtypeObj.initName("Type0");
+  encodingObj.initName("WinAnsiEncoding");
+
+  Object fontDictObj;
+  Dict *fontDict = new Dict(xref);
+  fontDict->decRef();
+  fontDict->add(copyString("BaseFont"), &baseFontObj);
+  fontDict->add(copyString("Subtype"), &subtypeObj);
+  fontDict->add(copyString("Encoding"), &encodingObj);
+  fontDictObj.initDict(fontDict);
+
+  Object fontsDictObj;
+  Dict *fontsDict = new Dict(xref);
+  fontsDict->decRef();
+  fontsDict->add(copyString("AnnotDrawFont"), &fontDictObj);
+  fontsDictObj.initDict(fontsDict);
+
+  Dict *dict = new Dict(xref);
+  dict->add(copyString("Font"), &fontsDictObj);
+
+  fontResDict->initDict(dict);
+  return GfxFont::makeFont(xref, "AnnotDrawFont", dummyRef, fontDict);
+}
+
+void AnnotFreeText::generateFreeTextAppearance()
+{
+  double ca = opacity;
+
+  appearBuf = new GooString ();
+  appearBuf->append ("q\n");
+  if (color) {
+    setColor(color, gTrue);
+  }
+
+  // Main segment length
+  const double width = rect->x2 - rect->x1;
+  const double height = rect->y2 - rect->y1;
+
+  // Parse text size from appearance string (TODO: other properties)
+  double fontsize = 0;
+  GooString * da = appearanceString;
+  if (da) {
+    GooList * daToks = new GooList();
+    int j, i = 0;
+    while (i < da->getLength()) {
+      while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
+        ++i;
+      }
+      if (i < da->getLength()) {
+        for (j = i + 1; j < da->getLength() && !Lexer::isSpace(da->getChar(j)); ++j) {
+        }
+        daToks->append(new GooString(da, i, j - i));
+        i = j;
+      }
+    }
+    for (i = 2; i < daToks->getLength(); ++i) {
+      if (!((GooString *)daToks->get(i))->cmp("Tf")) {
+        GooString * tok = (GooString *)daToks->get(i - 1);
+        fontsize = gatof(tok->getCString());
+        break;
+      }
+    }
+    deleteGooList(daToks, GooString);
+  }
+  if (fontsize <= 0) {
+    fontsize = 10; // Default value
+  }
+
+  // Draw box and setup clipping
+  appearBuf->appendf ("[] 0 d 1 w 0 G 0 0 {0:.2f} {1:.2f} re b\n", width, height);
+  appearBuf->appendf ("2 0 {0:.2f} {1:.2f} re W n\n", width-4, height);
+
+  // Set font state
+  appearBuf->appendf ("0 g BT 1 0 0 1 2 {0:.2f} Tm\n", height);
+  appearBuf->appendf ("{0:.2f} TL /AnnotDrawFont {0:.2f} Tf\n", fontsize);
+
+  Object fontResDict;
+  GfxFont *font = createAnnotDrawFont(xref, &fontResDict);
+
+  int i = 0;
+  while (i < contents->getLength()) {
+    GooString out;
+    layoutText(contents, &out, &i, font, NULL, 0, NULL, gFalse);
+    writeString(&out, appearBuf);
+    appearBuf->append("'\n");
+  }
+
+  font->decRefCnt();
+  appearBuf->append ("ET Q\n");
+
+  double bbox[4];
+  bbox[0] = bbox[1] = 0;
+  bbox[2] = rect->x2 - rect->x1;
+  bbox[3] = rect->y2 - rect->y1;
+
+  if (ca == 1) {
+    createForm(bbox, gFalse, &fontResDict, &appearance);
+  } else {
+    Object aStream, resDict;
+
+    createForm(bbox, gTrue, &fontResDict, &aStream);
+    delete appearBuf;
+
+    appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+    createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+    createForm(bbox, gFalse, &resDict, &appearance);
+  }
+  delete appearBuf;
+}
+
+void AnnotFreeText::draw(Gfx *gfx, GBool printing) {
+  Object obj;
+
+  if (!isVisible (printing))
+    return;
+
+  if (appearance.isNull()) {
+    generateFreeTextAppearance();
+  }
+
+  // draw the appearance stream
+  appearance.fetch(xref, &obj);
+  gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
+                 rect->x1, rect->y1, rect->x2, rect->y2);
+  obj.free();
+}
+
 //------------------------------------------------------------------------
 // AnnotLine
 //------------------------------------------------------------------------
@@ -3287,7 +3420,7 @@ void AnnotWidget::initialize(PDFDoc *docA, Dict *dict) {
 // TODO: Handle surrogate pairs in UTF-16.
 //       Should be able to generate output for any CID-keyed font.
 //       Doesn't handle vertical fonts--should it?
-void AnnotWidget::layoutText(GooString *text, GooString *outBuf, int *i,
+void Annot::layoutText(GooString *text, GooString *outBuf, int *i,
                              GfxFont *font, double *width, double widthLimit,
                              int *charCount, GBool noReencode)
 {
@@ -3481,7 +3614,7 @@ void AnnotWidget::layoutText(GooString *text, GooString *outBuf, int *i,
 
 // Copy the given string to appearBuf, adding parentheses around it and
 // escaping characters as appropriate.
-void AnnotWidget::writeString(GooString *str, GooString *appearBuf)
+void Annot::writeString(GooString *str, GooString *appearBuf)
 {
   char c;
   int i;
diff --git a/poppler/Annot.h b/poppler/Annot.h
index a01361f..5f0d4c4 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -563,6 +563,10 @@ protected:
   void drawCircle(double cx, double cy, double r, GBool fill);
   void drawCircleTopLeft(double cx, double cy, double r);
   void drawCircleBottomRight(double cx, double cy, double r);
+  void layoutText(GooString *text, GooString *outBuf, int *i, GfxFont *font,
+		  double *width, double widthLimit, int *charCount,
+		  GBool noReencode);
+  void writeString(GooString *str, GooString *appearBuf);
   void createForm(double *bbox, GBool transparencyGroup, Object *resDict, Object *aStream);
   void createResourcesDict(const char *formName, Object *formStream, const char *stateName,
 			   double opacity, const char *blendMode, Object *resDict);
@@ -837,6 +841,8 @@ public:
   AnnotFreeText(PDFDoc *docA, Dict *dict, Object *obj);
   ~AnnotFreeText();
 
+  virtual void draw(Gfx *gfx, GBool printing);
+
   void setAppearanceString(GooString *new_string);
   void setQuadding(AnnotFreeTextQuadding new_quadding);
   void setStyleString(GooString *new_string);
@@ -857,6 +863,7 @@ public:
 protected:
 
   void initialize(PDFDoc *docA, Dict *dict);
+  void generateFreeTextAppearance();
 
   // required
   GooString *appearanceString;      // DA
@@ -1242,10 +1249,6 @@ private:
 		GBool password=false);
   void drawListBox(FormFieldChoice *fieldChoice,
 		   GooString *da, GfxResources *resources, int quadding);
-  void layoutText(GooString *text, GooString *outBuf, int *i, GfxFont *font,
-		  double *width, double widthLimit, int *charCount,
-		  GBool noReencode);
-  void writeString(GooString *str, GooString *appearBuf);
 
   Form *form;
   FormField *field;                       // FormField object for this annotation
-- 
1.7.6.5

From feafea1ab6078aeb84c5b9759262f90d34ebb53c Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Thu, 29 Mar 2012 19:07:05 +0200
Subject: [PATCH 2/2] Avoid regenerating Annots when writing to PS + export
 poppler-generated appearance resource dict

1) With previous code each Annot object was reconstructed from the pdf object when
writing to PS, leading to the fact that writeDocSetup couldn't see the
consequences of Annot*::draw methods (i.e. new appearance).
This patch makes writeDocSetup use the same Annots object returned by
Page::getAnnots.

2) This patch also enables each Annot subtype to control the exported
resources. AnnotFreeText uses this new method to export font information.

3) Wrong and misleading comment fixed in Page.h: getAnnots does *not* give away
ownership, in fact the returned object is destroyed by ~Page.
---
 poppler/Annot.cc       |   28 ++++++++++++++++++++++++++++
 poppler/Annot.h        |    5 +++--
 poppler/FontInfo.cc    |   10 +++-------
 poppler/PSOutputDev.cc |   12 +++---------
 poppler/Page.h         |    2 +-
 5 files changed, 38 insertions(+), 19 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 8828525..3024f65 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -1552,6 +1552,25 @@ void Annot::createResourcesDict(const char *formName, Object *formStream,
   resDict->dictSet("XObject", &formDict);
 }
 
+Object *Annot::getAppearanceResDict(Object *dest) {
+  Object obj1, obj2;
+
+  dest->initNull(); // Default value
+
+  // Fetch appearance's resource dict (if any)
+  appearance.fetch(xref, &obj1);
+  if (obj1.isStream()) {
+    obj1.streamGetDict()->lookup("Resources", &obj2);
+    if (obj2.isDict()) {
+      obj2.copy(dest);
+    }
+    obj2.free();
+  }
+  obj1.free();
+
+  return dest;
+}
+
 GBool Annot::isVisible(GBool printing) {
   // check the flags
   if ((flags & flagHidden) ||
@@ -2682,6 +2701,15 @@ void AnnotFreeText::draw(Gfx *gfx, GBool printing) {
   obj.free();
 }
 
+// Before retrieving the res dict, regenerate the appearance stream if needed,
+// because AnnotFreeText::draw needs to store font info in the res dict
+Object *AnnotFreeText::getAppearanceResDict(Object *dest) {
+  if (appearance.isNull()) {
+    generateFreeTextAppearance();
+  }
+  return Annot::getAppearanceResDict(dest); // call base class
+}
+
 //------------------------------------------------------------------------
 // AnnotLine
 //------------------------------------------------------------------------
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 5f0d4c4..cfa2365 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -492,8 +492,8 @@ public:
   void decRefCnt();
 
   virtual void draw(Gfx *gfx, GBool printing);
-  // Get appearance object.
-  Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); }
+  // Get the resource dict of the appearance stream
+  virtual Object *getAppearanceResDict(Object *dest);
 
   GBool match(Ref *refA)
     { return ref.num == refA->num && ref.gen == refA->gen; }
@@ -842,6 +842,7 @@ public:
   ~AnnotFreeText();
 
   virtual void draw(Gfx *gfx, GBool printing);
+  virtual Object *getAppearanceResDict(Object *dest);
 
   void setAppearanceString(GooString *new_string);
   void setQuadding(AnnotFreeTextQuadding new_quadding);
diff --git a/poppler/FontInfo.cc b/poppler/FontInfo.cc
index 2a90c1e..e46f98d 100644
--- a/poppler/FontInfo.cc
+++ b/poppler/FontInfo.cc
@@ -53,7 +53,7 @@ GooList *FontInfoScanner::scan(int nPages) {
   Page *page;
   Dict *resDict;
   Annots *annots;
-  Object obj1, obj2;
+  Object obj1;
   int lastPage;
 
   if (currentPage > doc->getNumPages()) {
@@ -76,12 +76,8 @@ GooList *FontInfoScanner::scan(int nPages) {
     }
     annots = page->getAnnots();
     for (int i = 0; i < annots->getNumAnnots(); ++i) {
-      if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
-	obj1.streamGetDict()->lookup("Resources", &obj2);
-	if (obj2.isDict()) {
-	  scanFonts(obj2.getDict(), result);
-	}
-	obj2.free();
+      if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) {
+        scanFonts(obj1.getDict(), result);
       }
       obj1.free();
     }
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 54d1ea8..8d15836 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -1552,19 +1552,13 @@ void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
     if ((resDict = page->getResourceDict())) {
       setupResources(resDict);
     }
-    annots = new Annots(doc, page->getAnnots(&obj1));
-    obj1.free();
+    annots = page->getAnnots();
     for (i = 0; i < annots->getNumAnnots(); ++i) {
-      if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
-	obj1.streamGetDict()->lookup("Resources", &obj2);
-	if (obj2.isDict()) {
-	  setupResources(obj2.getDict());
-	}
-	obj2.free();
+      if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) {
+        setupResources(obj1.getDict());
       }
       obj1.free();
     }
-    delete annots;
   }
   if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) {
     if (acroForm->dictLookup("DR", &obj1)->isDict()) {
diff --git a/poppler/Page.h b/poppler/Page.h
index a1722a4..9dea41c 100644
--- a/poppler/Page.h
+++ b/poppler/Page.h
@@ -178,7 +178,7 @@ public:
   // Return a list of links.
   Links *getLinks();
 
-  // Return a list of annots. Ownership is transferred to the caller.
+  // Return a list of annots. It will be valid until the page is destroyed
   Annots *getAnnots();
 
   // Get contents.
-- 
1.7.6.5

_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to