@@ -57,6 +57,8 @@ namespace iText.Forms {
5757 /// <remarks>
5858 /// A sample implementation of the {#link IPdfPageExtraCopier} interface which
5959 /// copies only AcroForm fields to a new page.
60+ /// <p>
61+ /// <p>
6062 /// NOTE: While it's absolutely not necessary to use the same PdfPageFormCopier instance for copying operations,
6163 /// it is still worth to know that PdfPageFormCopier uses some caching logic which can potentially improve performance
6264 /// in case of the reusing of the same instance.
@@ -81,93 +83,110 @@ public virtual void Copy(PdfPage fromPage, PdfPage toPage) {
8183 documentTo = toPage . GetDocument ( ) ;
8284 formTo = PdfAcroForm . GetAcroForm ( documentTo , true ) ;
8385 }
84- if ( formFrom != null ) {
85- //duplicate AcroForm dictionary
86- IList < PdfName > excludedKeys = new List < PdfName > ( ) ;
87- excludedKeys . Add ( PdfName . Fields ) ;
88- excludedKeys . Add ( PdfName . DR ) ;
89- PdfDictionary dict = formFrom . GetPdfObject ( ) . CopyTo ( documentTo , excludedKeys , false ) ;
90- formTo . GetPdfObject ( ) . MergeDifferent ( dict ) ;
86+ if ( formFrom == null ) {
87+ return ;
9188 }
92- if ( formFrom != null ) {
93- IDictionary < String , PdfFormField > fieldsFrom = formFrom . GetFormFields ( ) ;
94- if ( fieldsFrom . Count > 0 ) {
95- IDictionary < String , PdfFormField > fieldsTo = formTo . GetFormFields ( ) ;
96- IList < PdfAnnotation > annots = toPage . GetAnnotations ( ) ;
97- foreach ( PdfAnnotation annot in 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- }
113- else {
114- PdfFormField field = PdfFormField . MakeFormField ( annot . GetPdfObject ( ) , documentTo ) ;
115- PdfString fieldName = field . GetFieldName ( ) ;
116- if ( fieldName != null ) {
117- PdfFormField existingField = fieldsTo . Get ( fieldName . ToUnicodeString ( ) ) ;
118- if ( existingField != null ) {
119- PdfFormField clonedField = PdfFormField . MakeFormField ( field . GetPdfObject ( ) . Clone ( ) . MakeIndirect ( documentTo
120- ) , documentTo ) ;
121- toPage . GetPdfObject ( ) . GetAsArray ( PdfName . Annots ) . Add ( clonedField . GetPdfObject ( ) ) ;
122- toPage . RemoveAnnotation ( annot ) ;
123- MergeFieldsWithTheSameName ( clonedField ) ;
124- }
125- else {
126- HashSet < String > existingFields = new HashSet < String > ( ) ;
127- GetAllFieldNames ( formTo . GetFields ( ) , existingFields ) ;
128- AddChildToExistingParent ( annot . GetPdfObject ( ) , existingFields ) ;
129- }
130- }
131- else {
132- if ( ! parentField . GetKids ( ) . Contains ( field . GetPdfObject ( ) ) ) {
133- HashSet < String > existingFields = new HashSet < String > ( ) ;
134- GetAllFieldNames ( formTo . GetFields ( ) , existingFields ) ;
135- AddChildToExistingParent ( annot . GetPdfObject ( ) , existingFields ) ;
136- }
137- }
138- }
139- }
140- else {
141- PdfString annotName = annot . GetPdfObject ( ) . GetAsString ( PdfName . T ) ;
142- String annotNameString = null ;
143- if ( annotName != null ) {
144- annotNameString = annotName . ToUnicodeString ( ) ;
145- }
146- if ( annotNameString != null && fieldsFrom . ContainsKey ( annotNameString ) ) {
147- PdfFormField field = fieldsTo . Get ( annotNameString ) ;
148- if ( field != null ) {
149- PdfDictionary clonedAnnot = ( PdfDictionary ) annot . GetPdfObject ( ) . Clone ( ) . MakeIndirect ( documentTo ) ;
150- toPage . GetPdfObject ( ) . GetAsArray ( PdfName . Annots ) . Add ( clonedAnnot ) ;
151- toPage . RemoveAnnotation ( annot ) ;
152- field = MergeFieldsWithTheSameName ( PdfFormField . MakeFormField ( clonedAnnot , toPage . GetDocument ( ) ) ) ;
153- logger . Warn ( MessageFormatUtil . Format ( iText . IO . LogMessageConstant . DOCUMENT_ALREADY_HAS_FIELD , annotNameString
154- ) ) ;
155- PdfArray kids = field . GetKids ( ) ;
156- if ( kids != null ) {
157- field . GetPdfObject ( ) . Remove ( PdfName . Kids ) ;
158- formTo . AddField ( field , toPage ) ;
159- field . GetPdfObject ( ) . Put ( PdfName . Kids , kids ) ;
160- }
161- else {
162- formTo . AddField ( field , toPage ) ;
163- }
164- }
165- else {
166- formTo . AddField ( PdfFormField . MakeFormField ( annot . GetPdfObject ( ) , documentTo ) , null ) ;
167- }
168- }
169- }
170- }
89+ //duplicate AcroForm dictionary
90+ IList < PdfName > excludedKeys = new List < PdfName > ( ) ;
91+ excludedKeys . Add ( PdfName . Fields ) ;
92+ excludedKeys . Add ( PdfName . DR ) ;
93+ PdfDictionary dict = formFrom . GetPdfObject ( ) . CopyTo ( documentTo , excludedKeys , false ) ;
94+ formTo . GetPdfObject ( ) . MergeDifferent ( dict ) ;
95+ IDictionary < String , PdfFormField > fieldsFrom = formFrom . GetFormFields ( ) ;
96+ if ( fieldsFrom . Count <= 0 ) {
97+ return ;
98+ }
99+ IDictionary < String , PdfFormField > fieldsTo = formTo . GetFormFields ( ) ;
100+ IList < PdfAnnotation > annots = toPage . GetAnnotations ( ) ;
101+ foreach ( PdfAnnotation annot in annots ) {
102+ if ( ! annot . GetSubtype ( ) . Equals ( PdfName . Widget ) ) {
103+ continue ;
104+ }
105+ CopyField ( toPage , fieldsFrom , fieldsTo , annot ) ;
106+ }
107+ }
108+
109+ private void CopyField ( PdfPage toPage , IDictionary < String , PdfFormField > fieldsFrom , IDictionary < String , PdfFormField
110+ > fieldsTo , PdfAnnotation currentAnnot ) {
111+ PdfDictionary parent = currentAnnot . GetPdfObject ( ) . GetAsDictionary ( PdfName . Parent ) ;
112+ if ( parent != null ) {
113+ PdfFormField parentField = GetParentField ( parent , documentTo ) ;
114+ PdfString parentName = parentField . GetFieldName ( ) ;
115+ if ( parentName == null ) {
116+ return ;
117+ }
118+ CopyParentFormField ( toPage , fieldsTo , currentAnnot , parentField ) ;
119+ }
120+ else {
121+ PdfString annotName = currentAnnot . GetPdfObject ( ) . GetAsString ( PdfName . T ) ;
122+ String annotNameString = null ;
123+ if ( annotName != null ) {
124+ annotNameString = annotName . ToUnicodeString ( ) ;
125+ }
126+ if ( annotNameString != null && fieldsFrom . ContainsKey ( annotNameString ) ) {
127+ PdfFormField field = fieldsTo . Get ( annotNameString ) ;
128+ if ( field == null ) {
129+ formTo . AddField ( PdfFormField . MakeFormField ( currentAnnot . GetPdfObject ( ) , documentTo ) , null ) ;
130+ }
131+ else {
132+ CopyExistingField ( toPage , currentAnnot , annotNameString ) ;
133+ }
134+ }
135+ }
136+ }
137+
138+ private void CopyExistingField ( PdfPage toPage , PdfAnnotation currentAnnot , String annotNameString ) {
139+ PdfFormField field ;
140+ PdfDictionary clonedAnnot = ( PdfDictionary ) currentAnnot . GetPdfObject ( ) . Clone ( ) . MakeIndirect ( documentTo ) ;
141+ toPage . GetPdfObject ( ) . GetAsArray ( PdfName . Annots ) . Add ( clonedAnnot ) ;
142+ toPage . RemoveAnnotation ( currentAnnot ) ;
143+ field = MergeFieldsWithTheSameName ( PdfFormField . MakeFormField ( clonedAnnot , toPage . GetDocument ( ) ) ) ;
144+ logger . Warn ( MessageFormatUtil . Format ( iText . IO . LogMessageConstant . DOCUMENT_ALREADY_HAS_FIELD , annotNameString
145+ ) ) ;
146+ PdfArray kids = field . GetKids ( ) ;
147+ if ( kids != null ) {
148+ field . GetPdfObject ( ) . Remove ( PdfName . Kids ) ;
149+ formTo . AddField ( field , toPage ) ;
150+ field . GetPdfObject ( ) . Put ( PdfName . Kids , kids ) ;
151+ }
152+ else {
153+ formTo . AddField ( field , toPage ) ;
154+ }
155+ }
156+
157+ private void CopyParentFormField ( PdfPage toPage , IDictionary < String , PdfFormField > fieldsTo , PdfAnnotation
158+ annot , PdfFormField parentField ) {
159+ PdfString parentName = parentField . GetFieldName ( ) ;
160+ if ( ! fieldsTo . ContainsKey ( parentName . ToUnicodeString ( ) ) ) {
161+ PdfFormField field = CreateParentFieldCopy ( annot . GetPdfObject ( ) , documentTo ) ;
162+ PdfArray kids = field . GetKids ( ) ;
163+ field . GetPdfObject ( ) . Remove ( PdfName . Kids ) ;
164+ formTo . AddField ( field , toPage ) ;
165+ field . GetPdfObject ( ) . Put ( PdfName . Kids , kids ) ;
166+ }
167+ else {
168+ PdfFormField field = PdfFormField . MakeFormField ( annot . GetPdfObject ( ) , documentTo ) ;
169+ PdfString fieldName = field . GetFieldName ( ) ;
170+ if ( fieldName != null ) {
171+ PdfFormField existingField = fieldsTo . Get ( fieldName . ToUnicodeString ( ) ) ;
172+ if ( existingField != null ) {
173+ PdfFormField clonedField = PdfFormField . MakeFormField ( field . GetPdfObject ( ) . Clone ( ) . MakeIndirect ( documentTo
174+ ) , documentTo ) ;
175+ toPage . GetPdfObject ( ) . GetAsArray ( PdfName . Annots ) . Add ( clonedField . GetPdfObject ( ) ) ;
176+ toPage . RemoveAnnotation ( annot ) ;
177+ MergeFieldsWithTheSameName ( clonedField ) ;
178+ }
179+ else {
180+ HashSet < String > existingFields = new HashSet < String > ( ) ;
181+ GetAllFieldNames ( formTo . GetFields ( ) , existingFields ) ;
182+ AddChildToExistingParent ( annot . GetPdfObject ( ) , existingFields , fieldsTo , toPage , annot ) ;
183+ }
184+ }
185+ else {
186+ if ( ! parentField . GetKids ( ) . Contains ( field . GetPdfObject ( ) ) ) {
187+ HashSet < String > existingFields = new HashSet < String > ( ) ;
188+ GetAllFieldNames ( formTo . GetFields ( ) , existingFields ) ;
189+ AddChildToExistingParent ( annot . GetPdfObject ( ) , existingFields ) ;
171190 }
172191 }
173192 }
@@ -233,18 +252,26 @@ private PdfFormField GetParentField(PdfDictionary parent, PdfDocument pdfDoc) {
233252 }
234253
235254 private PdfFormField CreateParentFieldCopy ( PdfDictionary fieldDic , PdfDocument pdfDoc ) {
236- fieldDic . Remove ( PdfName . Kids ) ;
237255 PdfDictionary parent = fieldDic . GetAsDictionary ( PdfName . Parent ) ;
238256 PdfFormField field = PdfFormField . MakeFormField ( fieldDic , pdfDoc ) ;
239257 if ( parent != null ) {
240258 field = CreateParentFieldCopy ( parent , pdfDoc ) ;
241- parent . Put ( PdfName . Kids , new PdfArray ( fieldDic ) ) ;
259+ PdfArray kids = ( PdfArray ) parent . Get ( PdfName . Kids ) ;
260+ if ( kids == null ) {
261+ parent . Put ( PdfName . Kids , new PdfArray ( fieldDic ) ) ;
262+ }
263+ else {
264+ kids . Add ( fieldDic ) ;
265+ }
242266 }
243267 return field ;
244268 }
245269
246270 private void AddChildToExistingParent ( PdfDictionary fieldDic , ICollection < String > existingFields ) {
247271 PdfDictionary parent = fieldDic . GetAsDictionary ( PdfName . Parent ) ;
272+ if ( parent == null ) {
273+ return ;
274+ }
248275 PdfString parentName = parent . GetAsString ( PdfName . T ) ;
249276 if ( parentName != null ) {
250277 String name = parentName . ToUnicodeString ( ) ;
@@ -259,6 +286,36 @@ private void AddChildToExistingParent(PdfDictionary fieldDic, ICollection<String
259286 }
260287 }
261288
289+ private void AddChildToExistingParent ( PdfDictionary fieldDic , ICollection < String > existingFields , IDictionary
290+ < String , PdfFormField > fieldsTo , PdfPage toPage , PdfAnnotation annot ) {
291+ PdfDictionary parent = fieldDic . GetAsDictionary ( PdfName . Parent ) ;
292+ if ( parent == null ) {
293+ return ;
294+ }
295+ PdfString parentName = parent . GetAsString ( PdfName . T ) ;
296+ if ( parentName != null ) {
297+ String name = parentName . ToUnicodeString ( ) ;
298+ if ( existingFields . Contains ( name ) ) {
299+ PdfArray kids = parent . GetAsArray ( PdfName . Kids ) ;
300+ foreach ( PdfObject kid in kids ) {
301+ if ( ( ( PdfDictionary ) kid ) . Get ( PdfName . T ) . Equals ( fieldDic . Get ( PdfName . T ) ) ) {
302+ PdfFormField kidField = PdfFormField . MakeFormField ( kid , documentTo ) ;
303+ fieldsTo . Put ( kidField . GetFieldName ( ) . ToUnicodeString ( ) , kidField ) ;
304+ logger . Warn ( MessageFormatUtil . Format ( iText . IO . LogMessageConstant . DOCUMENT_ALREADY_HAS_FIELD , kidField . GetFieldName
305+ ( ) . ToUnicodeString ( ) ) ) ;
306+ MergeFieldsWithTheSameName ( PdfFormField . MakeFormField ( fieldDic , documentTo ) ) ;
307+ return ;
308+ }
309+ }
310+ kids . Add ( fieldDic ) ;
311+ }
312+ else {
313+ parent . Put ( PdfName . Kids , new PdfArray ( fieldDic ) ) ;
314+ AddChildToExistingParent ( parent , existingFields ) ;
315+ }
316+ }
317+ }
318+
262319 private void GetAllFieldNames ( PdfArray fields , ICollection < String > existingFields ) {
263320 foreach ( PdfObject field in fields ) {
264321 if ( field . IsFlushed ( ) ) {
0 commit comments