Skip to content

Commit f4456fa

Browse files
author
glenn.volckaert
committed
Introduce a copy filter to handle specific cases while copying
Use a CopyFilter to handle destinations DEVSIX-6090
1 parent 0eb2271 commit f4456fa

File tree

62 files changed

+2344
-445
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2344
-445
lines changed

forms/src/test/java/com/itextpdf/forms/PdfFormCopyWithGotoTest.java

Lines changed: 439 additions & 0 deletions
Large diffs are not rendered by default.
Binary file not shown.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
3+
This file is part of the iText (R) project.
4+
Copyright (c) 1998-2022 iText Group NV
5+
Authors: Bruno Lowagie, Paulo Soares, et al.
6+
7+
This program is free software; you can redistribute it and/or modify
8+
it under the terms of the GNU Affero General Public License version 3
9+
as published by the Free Software Foundation with the addition of the
10+
following permission added to Section 15 as permitted in Section 7(a):
11+
FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
12+
ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
13+
OF THIRD PARTY RIGHTS
14+
15+
This program is distributed in the hope that it will be useful, but
16+
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17+
or FITNESS FOR A PARTICULAR PURPOSE.
18+
See the GNU Affero General Public License for more details.
19+
You should have received a copy of the GNU Affero General Public License
20+
along with this program; if not, see http://www.gnu.org/licenses or write to
21+
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22+
Boston, MA, 02110-1301 USA, or download the license from the following URL:
23+
http://itextpdf.com/terms-of-use/
24+
25+
The interactive user interfaces in modified source and object code versions
26+
of this program must display Appropriate Legal Notices, as required under
27+
Section 5 of the GNU Affero General Public License.
28+
29+
In accordance with Section 7(b) of the GNU Affero General Public License,
30+
a covered work must retain the producer line in every PDF that is created
31+
or manipulated using iText.
32+
33+
You can be released from the requirements of the license by purchasing
34+
a commercial license. Buying such a license is mandatory as soon as you
35+
develop commercial activities involving the iText software without
36+
disclosing the source code of your own applications.
37+
These activities include: offering paid services to customers as an ASP,
38+
serving PDFs on the fly in a web application, shipping iText with a closed
39+
source product.
40+
41+
For more information, please contact iText Software Corp. at this
42+
43+
*/
44+
package com.itextpdf.kernel.pdf;
45+
46+
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
47+
import com.itextpdf.kernel.pdf.navigation.PdfDestination;
48+
import com.itextpdf.kernel.utils.ICopyFilter;
49+
50+
import java.util.Collections;
51+
import java.util.List;
52+
53+
/**
54+
* A copy filter that will handle goto annotations and actions separately.
55+
*/
56+
public class DestinationResolverCopyFilter implements ICopyFilter {
57+
58+
private static final List<PdfName> EXCLUDE_KEYS_ACTIONCOPY = Collections.singletonList(PdfName.D);
59+
60+
private final PdfDocument targetDocument;
61+
private final PdfDocument fromDocument;
62+
63+
/**
64+
* Initilazes a copy filter that will set all needed information aside to handle objects with a page destination
65+
* after all pages are copied.
66+
*
67+
* <p>
68+
*
69+
* @param fromDocument the {@link PdfDocument} the pages are copied from
70+
* @param targetDocument the {@link PdfDocument} the pages are copied to
71+
*/
72+
public DestinationResolverCopyFilter(PdfDocument fromDocument, PdfDocument targetDocument) {
73+
this.fromDocument = fromDocument;
74+
this.targetDocument = targetDocument;
75+
}
76+
77+
@Override
78+
public boolean shouldProcess(PdfObject newParent, PdfName name, PdfObject value) {
79+
final PdfObject workRef = getDirectPdfObject(value);
80+
if (workRef.getType() == PdfObject.DICTIONARY) {
81+
final PdfDictionary dict = (PdfDictionary) workRef;
82+
// a goto action
83+
if (dict.getAsName(PdfName.S) == PdfName.GoTo) {
84+
processAction(newParent, name, dict);
85+
return false;
86+
}
87+
// a link annotation with destination
88+
if (PdfName.Link.equals(dict.getAsName(PdfName.Subtype)) && newParent.isDictionary()) {
89+
return processLinkAnnotion(newParent, value, dict);
90+
}
91+
}
92+
return true;
93+
}
94+
95+
private boolean processLinkAnnotion(PdfObject newParent, PdfObject value, PdfDictionary dict) {
96+
if (dict.get(PdfName.Dest) != null) {
97+
fromDocument.storeDestinationToReaddress(
98+
PdfDestination.makeDestination(dict.get(PdfName.Dest)), (PdfDestination nd) -> {
99+
final PdfObject newVal = value.copyTo(targetDocument, this);
100+
(new PdfPage((PdfDictionary) newParent)).
101+
addAnnotation(-1, PdfAnnotation.makeAnnotation(newVal), false);
102+
}, (PdfDestination od) -> {
103+
//do nothing
104+
});
105+
return false;
106+
}
107+
if (dict.getAsDictionary(PdfName.A) != null && dict.getAsDictionary(PdfName.A).get(PdfName.D) != null) {
108+
fromDocument.storeDestinationToReaddress(
109+
PdfDestination.makeDestination(dict.getAsDictionary(PdfName.A).get(PdfName.D)),
110+
(PdfDestination nd) -> {
111+
final PdfObject newAnnot = value.copyTo(targetDocument);
112+
((PdfDictionary) newAnnot).getAsDictionary(PdfName.A).put(PdfName.D, nd.getPdfObject());
113+
(new PdfPage((PdfDictionary) newParent)).
114+
addAnnotation(-1, PdfAnnotation.makeAnnotation(newAnnot), false);
115+
}, (PdfDestination od) -> {
116+
//do nothing
117+
});
118+
return false;
119+
}
120+
return true;
121+
}
122+
123+
private void processAction(PdfObject newParent, PdfName name, PdfDictionary dict) {
124+
fromDocument.storeDestinationToReaddress(
125+
PdfDestination.makeDestination(dict.get(PdfName.D)), (PdfDestination nd) -> {
126+
//Add action with new destination
127+
final PdfObject newVal = dict.copyTo(targetDocument, EXCLUDE_KEYS_ACTIONCOPY, false);
128+
((PdfDictionary) newVal).put(PdfName.D, nd.getPdfObject());
129+
130+
if (newParent.getType() == PdfObject.DICTIONARY) {
131+
((PdfDictionary) newParent).put(name, newVal);
132+
} else {
133+
((PdfArray) newParent).add(newVal);
134+
}
135+
}, (PdfDestination od) -> {
136+
//do nothing
137+
});
138+
}
139+
140+
private static PdfObject getDirectPdfObject(PdfObject value) {
141+
PdfObject workRef = value;
142+
if (value.isIndirectReference()) {
143+
workRef = ((PdfIndirectReference) value).getRefersTo();
144+
}
145+
return workRef;
146+
}
147+
}

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ This file is part of the iText (R) project.
4646
import com.itextpdf.kernel.exceptions.PdfException;
4747
import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant;
4848
import com.itextpdf.kernel.geom.Rectangle;
49+
import com.itextpdf.kernel.utils.ICopyFilter;
4950

5051
import java.util.ArrayList;
5152
import java.util.Collection;
@@ -598,11 +599,13 @@ protected PdfObject newInstance() {
598599
}
599600

600601
@Override
601-
protected void copyContent(PdfObject from, PdfDocument document) {
602-
super.copyContent(from, document);
602+
protected void copyContent(PdfObject from, PdfDocument document, ICopyFilter copyFilter) {
603+
super.copyContent(from, document, copyFilter);
603604
PdfArray array = (PdfArray) from;
604605
for (PdfObject entry : array.list) {
605-
add(entry.processCopying(document, false));
606+
if (copyFilter.shouldProcess(this, null, entry)) {
607+
add(entry.processCopying(document, false, copyFilter));
608+
}
606609
}
607610
}
608611

0 commit comments

Comments
 (0)