[poppler] 2 commits - poppler/Annot.cc poppler/Annot.h poppler/Page.cc poppler/Page.h
Albert Astals Cid
aacid at kemper.freedesktop.org
Wed Mar 28 14:54:12 PDT 2012
poppler/Annot.cc | 207 ++++++++++++++++++++++++++++++++++++++++++-------------
poppler/Annot.h | 30 ++++++-
poppler/Page.cc | 36 +++++++++
poppler/Page.h | 3
4 files changed, 225 insertions(+), 51 deletions(-)
New commits:
commit 631224dc0c721119c91984f1940c9e51edf17eca
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date: Tue Mar 20 00:56:50 2012 +0100
Annotation removal
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 79add84..caa13c5 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -5726,6 +5726,23 @@ void Annots::appendAnnot(Annot *annot) {
}
}
+GBool Annots::removeAnnot(Annot *annot) {
+ int idx = -1;
+ // Search annot and remove it by swapping with last element
+ for (int i = 0; idx == -1 && i < nAnnots; i++) {
+ if (annots[i] == annot) {
+ idx = i;
+ }
+ }
+ if (idx == -1) {
+ return gFalse;
+ } else {
+ annots[idx] = annots[--nAnnots];
+ annot->decRefCnt();
+ return gTrue;
+ }
+}
+
Annot *Annots::createAnnot(Dict* dict, Object *obj) {
Annot *annot = NULL;
Object obj1;
diff --git a/poppler/Annot.h b/poppler/Annot.h
index b506df9..b196e51 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -1330,6 +1330,7 @@ public:
int getNumAnnots() { return nAnnots; }
Annot *getAnnot(int i) { return annots[i]; }
void appendAnnot(Annot *annot);
+ GBool removeAnnot(Annot *annot);
private:
Annot* createAnnot(Dict* dict, Object *obj);
diff --git a/poppler/Page.cc b/poppler/Page.cc
index 48ed647..b9d25ff 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -24,6 +24,7 @@
// Copyright (C) 2008 Iñigo MartÃnez <inigomartinez at gmail.com>
// Copyright (C) 2008 Brad Hards <bradh at kde.org>
// Copyright (C) 2008 Ilya Gorenbein <igorenbein at finjan.com>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -394,6 +395,41 @@ void Page::addAnnot(Annot *annot) {
annot->setPage(&pageRef, num);
}
+void Page::removeAnnot(Annot *annot) {
+ Ref annotRef = annot->getRef();
+ Object annArray;
+
+ getAnnots(&annArray);
+ if (annArray.isArray()) {
+ int idx = -1;
+ // Get annotation position
+ for (int i = 0; idx == -1 && i < annArray.arrayGetLength(); ++i) {
+ Object tmp;
+ Ref currAnnot = annArray.arrayGetNF(i, &tmp)->getRef();
+ tmp.free();
+ if (currAnnot.num == annotRef.num && currAnnot.gen == annotRef.gen) {
+ idx = i;
+ }
+ }
+
+ if (idx == -1) {
+ error(errInternal, -1, "Annotation doesn't belong to this page");
+ annArray.free();
+ return;
+ }
+ annots->removeAnnot(annot); // Gracefully fails on popup windows
+ annArray.arrayRemove(idx);
+ xref->removeIndirectObject(annotRef);
+
+ if (annotsObj.isRef()) {
+ xref->setModifiedObject (&annArray, annotsObj.getRef());
+ } else {
+ xref->setModifiedObject (&pageObj, pageRef);
+ }
+ }
+ annArray.free();
+}
+
Links *Page::getLinks() {
return new Links(getAnnots());
}
diff --git a/poppler/Page.h b/poppler/Page.h
index 70141d0..a1722a4 100644
--- a/poppler/Page.h
+++ b/poppler/Page.h
@@ -171,6 +171,9 @@ public:
Object *getAnnots(Object *obj) { return annotsObj.fetch(xref, obj); }
// Add a new annotation to the page
void addAnnot(Annot *annot);
+ // Remove an existing annotation from the page
+ // Note: Caller is responsible for deleting popup and appearance streams too
+ void removeAnnot(Annot *annot);
// Return a list of links.
Links *getLinks();
commit 20476370a445a26f1fae9db6ad58727ee3c63550
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date: Wed Mar 28 23:16:37 2012 +0200
Basic support for Annot appearance stream removal and invalidation
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 405f5f6..79add84 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -776,6 +776,111 @@ AnnotIconFit::AnnotIconFit(Dict* dict) {
}
//------------------------------------------------------------------------
+// AnnotAppearance
+//------------------------------------------------------------------------
+
+AnnotAppearance::AnnotAppearance(PDFDoc *docA, Object *dict) {
+ assert(dict->isDict());
+ xref = docA->getXRef();
+ dict->copy(&appearDict);
+}
+
+AnnotAppearance::~AnnotAppearance() {
+ appearDict.free();
+}
+
+void AnnotAppearance::getAppearanceStream(AnnotAppearance::AnnotAppearanceType type, const char *state, Object *dest) {
+ Object apData, stream;
+ apData.initNull();
+
+ // Obtain dictionary or stream associated to appearance type
+ if (type == appearRollover) {
+ appearDict.dictLookupNF("R", &apData);
+ } else if (type == appearDown) {
+ appearDict.dictLookupNF("D", &apData);
+ }
+ if (apData.isNull()) { // Normal appearance, also used as fallback
+ appearDict.dictLookupNF("N", &apData);
+ }
+
+ // Search state if it's a subdictionary
+ if (apData.isDict() && state) {
+ Object obj1;
+ apData.dictLookupNF(state, &obj1);
+ apData.free();
+ obj1.copy(&apData);
+ obj1.free();
+ }
+
+ dest->initNull();
+ // Sanity check on the value we are about to return: it must be a ref to stream
+ if (apData.isRef()) {
+ apData.fetch(xref, &stream);
+ if (stream.isStream()) {
+ apData.copy(dest);
+ } else {
+ error(errSyntaxWarning, -1, "AP points to a non-stream object");
+ }
+ stream.free();
+ }
+ apData.free();
+}
+
+GooString * AnnotAppearance::getStateKey(int i) {
+ Object obj1;
+ GooString * res = NULL;
+ appearDict.dictLookupNF("N", &obj1);
+ if (obj1.isDict()) {
+ res = new GooString(obj1.dictGetKey(i));
+ }
+ obj1.free();
+ return res;
+}
+
+int AnnotAppearance::getNumStates() {
+ Object obj1;
+ int res = 0;
+ appearDict.dictLookupNF("N", &obj1);
+ if (obj1.isDict()) {
+ res = obj1.dictGetLength();
+ }
+ obj1.free();
+ return res;
+}
+
+// Removes stream if obj is a Ref, or removes pointed streams if obj is a Dict
+void AnnotAppearance::removeStateStreams(Object *obj1) {
+ // TODO: Remove XObject resources, check for XObjects shared by multiple
+ // annotations, delete streams from name table (if any)
+ if (obj1->isRef()) {
+ xref->removeIndirectObject(obj1->getRef());
+ } else if (obj1->isDict()) {
+ const int size = obj1->dictGetLength();
+ for (int i = 0; i < size; ++i) {
+ Object obj2;
+ obj1->dictGetValNF(i, &obj2);
+ if (obj2.isRef()) {
+ xref->removeIndirectObject(obj2.getRef());
+ }
+ obj2.free();
+ }
+ }
+}
+
+void AnnotAppearance::removeAllStreams() {
+ Object obj1;
+ appearDict.dictLookupNF("N", &obj1);
+ removeStateStreams(&obj1);
+ obj1.free();
+ appearDict.dictLookupNF("R", &obj1);
+ removeStateStreams(&obj1);
+ obj1.free();
+ appearDict.dictLookupNF("D", &obj1);
+ removeStateStreams(&obj1);
+ obj1.free();
+}
+
+//------------------------------------------------------------------------
// AnnotAppearanceCharacs
//------------------------------------------------------------------------
@@ -912,13 +1017,12 @@ Annot::Annot(PDFDoc *docA, Dict *dict, Object *obj) {
}
void Annot::initialize(PDFDoc *docA, Dict *dict) {
- Object apObj, asObj, obj1, obj2, obj3;
+ Object apObj, asObj, obj1, obj2;
- appRef.num = 0;
- appRef.gen = 65535;
ok = gTrue;
doc = docA;
xref = doc->getXRef();
+ appearStreams = NULL;
appearState = NULL;
appearBuf = NULL;
fontSize = 0;
@@ -995,22 +1099,25 @@ void Annot::initialize(PDFDoc *docA, Dict *dict) {
}
obj1.free();
- //----- get the appearance state
-
+ //----- get the annotation appearance dictionary
dict->lookup("AP", &apObj);
+ if (apObj.isDict()) {
+ appearStreams = new AnnotAppearance(doc, &apObj);
+ }
+ apObj.free();
+
+ //----- get the appearance state
dict->lookup("AS", &asObj);
if (asObj.isName()) {
appearState = new GooString(asObj.getName());
- } else if (apObj.isDict()) {
- if (apObj.dictLookup("N", &obj1)->isDict()) {
- error (errSyntaxError, -1, "Invalid or missing AS value in annotation containing one or more appearance subdictionaries");
- // AS value is required in this case, but if the
- // N dictionary contains only one entry
- // take it as default appearance.
- if (obj1.dictGetLength() == 1)
- appearState = new GooString(obj1.dictGetKey(0));
+ } else if (appearStreams && appearStreams->getNumStates() != 0) {
+ error (errSyntaxError, -1, "Invalid or missing AS value in annotation containing one or more appearance subdictionaries");
+ // AS value is required in this case, but if the
+ // N dictionary contains only one entry
+ // take it as default appearance.
+ if (appearStreams->getNumStates() == 1) {
+ appearState = appearStreams->getStateKey(0);
}
- obj1.free();
}
if (!appearState) {
appearState = new GooString("Off");
@@ -1018,22 +1125,9 @@ void Annot::initialize(PDFDoc *docA, Dict *dict) {
asObj.free();
//----- get the annotation appearance
-
- if (apObj.isDict()) {
- apObj.dictLookup("N", &obj1);
- apObj.dictLookupNF("N", &obj2);
- if (obj1.isDict()) {
- if (obj1.dictLookupNF(appearState->getCString(), &obj3)->isRef()) {
- obj3.copy(&appearance);
- }
- obj3.free();
- } else if (obj2.isRef()) {
- obj2.copy(&appearance);
- }
- obj1.free();
- obj2.free();
+ if (appearStreams) {
+ appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
}
- apObj.free();
//----- parse the border style
if (dict->lookup("BS", &obj1)->isDict()) {
@@ -1218,9 +1312,6 @@ void Annot::setAppearanceState(const char *state) {
if (!state)
return;
- if (appearState && appearState->cmp(state) == 0)
- return;
-
delete appearState;
appearState = new GooString(state);
@@ -1229,23 +1320,27 @@ void Annot::setAppearanceState(const char *state) {
update ("AS", &obj1);
// The appearance state determines the current appearance stream
- Object obj2;
- if (annotObj.dictLookup("AP", &obj2)->isDict()) {
- Object obj3;
-
- if (obj2.dictLookup("N", &obj3)->isDict()) {
- Object obj4;
+ appearance.free();
+ if (appearStreams) {
+ appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString(), &appearance);
+ } else {
+ appearance.initNull();
+ }
+}
- appearance.free();
- if (obj3.dictLookupNF(state, &obj4)->isRef())
- obj4.copy(&appearance);
- else
- appearance.initNull();
- obj4.free();
- }
- obj3.free();
+void Annot::invalidateAppearance() {
+ if (appearStreams) { // Remove existing appearance streams
+ appearStreams->removeAllStreams();
}
- obj2.free();
+ delete appearStreams;
+ appearStreams = NULL;
+
+ setAppearanceState("Off"); // Default appearance state
+
+ Object obj1;
+ obj1.initNull();
+ update ("AP", &obj1); // Remove AP
+ update ("AS", &obj1); // Remove AS
}
double Annot::getXMin() {
@@ -1292,6 +1387,7 @@ Annot::~Annot() {
if (modified)
delete modified;
+ delete appearStreams;
appearance.free();
if (appearState)
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 8d40a8a..b506df9 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -368,7 +368,26 @@ public:
appearDown
};
- AnnotAppearance(Dict *dict);
+ AnnotAppearance(PDFDoc *docA, Object *dict);
+ ~AnnotAppearance();
+
+ // State is ignored if no subdictionary is present
+ void getAppearanceStream(AnnotAppearanceType type, const char *state, Object *dest);
+
+ // Access keys in normal appearance subdictionary (N)
+ GooString * getStateKey(int i);
+ int getNumStates();
+
+ // Removes all associated streams in the xref table. Caller is required to
+ // reset parent annotation's AP and AS after this call.
+ void removeAllStreams();
+
+private:
+ void removeStateStreams(Object *state);
+
+protected:
+ XRef *xref; // the xref table for this PDF file
+ Object appearDict; // Annotation's AP
};
//------------------------------------------------------------------------
@@ -504,6 +523,9 @@ public:
void setAppearanceState(const char *state);
+ // Delete appearance streams and reset appearance state
+ void invalidateAppearance();
+
// getters
PDFDoc *getDoc() const { return doc; }
XRef *getXRef() const { return xref; }
@@ -517,7 +539,7 @@ public:
GooString *getName() const { return name; }
GooString *getModified() const { return modified; }
Guint getFlags() const { return flags; }
- /*Dict *getAppearDict() const { return appearDict; }*/
+ AnnotAppearance *getAppearStreams() const { return appearStreams; }
GooString *getAppearState() const { return appearState; }
AnnotBorder *getBorder() const { return border; }
AnnotColor *getColor() const { return color; }
@@ -564,8 +586,7 @@ protected:
GooString *name; // NM
GooString *modified; // M
Guint flags; // F (must be a 32 bit unsigned int)
- //Dict *appearDict; // AP (should be correctly parsed)
- Ref appRef; //the reference to the indirect appearance object in XRef
+ AnnotAppearance *appearStreams; // AP
Object appearance; // a reference to the Form XObject stream
// for the normal appearance
GooString *appearState; // AS
More information about the poppler
mailing list