Skip to content

Commit a00f6a4

Browse files
author
Eugene Bochilo
committed
Fix processing of widget annotation if page is deleted
DEVSIX-5760
1 parent 38ebc89 commit a00f6a4

File tree

10 files changed

+115
-118
lines changed

10 files changed

+115
-118
lines changed

kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2277,18 +2277,25 @@ private void updateValueInMarkInfoDict(PdfName key, PdfObject value) {
22772277
}
22782278

22792279
/**
2280-
* This method removes all annotation entries from form fields associated with a given page.
2280+
* Removes all widgets associated with a given page from AcroForm structure. Widgets can be either pure or merged.
22812281
*
22822282
* @param page to remove from.
22832283
*/
22842284
private void removeUnusedWidgetsFromFields(PdfPage page) {
22852285
if (page.isFlushed()) {
22862286
return;
22872287
}
2288+
2289+
final PdfDictionary acroForm = this.getCatalog().getPdfObject().getAsDictionary(PdfName.AcroForm);
2290+
final PdfArray fields = acroForm == null ? null : acroForm.getAsArray(PdfName.Fields);
2291+
22882292
List<PdfAnnotation> annots = page.getAnnotations();
22892293
for (PdfAnnotation annot : annots) {
22902294
if (annot.getSubtype().equals(PdfName.Widget)) {
22912295
((PdfWidgetAnnotation) annot).releaseFormFieldFromWidgetAnnotation();
2296+
if (fields != null) {
2297+
fields.remove(annot.getPdfObject());
2298+
}
22922299
}
22932300
}
22942301
}

kernel/src/main/java/com/itextpdf/kernel/pdf/annot/PdfWidgetAnnotation.java

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -75,30 +75,6 @@ protected PdfWidgetAnnotation(PdfDictionary pdfObject) {
7575
super(pdfObject);
7676
}
7777

78-
private HashSet<PdfName> widgetEntries = new HashSet<PdfName>();
79-
80-
{
81-
widgetEntries.add(PdfName.Subtype);
82-
widgetEntries.add(PdfName.Type);
83-
widgetEntries.add(PdfName.Rect);
84-
widgetEntries.add(PdfName.Contents);
85-
widgetEntries.add(PdfName.P);
86-
widgetEntries.add(PdfName.NM);
87-
widgetEntries.add(PdfName.M);
88-
widgetEntries.add(PdfName.F);
89-
widgetEntries.add(PdfName.AP);
90-
widgetEntries.add(PdfName.AS);
91-
widgetEntries.add(PdfName.Border);
92-
widgetEntries.add(PdfName.C);
93-
widgetEntries.add(PdfName.StructParent);
94-
widgetEntries.add(PdfName.OC);
95-
widgetEntries.add(PdfName.H);
96-
widgetEntries.add(PdfName.MK);
97-
widgetEntries.add(PdfName.A);
98-
widgetEntries.add(PdfName.AA);
99-
widgetEntries.add(PdfName.BS);
100-
}
101-
10278
@Override
10379
public PdfName getSubtype() {
10480
return PdfName.Widget;
@@ -133,22 +109,20 @@ public PdfName getHighlightMode() {
133109
}
134110

135111
/**
136-
* This method removes all widget annotation entries from the form field the given annotation merged with.
112+
* Remove widget annotation from AcroForm hierarchy.
137113
*/
138-
public void releaseFormFieldFromWidgetAnnotation(){
139-
PdfDictionary annotDict = getPdfObject();
140-
for (PdfName entry: widgetEntries) {
141-
annotDict.remove(entry);
142-
}
143-
PdfDictionary parent = annotDict.getAsDictionary(PdfName.Parent);
144-
if (parent != null && annotDict.size() == 1) {
114+
public void releaseFormFieldFromWidgetAnnotation() {
115+
PdfDictionary annotationDictionary = getPdfObject();
116+
PdfDictionary parent = annotationDictionary.getAsDictionary(PdfName.Parent);
117+
if (parent != null) {
145118
PdfArray kids = parent.getAsArray(PdfName.Kids);
146-
kids.remove(annotDict);
147-
if (kids.size() == 0) {
119+
kids.remove(annotationDictionary);
120+
if (kids.isEmpty()) {
148121
parent.remove(PdfName.Kids);
149122
}
150123
}
151124
}
125+
152126
/**
153127
* Set the visibility flags of the Widget annotation
154128
* Options are: HIDDEN, HIDDEN_BUT_PRINTABLE, VISIBLE, VISIBLE_BUT_DOES_NOT_PRINT

kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentTest.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -560,18 +560,37 @@ public void openDocumentWithInvalidCatalogVersionAndConservativeStrictnessReadin
560560
}
561561

562562
@Test
563-
// TODO DEVSIX-5760 cleaned widget left in the kids of the form field
564563
public void widgetDaEntryRemovePageTest() throws IOException, InterruptedException {
565-
// In this test widgets contain entry /DA that is not specific for widget annotation, so after removing of the
566-
// page such widget is not removed from the document. See method PdfDocument#removeUnusedWidgetsFromFields
567-
// to see logic of removing unused widgets.
568-
// If open the output PDF in Adobe Acrobat, widgets on pages 3-4 will not be viewed. It seems to adobe bug.
569564
final String testName = "widgetDaEntryRemovePage.pdf";
570565
final String outPdf = DESTINATION_FOLDER + testName;
571-
PdfDocument pdfDocument = new PdfDocument(new PdfReader(SOURCE_FOLDER + "widgetWithDaEntry.pdf"),
572-
new PdfWriter(outPdf));
573-
pdfDocument.removePage(3);
574-
pdfDocument.close();
566+
try (PdfDocument pdfDocument = new PdfDocument(
567+
new PdfReader(SOURCE_FOLDER + "widgetWithDaEntry.pdf"), new PdfWriter(outPdf))) {
568+
pdfDocument.removePage(3);
569+
}
570+
Assert.assertNull(new CompareTool().compareByContent(outPdf, SOURCE_FOLDER + "cmp_" + testName,
571+
DESTINATION_FOLDER));
572+
}
573+
574+
@Test
575+
public void mergedAndSimpleWidgetsRemovePageTest() throws IOException, InterruptedException {
576+
final String testName = "mergedAndSimpleWidgetsRemovePage.pdf";
577+
final String outPdf = DESTINATION_FOLDER + testName;
578+
try (PdfDocument pdfDocument = new PdfDocument(
579+
new PdfReader(SOURCE_FOLDER + "mergedAndSimpleWidgets.pdf"), new PdfWriter(outPdf))) {
580+
pdfDocument.removePage(1);
581+
}
582+
Assert.assertNull(new CompareTool().compareByContent(outPdf, SOURCE_FOLDER + "cmp_" + testName,
583+
DESTINATION_FOLDER));
584+
}
585+
586+
@Test
587+
public void mergedSiblingWidgetsRemovePageTest() throws IOException, InterruptedException {
588+
final String testName = "mergedSiblingWidgetsRemovePage.pdf";
589+
final String outPdf = DESTINATION_FOLDER + testName;
590+
try (PdfDocument pdfDocument = new PdfDocument(
591+
new PdfReader(SOURCE_FOLDER + "mergedSiblingWidgets.pdf"), new PdfWriter(outPdf))) {
592+
pdfDocument.removePage(2);
593+
}
575594
Assert.assertNull(new CompareTool().compareByContent(outPdf, SOURCE_FOLDER + "cmp_" + testName,
576595
DESTINATION_FOLDER));
577596
}

0 commit comments

Comments
 (0)