Hi: Here goes another patch that does parse a little more annotation data and does clean a little appearance parsing, but it still needs more work (appearance was something i didn't understand correctly (XObject streams)).
I'm sending again yesterdays PDFRectangle patch, there was a line missing (PDFRectangle should be deleted on the Annot destructor). Bye,
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 2e09848..40ff968 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -26,6 +26,7 @@
#include "CharCodeToUnicode.h"
#include "Form.h"
#include "Error.h"
+#include "Page.h"
#define annotFlagHidden 0x0002
#define annotFlagPrint 0x0004
@@ -104,7 +105,6 @@ void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog
double *borderDash;
int borderDashLength;
double borderR, borderG, borderB;
- double t;
ok = gTrue;
xref = xrefA;
@@ -129,34 +129,37 @@ void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog
obj1.free();
//----- parse the rectangle
+ rect = new PDFRectangle();
+ if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) {
+ Object obj2;
+ (obj1.arrayGet(0, &obj2)->isNum() ? rect->x1 = obj2.getNum() : rect->x1 = 0);
+ obj2.free();
+ (obj1.arrayGet(1, &obj2)->isNum() ? rect->y1 = obj2.getNum() : rect->y1 = 0);
+ obj2.free();
+ (obj1.arrayGet(2, &obj2)->isNum() ? rect->x2 = obj2.getNum() : rect->x2 = 1);
+ obj2.free();
+ (obj1.arrayGet(3, &obj2)->isNum() ? rect->y2 = obj2.getNum() : rect->y2 = 1);
+ obj2.free();
- if (dict->lookup("Rect", &obj1)->isArray() &&
- obj1.arrayGetLength() == 4) {
- readArrayNum(&obj1, 0, &xMin);
- readArrayNum(&obj1, 1, &yMin);
- readArrayNum(&obj1, 2, &xMax);
- readArrayNum(&obj1, 3, &yMax);
- if (ok) {
- if (xMin > xMax) {
- t = xMin; xMin = xMax; xMax = t;
- }
- if (yMin > yMax) {
- t = yMin; yMin = yMax; yMax = t;
- }
- } else {
- xMin = yMin = 0;
- xMax = yMax = 1;
- error(-1, "Bad bounding box for annotation");
- ok = gFalse;
+ if (rect->x1 > rect->x2) {
+ double t = rect->x1;
+ rect->x1 = rect->x2;
+ rect->x2 = t;
+ }
+
+ if (rect->y1 > rect->y2) {
+ double t = rect->y1;
+ rect->y1 = rect->y2;
+ rect->y2 = t;
}
} else {
- xMin = yMin = 0;
- xMax = yMax = 1;
+ rect->x1 = rect->y1 = 0;
+ rect->x2 = rect->y2 = 1;
error(-1, "Bad bounding box for annotation");
ok = gFalse;
}
obj1.free();
-
+
//----- get the flags
if (dict->lookup("F", &obj1)->isInt()) {
flags = obj1.getInt();
@@ -320,6 +323,14 @@ void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog
borderR, borderG, borderB);
}
+double Annot::getXMin() {
+ return rect->x1;
+}
+
+double Annot::getYMin() {
+ return rect->y1;
+}
+
void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
Object valueObject;
@@ -334,6 +345,8 @@ void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
}
Annot::~Annot() {
+ delete rect;
+
if (type) {
delete type;
}
@@ -392,7 +405,7 @@ void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
obj1.arrayGetLength() > 0) {
setColor(obj1.getArray(), gTrue, 0);
appearBuf->appendf("0 0 {0:.2f} {1:.2f} re f\n",
- xMax - xMin, yMax - yMin);
+ rect->x2 - rect->x1, rect->y2 - rect->y1);
}
obj1.free();
}
@@ -417,8 +430,8 @@ void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
mkDict->lookup("BG", &obj1);
}
if (obj1.isArray() && obj1.arrayGetLength() > 0) {
- dx = xMax - xMin;
- dy = yMax - yMin;
+ dx = rect->x2 - rect->x1;
+ dy = rect->y2 - rect->y1;
// radio buttons with no caption have a round border
hasCaption = mkDict->lookup("CA", &obj2)->isString();
@@ -554,8 +567,8 @@ void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
if (mkDict) {
if (mkDict->lookup("BC", &obj3)->isArray() &&
obj3.arrayGetLength() > 0) {
- dx = xMax - xMin;
- dy = yMax - yMin;
+ dx = rect->x2 - rect->x1;
+ dy = rect->y2 - rect->y1;
setColor(obj3.getArray(), gTrue, 0);
drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy),
gTrue);
@@ -704,8 +717,8 @@ void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
obj1.initArray(xref);
obj1.arrayAdd(obj2.initReal(0));
obj1.arrayAdd(obj2.initReal(0));
- obj1.arrayAdd(obj2.initReal(xMax - xMin));
- obj1.arrayAdd(obj2.initReal(yMax - yMin));
+ obj1.arrayAdd(obj2.initReal(rect->x2 - rect->x1));
+ obj1.arrayAdd(obj2.initReal(rect->y2 - rect->y1));
appearDict.dictAdd(copyString("BBox"), &obj1);
// set the resource dictionary
@@ -911,12 +924,12 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
if (multiline) {
// note: the comb flag is ignored in multiline mode
- wMax = xMax - xMin - 2 * border - 4;
+ wMax = rect->x2 - rect->x1 - 2 * border - 4;
// compute font autosize
if (fontSize == 0) {
for (fontSize = 20; fontSize > 1; --fontSize) {
- y = yMax - yMin;
+ y = rect->y2 - rect->y1;
w2 = 0;
i = 0;
while (i < text->getLength()) {
@@ -942,7 +955,7 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
// starting y coordinate
// (note: each line of text starts with a Td operator that moves
// down a line)
- y = yMax - yMin;
+ y = rect->y2 - rect->y1;
// set the font matrix
if (tmPos >= 0) {
@@ -980,10 +993,10 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
x = border + 2;
break;
case fieldQuadCenter:
- x = (xMax - xMin - w) / 2;
+ x = (rect->x2 - rect->x1 - w) / 2;
break;
case fieldQuadRight:
- x = xMax - xMin - border - 2 - w;
+ x = rect->x2 - rect->x1 - border - 2 - w;
break;
}
@@ -1005,11 +1018,11 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
// comb formatting
if (comb > 0) {
// compute comb spacing
- w = (xMax - xMin - 2 * border) / comb;
+ w = (rect->x2 - rect->x1 - 2 * border) / comb;
// compute font autosize
if (fontSize == 0) {
- fontSize = yMax - yMin - 2 * border;
+ fontSize = rect->y2 - rect->y1 - 2 * border;
if (w < fontSize) {
fontSize = w;
}
@@ -1034,7 +1047,7 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
x = border + 2 + (comb - text->getLength()) * w;
break;
}
- y = 0.5 * (yMax - yMin) - 0.4 * fontSize;
+ y = 0.5 * (rect->y2 - rect->y1) - 0.4 * fontSize;
// set the font matrix
if (tmPos >= 0) {
@@ -1086,8 +1099,8 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
// compute font autosize
if (fontSize == 0) {
- fontSize = yMax - yMin - 2 * border;
- fontSize2 = (xMax - xMin - 4 - 2 * border) / w;
+ fontSize = rect->y2 - rect->y1 - 2 * border;
+ fontSize2 = (rect->x2 - rect->x1 - 4 - 2 * border) / w;
if (fontSize2 < fontSize) {
fontSize = fontSize2;
}
@@ -1107,13 +1120,13 @@ void Annot::drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
x = border + 2;
break;
case fieldQuadCenter:
- x = (xMax - xMin - w) / 2;
+ x = (rect->x2 - rect->x1 - w) / 2;
break;
case fieldQuadRight:
- x = xMax - xMin - border - 2 - w;
+ x = rect->x2 - rect->x1 - border - 2 - w;
break;
}
- y = 0.5 * (yMax - yMin) - 0.4 * fontSize;
+ y = 0.5 * (rect->y2 - rect->y1) - 0.4 * fontSize;
// set the font matrix
if (tmPos >= 0) {
@@ -1237,8 +1250,8 @@ void Annot::drawListBox(GooString **text, GBool *selection,
wMax = w;
}
}
- fontSize = yMax - yMin - 2 * border;
- fontSize2 = (xMax - xMin - 4 - 2 * border) / wMax;
+ fontSize = rect->y2 - rect->y1 - 2 * border;
+ fontSize2 = (rect->x2 - rect->x1 - 4 - 2 * border) / wMax;
if (fontSize2 < fontSize) {
fontSize = fontSize2;
}
@@ -1250,7 +1263,7 @@ void Annot::drawListBox(GooString **text, GBool *selection,
}
}
// draw the text
- y = yMax - yMin - 1.1 * fontSize;
+ y = rect->y2 - rect->y1 - 1.1 * fontSize;
for (i = topIdx; i < nOptions; ++i) {
// setup
appearBuf->append("q\n");
@@ -1261,7 +1274,7 @@ void Annot::drawListBox(GooString **text, GBool *selection,
appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re f\n",
border,
y - 0.2 * fontSize,
- xMax - xMin - 2 * border,
+ rect->x2 - rect->x1 - 2 * border,
1.1 * fontSize);
}
@@ -1287,10 +1300,10 @@ void Annot::drawListBox(GooString **text, GBool *selection,
x = border + 2;
break;
case fieldQuadCenter:
- x = (xMax - xMin - w) / 2;
+ x = (rect->x2 - rect->x1 - w) / 2;
break;
case fieldQuadRight:
- x = xMax - xMin - border - 2 - w;
+ x = rect->x2 - rect->x1 - border - 2 - w;
break;
}
@@ -1495,7 +1508,7 @@ void Annot::draw(Gfx *gfx, GBool printing) {
isLink = type && !type->cmp("Link");
appearance.fetch(xref, &obj);
gfx->drawAnnot(&obj, isLink ? borderStyle : (AnnotBorderStyle *)NULL,
- xMin, yMin, xMax, yMax);
+ rect->x1, rect->y1, rect->x2, rect->y2);
obj.free();
}
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 50f5bfb..5b7c2b5 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -20,6 +20,7 @@ class CharCodeToUnicode;
class GfxFont;
class GfxFontDict;
class FormWidget;
+class PDFRectangle;
//------------------------------------------------------------------------
// AnnotBorderStyle
@@ -82,13 +83,14 @@ public:
void generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm);
- double getXMin() { return xMin; }
- double getYMin() { return yMin; }
+ double getXMin();
+ double getYMin();
double getFontSize() { return fontSize; }
GooString *getType() { return type; }
-
+ PDFRectangle *getRect() { return rect; }
+
private:
void setColor(Array *a, GBool fill, int adjust);
void drawText(GooString *text, GooString *da, GfxFontDict *fontDict,
@@ -110,6 +112,9 @@ private:
void initialize (XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog);
+ // required data
+ PDFRectangle *rect; // Rect
+
XRef *xref; // the xref table for this PDF file
Ref ref; // object ref identifying this annotation
FormWidget *widget; // FormWidget object for this annotation
@@ -118,8 +123,6 @@ private:
// for the normal appearance
GooString *appearBuf;
Guint flags;
- double xMin, yMin, // annotation rectangle
- xMax, yMax;
AnnotBorderStyle *borderStyle;
double fontSize;
GBool ok;
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 2e09848..5933986 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -89,11 +89,13 @@ Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict, const Ref& aref, Catalog*
{
hasRef = true;
ref = aref;
+ flags = flagUnknown;
initialize (xrefA, acroForm, dict, catalog);
}
Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog* catalog) {
hasRef = false;
+ flags = flagUnknown;
initialize (xrefA, acroForm, dict, catalog);
}
@@ -157,19 +159,43 @@ void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog
}
obj1.free();
+ if (dict->lookup("Contents", &obj1)->isString()) {
+ contents = obj1.getString()->copy();
+ } else {
+ contents = NULL;
+ }
+ obj1.free();
+
+ /* TODO: Page Object indirect reference (should be parsed ?)
+ if (dict->lookup("P", &obj1)->isDict()) {
+ pageDict = NULL;
+ } else {
+ pageDict = NULL;
+ }
+ obj1.free();
+ */
+
+ if (dict->lookup("NM", &obj1)->isString()) {
+ name = obj1.getString()->copy();
+ } else {
+ name = NULL;
+ }
+ obj1.free();
+
+ if (dict->lookup("M", &obj1)->isString()) {
+ modified = obj1.getString()->copy();
+ } else {
+ modified = NULL;
+ }
+ obj1.free();
+
//----- get the flags
if (dict->lookup("F", &obj1)->isInt()) {
- flags = obj1.getInt();
+ flags |= obj1.getInt();
} else {
- flags = 0;
+ flags = flagUnknown;
}
- obj1.free ();
-
- //check for hidden annot
- if (flags & 0x2)
- hidden = true;
- else
- hidden = false;
+ obj1.free();
// check if field apperances need to be regenerated
// Only text or choice fields needs to have appearance regenerated
@@ -185,39 +211,46 @@ void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog
obj1.free();
}
}
+ obj3.free();
+
+ if (dict->lookup("AP", &obj1)->isDict()) {
+ Object obj2;
+
+ if (dict->lookup("AS", &obj2)->isName()) {
+ Object obj3;
+
+ appearState = new GooString(obj2.getName());
+ if (obj1.dictLookup("N", &obj3)->isDict()) {
+ Object obj4;
- if (dict->lookup("AP", &apObj)->isDict()) {
- if (dict->lookup("AS", &asObj)->isName()) {
- if (apObj.dictLookup("N", &obj1)->isDict()) {
- if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) {
- obj2.copy(&appearance);
- ok = gTrue;
- } else {
- obj2.free();
- if (obj1.dictLookupNF("Off", &obj2)->isRef()) {
- obj2.copy(&appearance);
- ok = gTrue;
- } else
- regen = gTrue;
- }
- obj2.free();
+ if (obj3.dictLookupNF(appearState->getCString(), &obj4)->isRef()) {
+ obj4.copy(&appearance);
+ } else {
+ obj4.free();
+ if (obj3.dictLookupNF("Off", &obj4)->isRef()) {
+ obj4.copy(&appearance);
+ } else
+ regen = gTrue;
+ }
+ obj4.free();
}
- obj1.free();
+ obj3.free();
} else {
- if (apObj.dictLookupNF("N", &obj1)->isRef()) {
- obj1.copy(&appearance);
- ok = gTrue;
+ obj2.free();
+
+ appearState = NULL;
+ if (obj1.dictLookupNF("N", &obj2)->isRef()) {
+ obj2.copy(&appearance);
} else
regen = gTrue;
- obj1.free();
}
- asObj.free();
+ obj2.free();
} else {
+ appearState = NULL;
// If field doesn't have an AP we'll have to generate it
regen = gTrue;
}
- apObj.free();
- obj3.free();
+ obj1.free();
//----- parse the border style
@@ -318,6 +351,22 @@ void Annot::initialize(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog
borderStyle = new AnnotBorderStyle(borderType, borderWidth,
borderDash, borderDashLength,
borderR, borderG, borderB);
+
+ if (dict->lookup("StructParent", &obj1)->isInt()) {
+ treeKey = obj1.getInt();
+ } else {
+ treeKey = 0;
+ }
+ obj1.free();
+
+ /* TODO: optional content should be parsed
+ if (dict->lookup("OC", &obj1)->isDict()) {
+ optionalContent = NULL;
+ } else {
+ optionalContent = NULL;
+ }
+ obj1.free();
+ */
}
void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
@@ -334,6 +383,18 @@ void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
}
Annot::~Annot() {
+ if (contents)
+ delete contents;
+
+ if (pageDict)
+ delete pageDict;
+
+ if(name)
+ delete name;
+
+ if (modified)
+ delete modified;
+
if (type) {
delete type;
}
@@ -342,9 +403,15 @@ Annot::~Annot() {
delete appearBuf;
}
+ if(appearState)
+ delete appearState;
+
if (borderStyle) {
delete borderStyle;
}
+
+ if (optionalContent)
+ delete optionalContent;
}
void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 50f5bfb..d25f32b 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -63,6 +63,19 @@ private:
class Annot {
public:
+ enum AnnotFlag {
+ flagUnknown = 0x0000,
+ flagInvisible = 0x0001,
+ flagHidden = 0x0002,
+ flagPrint = 0x0004,
+ flagNoZoom = 0x0008,
+ flagNoRotate = 0x0010,
+ flagNoView = 0x0020,
+ flagReadOnly = 0x0040,
+ flagLocked = 0x0080,
+ flagToggleNoView = 0x0100,
+ flagLockedContents = 0x0200
+ };
Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog);
Annot(XRef *xrefA, Dict *acroForm, Dict *dict, const Ref& aref, Catalog *catalog);
@@ -110,14 +123,24 @@ private:
void initialize (XRef *xrefA, Dict *acroForm, Dict *dict, Catalog *catalog);
+ // optional data
+ GooString *contents; // Contents
+ Dict *pageDict; // P
+ GooString *name; // NM
+ GooString *modified; // M
+ Guint flags; // F (must be a 32 bit unsigned int)
+ //Dict *appearDict; // AP (should be correctly parsed)
+ Object appearance; // a reference to the Form XObject stream
+ // for the normal appearance
+ GooString *appearState; // AS
+ int treeKey; // Struct Parent;
+ Dict *optionalContent; // OC
+
XRef *xref; // the xref table for this PDF file
Ref ref; // object ref identifying this annotation
FormWidget *widget; // FormWidget object for this annotation
GooString *type; // annotation type
- Object appearance; // a reference to the Form XObject stream
- // for the normal appearance
GooString *appearBuf;
- Guint flags;
double xMin, yMin, // annotation rectangle
xMax, yMax;
AnnotBorderStyle *borderStyle;
@@ -127,7 +150,6 @@ private:
GBool isMultiline, isListbox;
bool hasRef;
- bool hidden;
};
//------------------------------------------------------------------------
signature.asc
Description: Esta parte del mensaje está firmada digitalmente
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
