Skip to content

Commit 1748f09

Browse files
committed
Syncronize DA and DR. Retrieve FormField's font.
The key idea is that DA and appearance stream may have different names in resources. Simplify resource merging with regenerating default appearance and default resources during coping. Initialize FormFields's PdfFont and fontsize in constructor. PdfPageFormCopier won't keep existing DA and will regenerate it based on given properties. Replace getPdfObject().put() with just put(), it will set modified state. Remove redundant private methods in PdfAcroForm and PdfFormField. Set autosize for checkbox, keep DA for push buttons and choice fields. DEVSIX-2875 DEVSIX-2016
1 parent 8656090 commit 1748f09

File tree

94 files changed

+699
-757
lines changed

Some content is hidden

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

94 files changed

+699
-757
lines changed

barcodes/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
33
<modelVersion>4.0.0</modelVersion>
4+
45
<parent>
56
<groupId>com.itextpdf</groupId>
67
<artifactId>root</artifactId>
78
<version>7.1.7-SNAPSHOT</version>
89
</parent>
10+
911
<artifactId>barcodes</artifactId>
12+
1013
<name>iText 7 - barcodes</name>
1114
<url>https://itextpdf.com/</url>
15+
1216
<dependencies>
1317
<dependency>
1418
<groupId>com.itextpdf</groupId>
@@ -22,6 +26,7 @@
2226
<scope>test</scope>
2327
</dependency>
2428
</dependencies>
29+
2530
<build>
2631
<plugins>
2732
<plugin>

font-asian/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
33
<modelVersion>4.0.0</modelVersion>
4+
45
<parent>
56
<groupId>com.itextpdf</groupId>
67
<artifactId>root</artifactId>
78
<version>7.1.7-SNAPSHOT</version>
89
</parent>
10+
911
<artifactId>font-asian</artifactId>
12+
1013
<name>iText 7 - Asian fonts</name>
1114
<description>iText Asian fonts for use in conjunction with iText 7, a free Java-PDF library</description>
1215
<url>https://itextpdf.com/</url>
@@ -15,6 +18,7 @@
1518
<name>Various licenses (see individual files)</name>
1619
</license>
1720
</licenses>
21+
1822
<build>
1923
<plugins>
2024
<plugin>

forms/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
33
<modelVersion>4.0.0</modelVersion>
4+
45
<parent>
56
<groupId>com.itextpdf</groupId>
67
<artifactId>root</artifactId>
78
<version>7.1.7-SNAPSHOT</version>
89
</parent>
10+
911
<artifactId>forms</artifactId>
12+
1013
<name>iText 7 - forms</name>
1114
<url>https://itextpdf.com/</url>
15+
1216
<dependencies>
1317
<dependency>
1418
<groupId>com.itextpdf</groupId>
@@ -20,6 +24,12 @@
2024
<artifactId>layout</artifactId>
2125
<version>${project.version}</version>
2226
</dependency>
27+
<dependency>
28+
<groupId>com.itextpdf</groupId>
29+
<artifactId>font-asian</artifactId>
30+
<version>${project.version}</version>
31+
<scope>test</scope>
32+
</dependency>
2333
<dependency>
2434
<groupId>com.itextpdf</groupId>
2535
<artifactId>pdftest</artifactId>
@@ -41,6 +51,7 @@
4151
<optional>true</optional>
4252
</dependency>
4353
</dependencies>
54+
4455
<build>
4556
<plugins>
4657
<plugin>

forms/src/main/java/com/itextpdf/forms/PdfAcroForm.java

Lines changed: 49 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,16 @@ This file is part of the iText (R) project.
6969
import com.itextpdf.kernel.pdf.tagutils.TagReference;
7070
import com.itextpdf.kernel.pdf.tagutils.TagTreePointer;
7171
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
72+
import org.slf4j.Logger;
73+
import org.slf4j.LoggerFactory;
7274

73-
import java.util.ArrayList;
7475
import java.util.Collection;
7576
import java.util.Collections;
7677
import java.util.LinkedHashMap;
7778
import java.util.LinkedHashSet;
78-
import java.util.List;
7979
import java.util.Map;
8080
import java.util.Set;
8181

82-
import org.slf4j.Logger;
83-
import org.slf4j.LoggerFactory;
84-
8582
/**
8683
* This class represents the static form technology AcroForm on a PDF file.
8784
*/
@@ -134,10 +131,10 @@ public class PdfAcroForm extends PdfObjectWrapper<PdfDictionary> {
134131
*/
135132
protected PdfDocument document;
136133

137-
private static PdfName[] resourceNames = {PdfName.Font, PdfName.XObject, PdfName.ColorSpace, PdfName.Pattern};
138134
private PdfDictionary defaultResources;
139135
private Set<PdfFormField> fieldsForFlattening = new LinkedHashSet<>();
140136
private XfaForm xfaForm;
137+
private static Logger logger = LoggerFactory.getLogger(PdfAcroForm.class);
141138

142139
/**
143140
* Creates a PdfAcroForm as a wrapper of a dictionary.
@@ -235,17 +232,6 @@ public void addField(PdfFormField field, PdfPage page) {
235232
iterateFields(field.getKids(), fields);
236233
}
237234

238-
//There's an issue described in DEVSIX-573. When you create multiple fields with different fonts those font may
239-
// have same names (F1, F2, etc). So only first of them will be save in default resources.
240-
if (field.getFormType() != null && (field.getFormType().equals(PdfName.Tx) || field.getFormType().equals(PdfName.Ch))) {
241-
List<PdfDictionary> resources = getResources(field.getPdfObject());
242-
for (PdfDictionary resDict : resources) {
243-
mergeResources(defaultResources, resDict);
244-
}
245-
if (!defaultResources.isEmpty()) {
246-
put(PdfName.DR, defaultResources);
247-
}
248-
}
249235
if (fieldDic.containsKey(PdfName.Subtype) && page != null) {
250236
PdfAnnotation annot = PdfAnnotation.makeAnnotation(fieldDic);
251237
addWidgetAnnotationToPage(page, annot);
@@ -285,7 +271,6 @@ public void addFieldAppearanceToPage(PdfFormField field, PdfPage page) {
285271
public Map<String, PdfFormField> getFormFields() {
286272
if (fields.size() == 0) {
287273
fields = iterateFields(getFields());
288-
289274
}
290275
return fields;
291276
}
@@ -647,7 +632,7 @@ public void flattenFields() {
647632
initialPageResourceClones.put(i, resources == null ? null : resources.clone());
648633
}
649634

650-
Set<PdfPage> wrappedPages = new LinkedHashSet<PdfPage>();
635+
Set<PdfPage> wrappedPages = new LinkedHashSet<>();
651636
PdfPage page;
652637
for (PdfFormField field : fields) {
653638
PdfDictionary fieldObject = field.getPdfObject();
@@ -676,58 +661,54 @@ public void flattenFields() {
676661
appDic = fieldObject.getAsDictionary(PdfName.AP);
677662
}
678663
}
679-
if (null != appDic) {
680-
PdfObject normal = appDic.get(PdfName.N);
681-
if (null == normal) {
682-
Logger logger = LoggerFactory.getLogger(PdfAcroForm.class);
683-
logger.error(LogMessageConstant.N_ENTRY_IS_REQUIRED_FOR_APPEARANCE_DICTIONARY);
684-
} else {
685-
PdfFormXObject xObject = null;
686-
if (normal.isStream()) {
687-
xObject = new PdfFormXObject((PdfStream) normal);
688-
} else if (normal.isDictionary()) {
689-
PdfName as = fieldObject.getAsName(PdfName.AS);
690-
if (((PdfDictionary) normal).getAsStream(as) != null) {
691-
xObject = new PdfFormXObject(((PdfDictionary) normal).getAsStream(as));
692-
xObject.makeIndirect(document);
693-
}
664+
PdfObject normal = appDic != null ? appDic.get(PdfName.N) : null;
665+
if (null != normal) {
666+
PdfFormXObject xObject = null;
667+
if (normal.isStream()) {
668+
xObject = new PdfFormXObject((PdfStream) normal);
669+
} else if (normal.isDictionary()) {
670+
PdfName as = fieldObject.getAsName(PdfName.AS);
671+
if (((PdfDictionary) normal).getAsStream(as) != null) {
672+
xObject = new PdfFormXObject(((PdfDictionary) normal).getAsStream(as));
673+
xObject.makeIndirect(document);
694674
}
675+
}
676+
677+
if (xObject != null) {
678+
//subtype is required field for FormXObject, but can be omitted in normal appearance.
679+
xObject.put(PdfName.Subtype, PdfName.Form);
680+
Rectangle annotBBox = fieldObject.getAsRectangle(PdfName.Rect);
681+
if (page.isFlushed()) {
682+
throw new PdfException(PdfException.PageAlreadyFlushedUseAddFieldAppearanceToPageMethodBeforePageFlushing);
683+
}
684+
PdfCanvas canvas = new PdfCanvas(page, !wrappedPages.contains(page));
685+
wrappedPages.add(page);
686+
687+
// Here we avoid circular reference which might occur when page resources and the appearance xObject's
688+
// resources are the same object
689+
PdfObject xObjectResources = xObject.getPdfObject().get(PdfName.Resources);
690+
PdfObject pageResources = page.getResources().getPdfObject();
691+
if (xObjectResources != null && xObjectResources == pageResources) {
692+
xObject.getPdfObject().put(PdfName.Resources, initialPageResourceClones.get(document.getPageNumber(page)));
693+
}
694+
695+
if (tagPointer != null) {
696+
tagPointer.setPageForTagging(page);
697+
TagReference tagRef = tagPointer.getTagReference();
698+
canvas.openTag(tagRef);
699+
}
700+
701+
AffineTransform at = calcFieldAppTransformToAnnotRect(xObject, annotBBox);
702+
float[] m = new float[6];
703+
at.getMatrix(m);
704+
canvas.addXObject(xObject, m[0], m[1], m[2], m[3], m[4], m[5]);
695705

696-
if (xObject != null) {
697-
//subtype is required field for FormXObject, but can be omitted in normal appearance.
698-
xObject.put(PdfName.Subtype, PdfName.Form);
699-
Rectangle annotBBox = fieldObject.getAsRectangle(PdfName.Rect);
700-
if (page.isFlushed()) {
701-
throw new PdfException(PdfException.PageAlreadyFlushedUseAddFieldAppearanceToPageMethodBeforePageFlushing);
702-
}
703-
PdfCanvas canvas = new PdfCanvas(page, !wrappedPages.contains(page));
704-
wrappedPages.add(page);
705-
706-
// Here we avoid circular reference which might occur when page resources and the appearance xObject's
707-
// resources are the same object
708-
PdfObject xObjectResources = xObject.getPdfObject().get(PdfName.Resources);
709-
PdfObject pageResources = page.getResources().getPdfObject();
710-
if (xObjectResources != null && pageResources != null &&
711-
xObjectResources == pageResources) {
712-
xObject.getPdfObject().put(PdfName.Resources, initialPageResourceClones.get(document.getPageNumber(page)));
713-
}
714-
715-
if (tagPointer != null) {
716-
tagPointer.setPageForTagging(page);
717-
TagReference tagRef = tagPointer.getTagReference();
718-
canvas.openTag(tagRef);
719-
}
720-
721-
AffineTransform at = calcFieldAppTransformToAnnotRect(xObject, annotBBox);
722-
float[] m = new float[6];
723-
at.getMatrix(m);
724-
canvas.addXObject(xObject, m[0], m[1], m[2], m[3], m[4], m[5]);
725-
726-
if (tagPointer != null) {
727-
canvas.closeTag();
728-
}
706+
if (tagPointer != null) {
707+
canvas.closeTag();
729708
}
730709
}
710+
} else {
711+
logger.error(LogMessageConstant.N_ENTRY_IS_REQUIRED_FOR_APPEARANCE_DICTIONARY);
731712
}
732713

733714
PdfArray fFields = getFields();
@@ -839,10 +820,8 @@ public void renameField(String oldName, String newName) {
839820
public PdfFormField copyField(String name) {
840821
PdfFormField oldField = getField(name);
841822
if (oldField != null) {
842-
PdfFormField field = new PdfFormField((PdfDictionary) oldField.getPdfObject().clone().makeIndirect(document));
843-
return field;
823+
return new PdfFormField((PdfDictionary) oldField.getPdfObject().clone().makeIndirect(document));
844824
}
845-
846825
return null;
847826
}
848827

@@ -866,7 +845,6 @@ public void replaceField(String name, PdfFormField field) {
866845
protected PdfArray getFields() {
867846
PdfArray fields = getPdfObject().getAsArray(PdfName.Fields);
868847
if (fields == null) {
869-
Logger logger = LoggerFactory.getLogger(PdfAcroForm.class);
870848
logger.warn(LogMessageConstant.NO_FIELDS_IN_ACROFORM);
871849
fields = new PdfArray();
872850
getPdfObject().put(PdfName.Fields, fields);
@@ -883,7 +861,6 @@ private Map<String, PdfFormField> iterateFields(PdfArray array, Map<String, PdfF
883861
int index = 1;
884862
for (PdfObject field : array) {
885863
if (field.isFlushed()) {
886-
Logger logger = LoggerFactory.getLogger(PdfAcroForm.class);
887864
logger.warn(LogMessageConstant.FORM_FIELD_WAS_FLUSHED);
888865
continue;
889866
}
@@ -987,62 +964,6 @@ private void addWidgetAnnotationToPage(PdfPage page, PdfAnnotation annot) {
987964
}
988965
}
989966

990-
private List<PdfDictionary> getResources(PdfDictionary field) {
991-
List<PdfDictionary> resources = new ArrayList<>();
992-
993-
PdfDictionary ap = field.getAsDictionary(PdfName.AP);
994-
if (ap != null && !ap.isFlushed()) {
995-
PdfObject normal = ap.get(PdfName.N);
996-
if (normal != null && !normal.isFlushed()) {
997-
if (normal.isDictionary()) {
998-
for (PdfName key : ((PdfDictionary) normal).keySet()) {
999-
PdfStream appearance = ((PdfDictionary) normal).getAsStream(key);
1000-
PdfDictionary resDict = appearance.getAsDictionary(PdfName.Resources);
1001-
if (resDict != null) {
1002-
resources.add(resDict);
1003-
break;
1004-
}
1005-
}
1006-
} else if (normal.isStream()) {
1007-
PdfDictionary resDict = ((PdfStream) normal).getAsDictionary(PdfName.Resources);
1008-
if (resDict != null) {
1009-
resources.add(resDict);
1010-
}
1011-
}
1012-
}
1013-
}
1014-
1015-
PdfArray kids = field.getAsArray(PdfName.Kids);
1016-
if (kids != null) {
1017-
for (PdfObject kid : kids) {
1018-
resources.addAll(getResources((PdfDictionary) kid));
1019-
}
1020-
}
1021-
1022-
return resources;
1023-
}
1024-
1025-
/**
1026-
* Merges two dictionaries. When both dictionaries contain the same key,
1027-
* the value from the first dictionary is kept.
1028-
*
1029-
* @param result the {@link PdfDictionary} which may get extra entries from source
1030-
* @param source the {@link PdfDictionary} whose entries may be merged into result
1031-
*/
1032-
private void mergeResources(PdfDictionary result, PdfDictionary source) {
1033-
for (PdfName name : resourceNames) {
1034-
PdfDictionary dic = source.isFlushed() ? null : source.getAsDictionary(name);
1035-
PdfDictionary res = result.getAsDictionary(name);
1036-
if (res == null) {
1037-
res = new PdfDictionary();
1038-
}
1039-
if (dic != null) {
1040-
res.mergeDifferent(dic);
1041-
result.put(name, res);
1042-
}
1043-
}
1044-
}
1045-
1046967
/**
1047968
* Determines whether the AcroForm contains XFA data.
1048969
*

0 commit comments

Comments
 (0)