@@ -45,19 +45,30 @@ This file is part of the iText (R) project.
45
45
46
46
import com .itextpdf .forms .fields .PdfFormField ;
47
47
import com .itextpdf .io .LogMessageConstant ;
48
- import com .itextpdf .kernel .pdf .*;
48
+ import com .itextpdf .io .util .MessageFormatUtil ;
49
+ import com .itextpdf .kernel .pdf .IPdfPageExtraCopier ;
50
+ import com .itextpdf .kernel .pdf .PdfArray ;
51
+ import com .itextpdf .kernel .pdf .PdfDictionary ;
52
+ import com .itextpdf .kernel .pdf .PdfDocument ;
53
+ import com .itextpdf .kernel .pdf .PdfName ;
54
+ import com .itextpdf .kernel .pdf .PdfObject ;
55
+ import com .itextpdf .kernel .pdf .PdfPage ;
56
+ import com .itextpdf .kernel .pdf .PdfString ;
49
57
import com .itextpdf .kernel .pdf .annot .PdfAnnotation ;
50
58
import org .slf4j .Logger ;
51
59
import org .slf4j .LoggerFactory ;
52
60
53
- import com .itextpdf .io .util .MessageFormatUtil ;
54
- import java .util .*;
61
+ import java .util .ArrayList ;
62
+ import java .util .HashSet ;
63
+ import java .util .List ;
64
+ import java .util .Map ;
65
+ import java .util .Set ;
55
66
56
67
/**
57
68
* A sample implementation of the {#link IPdfPageExtraCopier} interface which
58
69
* copies only AcroForm fields to a new page.
59
- *
60
- *
70
+ * <p>
71
+ * <p>
61
72
* NOTE: While it's absolutely not necessary to use the same PdfPageFormCopier instance for copying operations,
62
73
* it is still worth to know that PdfPageFormCopier uses some caching logic which can potentially improve performance
63
74
* in case of the reusing of the same instance.
@@ -80,87 +91,110 @@ public void copy(PdfPage fromPage, PdfPage toPage) {
80
91
documentTo = toPage .getDocument ();
81
92
formTo = PdfAcroForm .getAcroForm (documentTo , true );
82
93
}
83
- if (formFrom != null ) {
84
- //duplicate AcroForm dictionary
85
- List <PdfName > excludedKeys = new ArrayList <>();
86
- excludedKeys .add (PdfName .Fields );
87
- excludedKeys .add (PdfName .DR );
88
- PdfDictionary dict = formFrom .getPdfObject ().copyTo (documentTo , excludedKeys , false );
89
- formTo .getPdfObject ().mergeDifferent (dict );
94
+
95
+ if (formFrom == null ) {
96
+ return ;
90
97
}
91
98
92
- if (formFrom != null ) {
93
- Map <String , PdfFormField > fieldsFrom = formFrom .getFormFields ();
94
- if (fieldsFrom .size () > 0 ) {
95
- Map <String , PdfFormField > fieldsTo = formTo .getFormFields ();
96
- List <PdfAnnotation > annots = toPage .getAnnotations ();
97
- for (PdfAnnotation annot : annots ) {
98
- if (annot .getSubtype ().equals (PdfName .Widget )) {
99
- PdfDictionary parent = annot .getPdfObject ().getAsDictionary (PdfName .Parent );
100
- if (parent != null ) {
101
- PdfFormField parentField = getParentField (parent , documentTo );
102
- PdfString parentName = parentField .getFieldName ();
103
- if (parentName == null ) {
104
- continue ;
105
- }
106
- if (!fieldsTo .containsKey (parentName .toUnicodeString ())) {
107
- PdfFormField field = createParentFieldCopy (annot .getPdfObject (), documentTo );
108
- PdfArray kids = field .getKids ();
109
- field .getPdfObject ().remove (PdfName .Kids );
110
- formTo .addField (field , toPage );
111
- field .getPdfObject ().put (PdfName .Kids , kids );
112
- } else {
113
- PdfFormField field = PdfFormField .makeFormField (annot .getPdfObject (), documentTo );
114
- PdfString fieldName = field .getFieldName ();
115
- if (fieldName != null ) {
116
- PdfFormField existingField = fieldsTo .get (fieldName .toUnicodeString ());
117
- if (existingField != null ) {
118
- PdfFormField clonedField = PdfFormField .makeFormField (field .getPdfObject ().clone ().makeIndirect (documentTo ), documentTo );
119
- toPage .getPdfObject ().getAsArray (PdfName .Annots ).add (clonedField .getPdfObject ());
120
- toPage .removeAnnotation (annot );
121
- mergeFieldsWithTheSameName (clonedField );
122
- } else {
123
- HashSet <String > existingFields = new HashSet <>();
124
- getAllFieldNames (formTo .getFields (), existingFields );
125
- addChildToExistingParent (annot .getPdfObject (), existingFields );
126
- }
127
- } else {
128
- if (!parentField .getKids ().contains (field .getPdfObject ())) {
129
- HashSet <String > existingFields = new HashSet <>();
130
- getAllFieldNames (formTo .getFields (), existingFields );
131
- addChildToExistingParent (annot .getPdfObject (), existingFields );
132
- }
133
- }
134
- }
135
- } else {
136
- PdfString annotName = annot .getPdfObject ().getAsString (PdfName .T );
137
- String annotNameString = null ;
138
- if (annotName != null ) {
139
- annotNameString = annotName .toUnicodeString ();
140
- }
141
- if (annotNameString != null && fieldsFrom .containsKey (annotNameString )) {
142
- PdfFormField field = fieldsTo .get (annotNameString );
143
- if (field != null ) {
144
- PdfDictionary clonedAnnot = (PdfDictionary ) annot .getPdfObject ().clone ().makeIndirect (documentTo );
145
- toPage .getPdfObject ().getAsArray (PdfName .Annots ).add (clonedAnnot );
146
- toPage .removeAnnotation (annot );
147
- field = mergeFieldsWithTheSameName (PdfFormField .makeFormField (clonedAnnot , toPage .getDocument ()));
148
-
149
- logger .warn (MessageFormatUtil .format (LogMessageConstant .DOCUMENT_ALREADY_HAS_FIELD , annotNameString ));
150
- PdfArray kids = field .getKids ();
151
- if (kids != null ) {
152
- field .getPdfObject ().remove (PdfName .Kids );
153
- formTo .addField (field , toPage );
154
- field .getPdfObject ().put (PdfName .Kids , kids );
155
- } else {
156
- formTo .addField (field , toPage );
157
- }
158
- } else {
159
- formTo .addField (PdfFormField .makeFormField (annot .getPdfObject (), documentTo ), null );
160
- }
161
- }
162
- }
163
- }
99
+ //duplicate AcroForm dictionary
100
+ List <PdfName > excludedKeys = new ArrayList <>();
101
+ excludedKeys .add (PdfName .Fields );
102
+ excludedKeys .add (PdfName .DR );
103
+
104
+ PdfDictionary dict = formFrom .getPdfObject ().copyTo (documentTo , excludedKeys , false );
105
+ formTo .getPdfObject ().mergeDifferent (dict );
106
+
107
+ Map <String , PdfFormField > fieldsFrom = formFrom .getFormFields ();
108
+ if (fieldsFrom .size () <= 0 ) {
109
+ return ;
110
+ }
111
+ Map <String , PdfFormField > fieldsTo = formTo .getFormFields ();
112
+
113
+ List <PdfAnnotation > annots = toPage .getAnnotations ();
114
+
115
+ for (PdfAnnotation annot : annots ) {
116
+ if (!annot .getSubtype ().equals (PdfName .Widget )) {
117
+ continue ;
118
+ }
119
+ copyField (toPage , fieldsFrom , fieldsTo , annot );
120
+ }
121
+ }
122
+
123
+ private void copyField (PdfPage toPage , Map <String , PdfFormField > fieldsFrom ,
124
+ Map <String , PdfFormField > fieldsTo , PdfAnnotation currentAnnot ) {
125
+ PdfDictionary parent = currentAnnot .getPdfObject ().getAsDictionary (PdfName .Parent );
126
+ if (parent != null ) {
127
+ PdfFormField parentField = getParentField (parent , documentTo );
128
+ PdfString parentName = parentField .getFieldName ();
129
+ if (parentName == null ) {
130
+ return ;
131
+ }
132
+ copyParentFormField (toPage , fieldsTo , currentAnnot , parentField );
133
+ } else {
134
+ PdfString annotName = currentAnnot .getPdfObject ().getAsString (PdfName .T );
135
+ String annotNameString = null ;
136
+ if (annotName != null ) {
137
+ annotNameString = annotName .toUnicodeString ();
138
+ }
139
+ if (annotNameString != null && fieldsFrom .containsKey (annotNameString )) {
140
+ PdfFormField field = fieldsTo .get (annotNameString );
141
+ if (field == null ) {
142
+ formTo .addField (PdfFormField .makeFormField (currentAnnot .getPdfObject (), documentTo ), null );
143
+ } else {
144
+ copyExistingField (toPage , currentAnnot , annotNameString );
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ private void copyExistingField (PdfPage toPage , PdfAnnotation currentAnnot , String annotNameString ) {
151
+ PdfFormField field ;
152
+ PdfDictionary clonedAnnot = (PdfDictionary ) currentAnnot .getPdfObject ().clone ().makeIndirect (documentTo );
153
+ toPage .getPdfObject ().getAsArray (PdfName .Annots ).add (clonedAnnot );
154
+ toPage .removeAnnotation (currentAnnot );
155
+ field = mergeFieldsWithTheSameName (PdfFormField .makeFormField (clonedAnnot , toPage .getDocument ()));
156
+
157
+ logger .warn (MessageFormatUtil .format (LogMessageConstant .DOCUMENT_ALREADY_HAS_FIELD , annotNameString ));
158
+ PdfArray kids = field .getKids ();
159
+ if (kids != null ) {
160
+ field .getPdfObject ().remove (PdfName .Kids );
161
+ formTo .addField (field , toPage );
162
+ field .getPdfObject ().put (PdfName .Kids , kids );
163
+ } else {
164
+ formTo .addField (field , toPage );
165
+ }
166
+ }
167
+
168
+ private void copyParentFormField (PdfPage toPage , Map <String , PdfFormField > fieldsTo ,
169
+ PdfAnnotation annot , PdfFormField parentField ) {
170
+ PdfString parentName = parentField .getFieldName ();
171
+ if (!fieldsTo .containsKey (parentName .toUnicodeString ())) {
172
+ PdfFormField field = createParentFieldCopy (annot .getPdfObject (), documentTo );
173
+ PdfArray kids = field .getKids ();
174
+ field .getPdfObject ().remove (PdfName .Kids );
175
+ formTo .addField (field , toPage );
176
+ field .getPdfObject ().put (PdfName .Kids , kids );
177
+ } else {
178
+ PdfFormField field = PdfFormField .makeFormField (annot .getPdfObject (), documentTo );
179
+ PdfString fieldName = field .getFieldName ();
180
+ if (fieldName != null ) {
181
+ PdfFormField existingField = fieldsTo .get (fieldName .toUnicodeString ());
182
+ if (existingField != null ) {
183
+ PdfFormField clonedField = PdfFormField .makeFormField (field .getPdfObject ().clone ().makeIndirect (documentTo ), documentTo );
184
+ toPage .getPdfObject ().getAsArray (PdfName .Annots ).add (clonedField .getPdfObject ());
185
+ toPage .removeAnnotation (annot );
186
+ mergeFieldsWithTheSameName (clonedField );
187
+ } else {
188
+ HashSet <String > existingFields = new HashSet <>();
189
+ getAllFieldNames (formTo .getFields (), existingFields );
190
+ addChildToExistingParent (annot .getPdfObject (), existingFields ,
191
+ fieldsTo , toPage , annot );
192
+ }
193
+ } else {
194
+ if (!parentField .getKids ().contains (field .getPdfObject ())) {
195
+ HashSet <String > existingFields = new HashSet <>();
196
+ getAllFieldNames (formTo .getFields (), existingFields );
197
+ addChildToExistingParent (annot .getPdfObject (), existingFields );
164
198
}
165
199
}
166
200
}
@@ -177,7 +211,7 @@ private PdfFormField mergeFieldsWithTheSameName(PdfFormField newField) {
177
211
index ++;
178
212
newField .setFieldName (fieldName .toUnicodeString () + "_#" + index );
179
213
fullFieldName = newField .getFieldName ().toUnicodeString ();
180
- } while (formTo .getField (fullFieldName ) != null );
214
+ } while (formTo .getField (fullFieldName ) != null );
181
215
return newField ;
182
216
}
183
217
newField .getPdfObject ().remove (PdfName .T );
@@ -217,7 +251,6 @@ private PdfFormField mergeFieldsWithTheSameName(PdfFormField newField) {
217
251
if (value != null ) {
218
252
mergedField .put (PdfName .V , existingField .getPdfObject ().get (PdfName .V ));
219
253
}
220
-
221
254
return mergedField ;
222
255
}
223
256
@@ -233,21 +266,28 @@ private PdfFormField getParentField(PdfDictionary parent, PdfDocument pdfDoc) {
233
266
}
234
267
235
268
private PdfFormField createParentFieldCopy (PdfDictionary fieldDic , PdfDocument pdfDoc ) {
236
- fieldDic .remove (PdfName .Kids );
237
-
238
269
PdfDictionary parent = fieldDic .getAsDictionary (PdfName .Parent );
239
270
PdfFormField field = PdfFormField .makeFormField (fieldDic , pdfDoc );
240
271
241
272
if (parent != null ) {
242
273
field = createParentFieldCopy (parent , pdfDoc );
243
- parent .put (PdfName .Kids , new PdfArray (fieldDic ));
274
+ PdfArray kids = (PdfArray ) parent .get (PdfName .Kids );
275
+ if (kids == null ) {
276
+ parent .put (PdfName .Kids , new PdfArray (fieldDic ));
277
+ } else {
278
+ kids .add (fieldDic );
279
+ }
244
280
}
245
281
246
282
return field ;
247
283
}
248
284
249
285
private void addChildToExistingParent (PdfDictionary fieldDic , Set <String > existingFields ) {
250
286
PdfDictionary parent = fieldDic .getAsDictionary (PdfName .Parent );
287
+ if (parent == null ) {
288
+ return ;
289
+ }
290
+
251
291
PdfString parentName = parent .getAsString (PdfName .T );
252
292
if (parentName != null ) {
253
293
String name = parentName .toUnicodeString ();
@@ -261,6 +301,37 @@ private void addChildToExistingParent(PdfDictionary fieldDic, Set<String> existi
261
301
}
262
302
}
263
303
304
+ private void addChildToExistingParent (PdfDictionary fieldDic , Set <String > existingFields ,
305
+ Map <String , PdfFormField > fieldsTo ,
306
+ PdfPage toPage , PdfAnnotation annot ) {
307
+ PdfDictionary parent = fieldDic .getAsDictionary (PdfName .Parent );
308
+ if (parent == null ) {
309
+ return ;
310
+ }
311
+
312
+ PdfString parentName = parent .getAsString (PdfName .T );
313
+ if (parentName != null ) {
314
+ String name = parentName .toUnicodeString ();
315
+ if (existingFields .contains (name )) {
316
+ PdfArray kids = parent .getAsArray (PdfName .Kids );
317
+ for (PdfObject kid : kids ) {
318
+ if (((PdfDictionary ) kid ).get (PdfName .T ).equals (fieldDic .get (PdfName .T ))) {
319
+ PdfFormField kidField = PdfFormField .makeFormField (kid , documentTo );
320
+ fieldsTo .put (kidField .getFieldName ().toUnicodeString (), kidField );
321
+ logger .warn (MessageFormatUtil .format (LogMessageConstant .DOCUMENT_ALREADY_HAS_FIELD ,
322
+ kidField .getFieldName ().toUnicodeString ()));
323
+ mergeFieldsWithTheSameName (PdfFormField .makeFormField (fieldDic , documentTo ));
324
+ return ;
325
+ }
326
+ }
327
+ kids .add (fieldDic );
328
+ } else {
329
+ parent .put (PdfName .Kids , new PdfArray (fieldDic ));
330
+ addChildToExistingParent (parent , existingFields );
331
+ }
332
+ }
333
+ }
334
+
264
335
private void getAllFieldNames (PdfArray fields , Set <String > existingFields ) {
265
336
for (PdfObject field : fields ) {
266
337
if (field .isFlushed ()) {
0 commit comments