1) AnnotText: Always force 24x24 size with custom stamps, not only on first rendering
AnnotText::draw forces the bounding rectangle to be 24x24. However, the overridden values are lost after the first rendering, because appearance is not Null any more. This leads to inconsistent rendering results. This patch makes the 24x24 rectangle persistent. 2) Do not remove appearance stream if it's shared with other annotations The same appearance stream can be shared by many annotations. With my previous code, I didn't check if a stream was shared before removing it. This patch implements the check by scanning all annotations in the document. I'm attaching a document with two annotations that share the same appearance stream. Without this patch, if you removed one, both of them disappeared because the stream was removed under the other annotation's foot. 3) Preserve z-index after annotation removal With my previous code, I implemented annotation removal by overriding the annotation to be removed with the last one. But it breaks z-order. This patch implements removal by shifting subsequent elements left. See thread "[poppler] z-order of annotation objects in PDF document".
From f578b791150d1be5726b1041985180498a07ddcb Mon Sep 17 00:00:00 2001 From: Fabio D'Urso <[email protected]> Date: Sat, 21 Apr 2012 20:26:49 +0200 Subject: [PATCH 1/3] AnnotText: Always force 24x24 size with custom stamps, not only on first rendering --- poppler/Annot.cc | 21 ++++++++++++--------- 1 files changed, 12 insertions(+), 9 deletions(-) diff --git a/poppler/Annot.cc b/poppler/Annot.cc index 130b9bb..06d08d5 100644 --- a/poppler/Annot.cc +++ b/poppler/Annot.cc @@ -2248,8 +2248,6 @@ void AnnotText::draw(Gfx *gfx, GBool printing) { if (!isVisible (printing)) return; - double rectx2 = rect->x2; - double recty2 = rect->y2; if (appearance.isNull()) { ca = opacity; @@ -2280,9 +2278,11 @@ void AnnotText::draw(Gfx *gfx, GBool printing) { appearBuf->append (ANNOT_TEXT_AP_CIRCLE); appearBuf->append ("Q\n"); + // Force 24x24 rectangle + PDFRectangle fixedRect(rect->x1, rect->y1, rect->x1 + 24, rect->y1 + 24); + appearBBox = new AnnotAppearanceBBox(&fixedRect); double bbox[4]; - bbox[0] = bbox[1] = 0; - bbox[2] = bbox[3] = 24; + appearBBox->getBBoxRect(bbox); if (ca == 1) { createForm(bbox, gFalse, NULL, &appearance); } else { @@ -2296,15 +2296,18 @@ void AnnotText::draw(Gfx *gfx, GBool printing) { createForm(bbox, gFalse, &resDict, &appearance); } delete appearBuf; - - rectx2 = rect->x1 + 24; - recty2 = rect->y1 + 24; } // draw the appearance stream appearance.fetch(xref, &obj); - gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color, - rect->x1, rect->y1, rectx2, recty2); + if (appearBBox) { + gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color, + appearBBox->getPageXMin(), appearBBox->getPageYMin(), + appearBBox->getPageXMax(), appearBBox->getPageYMax()); + } else { + gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color, + rect->x1, rect->y1, rect->x2, rect->y2); + } obj.free(); } -- 1.7.6.5
From f5ca73fc84d30236489e1244915baf77f284d4a5 Mon Sep 17 00:00:00 2001 From: Fabio D'Urso <[email protected]> Date: Sat, 21 Apr 2012 17:53:22 +0200 Subject: [PATCH 2/3] Do not remove appearance stream if it's shared with other annotations --- poppler/Annot.cc | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++--- poppler/Annot.h | 6 ++++ 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/poppler/Annot.cc b/poppler/Annot.cc index 06d08d5..b3bc97d 100644 --- a/poppler/Annot.cc +++ b/poppler/Annot.cc @@ -774,6 +774,7 @@ AnnotIconFit::AnnotIconFit(Dict* dict) { AnnotAppearance::AnnotAppearance(PDFDoc *docA, Object *dict) { assert(dict->isDict()); + doc = docA; xref = docA->getXRef(); dict->copy(&appearDict); } @@ -841,19 +842,88 @@ int AnnotAppearance::getNumStates() { return res; } +// Test if stateObj (a Ref or a Dict) points to the specified stream +GBool AnnotAppearance::referencesStream(Object *stateObj, Ref refToStream) { + if (stateObj->isRef()) { + Ref r = stateObj->getRef(); + if (r.num == refToStream.num && r.gen == refToStream.gen) { + return gTrue; + } + } else if (stateObj->isDict()) { // Test each value + const int size = stateObj->dictGetLength(); + for (int i = 0; i < size; ++i) { + Object obj1; + stateObj->dictGetValNF(i, &obj1); + if (obj1.isRef()) { + Ref r = obj1.getRef(); + if (r.num == refToStream.num && r.gen == refToStream.gen) { + return gTrue; + } + } + obj1.free(); + } + } + return gFalse; // Not found +} + +// Test if this AnnotAppearance references the specified stream +GBool AnnotAppearance::referencesStream(Ref refToStream) { + Object obj1; + GBool found; + + // Scan each state's ref/subdictionary + appearDict.dictLookupNF("N", &obj1); + found = referencesStream(&obj1, refToStream); + obj1.free(); + if (found) + return gTrue; + + appearDict.dictLookupNF("R", &obj1); + found = referencesStream(&obj1, refToStream); + obj1.free(); + if (found) + return gTrue; + + appearDict.dictLookupNF("D", &obj1); + found = referencesStream(&obj1, refToStream); + obj1.free(); + return found; +} + +// If this is the only annotation in the document that references the +// specified appearance stream, remove the appearance stream +void AnnotAppearance::removeStream(Ref refToStream) { + const int lastpage = doc->getNumPages(); + for (int pg = 1; pg <= lastpage; ++pg) { // Scan all annotations in the document + Page *page = doc->getPage(pg); + if (!page) { + error(errSyntaxError, -1, "Failed check for shared annotation stream at page {0:d}", pg); + continue; + } + Annots *annots = page->getAnnots(); + for (int i = 0; i < annots->getNumAnnots(); ++i) { + AnnotAppearance *annotAp = annots->getAnnot(i)->getAppearStreams(); + if (annotAp && annotAp != this && annotAp->referencesStream(refToStream)) { + return; // Another annotation points to the stream -> Don't delete it + } + } + } + + // TODO: stream resources (e.g. font), AP name tree + xref->removeIndirectObject(refToStream); +} + // 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()); + removeStream(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()); + removeStream(obj2.getRef()); } obj2.free(); } diff --git a/poppler/Annot.h b/poppler/Annot.h index 98e4d70..04a1301 100644 --- a/poppler/Annot.h +++ b/poppler/Annot.h @@ -382,10 +382,16 @@ public: // reset parent annotation's AP and AS after this call. void removeAllStreams(); + // Test if this AnnotAppearance references the specified stream + GBool referencesStream(Ref targetStreamRef); + private: + static GBool referencesStream(Object *stateObj, Ref targetStreamRef); + void removeStream(Ref refToStream); void removeStateStreams(Object *state); protected: + PDFDoc *doc; XRef *xref; // the xref table for this PDF file Object appearDict; // Annotation's AP }; -- 1.7.6.5
From cd6fc1e34b92f668987bd725da6900a96cb3db11 Mon Sep 17 00:00:00 2001 From: Fabio D'Urso <[email protected]> Date: Sat, 21 Apr 2012 18:16:46 +0200 Subject: [PATCH 3/3] Preserve z-index after annotation removal --- poppler/Annot.cc | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/poppler/Annot.cc b/poppler/Annot.cc index b3bc97d..24ef57d 100644 --- a/poppler/Annot.cc +++ b/poppler/Annot.cc @@ -6446,7 +6446,7 @@ void Annots::appendAnnot(Annot *annot) { GBool Annots::removeAnnot(Annot *annot) { int idx = -1; - // Search annot and remove it by swapping with last element + // Search annot and determine its index for (int i = 0; idx == -1 && i < nAnnots; i++) { if (annots[i] == annot) { idx = i; @@ -6455,7 +6455,8 @@ GBool Annots::removeAnnot(Annot *annot) { if (idx == -1) { return gFalse; } else { - annots[idx] = annots[--nAnnots]; + --nAnnots; + memmove( annots + idx, annots + idx + 1, sizeof(annots[0]) * (nAnnots - idx) ); annot->decRefCnt(); return gTrue; } -- 1.7.6.5
shared-ap-streams.pdf
Description: Adobe PDF document
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
