Skip to content

Commit 19c3ba5

Browse files
committed
Port PdfFormField from develop
Add AppearanceResources and AppearanceXObject Those classes will save font names from default resources. Update javadoc for PdfAcroForm#setGenerateAppearance() Update PdfFormField#setDefaultAppearance() Save original font and fontSize for /DA. Do not override /DA if inherited is the same. Use font from /DA for button Actually /DA has no any sense for button. But let's keep this behaviour as backward compatibility. Fix backward compatibility issue in PdfFormField Remove redundant comparing in setDefaultAppearance DEVSIX-1916
1 parent 0be99b6 commit 19c3ba5

File tree

11 files changed

+171
-23
lines changed

11 files changed

+171
-23
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,8 @@ public boolean isGenerateAppearance() {
578578
* If generateAppearance is set to <code>true</code>, then
579579
* <code>NeedAppearances</code> is set to <code>false</code>. This does not
580580
* apply vice versa.
581+
* <p>
582+
* Note, this method does not change default behaviour of {@link PdfFormField#setValue(String)} method.
581583
*
582584
* @param generateAppearance a boolean
583585
*/
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.itextpdf.forms.fields;
2+
3+
import com.itextpdf.kernel.font.PdfFont;
4+
import com.itextpdf.kernel.pdf.PdfDictionary;
5+
import com.itextpdf.kernel.pdf.PdfDocument;
6+
import com.itextpdf.kernel.pdf.PdfIndirectReference;
7+
import com.itextpdf.kernel.pdf.PdfName;
8+
import com.itextpdf.kernel.pdf.PdfResources;
9+
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
13+
/**
14+
* AppearanceResources allows to register font names that will be used as resource name.
15+
* Preserving existed font names in default resources of AcroForm is the only goal of this class.
16+
* <p>
17+
* Shall be used only in {@link PdfFormField}.
18+
*
19+
* @see AppearanceXObject
20+
*/
21+
class AppearanceResources extends PdfResources {
22+
23+
private static final long serialVersionUID = -1991503804376023468L;
24+
25+
private Map<PdfIndirectReference, PdfName> drFonts = new HashMap<>();
26+
27+
AppearanceResources() {
28+
super();
29+
}
30+
31+
AppearanceResources(PdfDictionary pdfObject) {
32+
super(pdfObject);
33+
}
34+
35+
AppearanceResources addFontFromDefaultResources(PdfName name, PdfFont font) {
36+
if (name != null && font != null && font.getPdfObject().getIndirectReference() != null) {
37+
//So, most likely it's a document PdfFont
38+
drFonts.put(font.getPdfObject().getIndirectReference(), name);
39+
}
40+
return this;
41+
}
42+
43+
@Override
44+
public PdfName addFont(PdfDocument pdfDocument, PdfFont font) {
45+
PdfName fontName = null;
46+
if (font != null && font.getPdfObject().getIndirectReference() != null) {
47+
fontName = drFonts.get(font.getPdfObject().getIndirectReference());
48+
}
49+
50+
if (fontName != null) {
51+
addResource(font.getPdfObject(), PdfName.Font, fontName);
52+
return fontName;
53+
} else {
54+
return super.addFont(pdfDocument, font);
55+
}
56+
}
57+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.itextpdf.forms.fields;
2+
3+
import com.itextpdf.kernel.font.PdfFont;
4+
import com.itextpdf.kernel.geom.Rectangle;
5+
import com.itextpdf.kernel.pdf.PdfDictionary;
6+
import com.itextpdf.kernel.pdf.PdfName;
7+
import com.itextpdf.kernel.pdf.PdfResources;
8+
import com.itextpdf.kernel.pdf.PdfStream;
9+
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
10+
11+
/**
12+
* AppearanceXObject allows font names registration. Those names will be used as resource name
13+
* for a particular {@link PdfFont}.
14+
* <p>
15+
* Preserving existed font names in default resources of AcroForm is the only goal of this class.
16+
* <p>
17+
* Shall be used only in {@link PdfFormField}.
18+
*/
19+
class AppearanceXObject extends PdfFormXObject {
20+
21+
private static final long serialVersionUID = 6098843657444897565L;
22+
23+
AppearanceXObject(PdfStream pdfStream) {
24+
super(pdfStream);
25+
}
26+
27+
AppearanceXObject(Rectangle bBox) {
28+
super(bBox);
29+
}
30+
31+
void addFontFromDR(PdfName fontName, PdfFont font) {
32+
if (fontName != null && font != null) {
33+
((AppearanceResources) getResources()).addFontFromDefaultResources(fontName, font);
34+
}
35+
}
36+
37+
@Override
38+
public PdfResources getResources() {
39+
if (this.resources == null) {
40+
PdfDictionary resourcesDict = getPdfObject().getAsDictionary(PdfName.Resources);
41+
if (resourcesDict == null) {
42+
resourcesDict = new PdfDictionary();
43+
getPdfObject().put(PdfName.Resources, resourcesDict);
44+
}
45+
this.resources = new AppearanceResources(resourcesDict);
46+
}
47+
return resources;
48+
}
49+
}

forms/src/main/java/com/itextpdf/forms/fields/PdfFormField.java

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ This file is part of the iText (R) project.
101101
/**
102102
* This class represents a single field or field group in an {@link com.itextpdf.forms.PdfAcroForm
103103
* AcroForm}.
104-
* <p>
104+
*
105105
* <br><br>
106106
* To be able to be wrapped with this {@link PdfObjectWrapper} the {@link PdfObject}
107107
* must be indirect.
@@ -795,7 +795,7 @@ public static PdfButtonFormField createPushButton(PdfDocument doc, Rectangle rec
795795
field.font = font;
796796
field.fontSize = fontSize;
797797

798-
PdfFormXObject xObject = field.drawPushButtonAppearance(rect.getWidth(), rect.getHeight(), caption, font, fontSize);
798+
PdfFormXObject xObject = field.drawPushButtonAppearance(rect.getWidth(), rect.getHeight(), caption, font, null, fontSize);
799799
annot.setNormalAppearance(xObject.getPdfObject());
800800

801801
PdfDictionary mk = new PdfDictionary();
@@ -1513,8 +1513,7 @@ public PdfString getDefaultAppearance() {
15131513
*/
15141514
public PdfFormField setDefaultAppearance(String defaultAppearance) {
15151515
byte[] b = defaultAppearance.getBytes(StandardCharsets.UTF_8);
1516-
int len = b.length;
1517-
for (int k = 0; k < len; ++k) {
1516+
for (int k = 0; k < b.length; ++k) {
15181517
if (b[k] == '\n')
15191518
b[k] = 32;
15201519
}
@@ -1805,7 +1804,10 @@ public boolean regenerateField() {
18051804

18061805
Object[] fontAndSize = getFontAndSize(asNormal);
18071806
PdfFont localFont = (PdfFont) fontAndSize[0];
1808-
float fontSize = normalizeFontSize((float) fontAndSize[1], localFont, bBox, value);
1807+
PdfName localFontName = (PdfName) fontAndSize[2];
1808+
// Save it for Default Appearance.
1809+
this.fontSize = (float) fontAndSize[1];
1810+
float fontSize = normalizeFontSize(this.fontSize, localFont, bBox, value);
18091811

18101812
//Apply Page rotation
18111813
int pageRotation = 0;
@@ -1886,14 +1888,14 @@ public boolean regenerateField() {
18861888
bBox = new PdfArray(rect);
18871889
}
18881890
//Create appearance
1889-
PdfFormXObject appearance = null;
1891+
AppearanceXObject appearance;
18901892
if (asNormal != null) {
1891-
appearance = new PdfFormXObject(asNormal);
1893+
appearance = new AppearanceXObject(asNormal);
18921894
appearance.setBBox(new PdfArray(new float[]{0, 0, bBox.toRectangle().getWidth(), bBox.toRectangle().getHeight()}));
1895+
} else {
1896+
appearance = new AppearanceXObject(new Rectangle(0, 0, bBox.toRectangle().getWidth(), bBox.toRectangle().getHeight()));
18931897
}
1894-
if (appearance == null) {
1895-
appearance = new PdfFormXObject(new Rectangle(0, 0, bBox.toRectangle().getWidth(), bBox.toRectangle().getHeight()));
1896-
}
1898+
appearance.addFontFromDR(localFontName, localFont);
18971899
appearance.put(PdfName.Matrix, matrix);
18981900
//Create text appearance
18991901
if (PdfName.Tx.equals(type)) {
@@ -1943,20 +1945,19 @@ public boolean regenerateField() {
19431945
apDic = widgets.get(0).getPdfObject().getAsDictionary(PdfName.AP);
19441946
}
19451947
}
1946-
if (img != null) {
1947-
appearance = drawPushButtonAppearance(rect.getWidth(), rect.getHeight(), value, null, 0);
1948-
} else if (form != null) {
1949-
appearance = drawPushButtonAppearance(rect.getWidth(), rect.getHeight(), value, null, 0);
1948+
if (img != null || form != null) {
1949+
appearance = drawPushButtonAppearance(rect.getWidth(), rect.getHeight(), value, null, null, 0);
19501950
} else {
19511951
PdfStream asNormal = null;
19521952
if (apDic != null) {
19531953
asNormal = apDic.getAsStream(PdfName.N);
19541954
}
19551955
Object[] fontAndSize = getFontAndSize(asNormal);
19561956
PdfFont localFont = (PdfFont) fontAndSize[0];
1957+
PdfName localFontName = (PdfName) fontAndSize[2];
19571958
float fontSize = (float) fontAndSize[1];
1958-
appearance = drawPushButtonAppearance(rect.getWidth(), rect.getHeight(), value, localFont, fontSize);
1959-
appearance.getResources().addFont(getDocument(), localFont);
1959+
appearance = drawPushButtonAppearance(rect.getWidth(), rect.getHeight(), value,
1960+
localFont, localFontName, fontSize);
19601961
}
19611962

19621963
if (apDic == null) {
@@ -2032,6 +2033,7 @@ private PdfObject getAcroFormKey(PdfName key, int type) {
20322033
private float normalizeFontSize(float fs, PdfFont localFont, PdfArray bBox, String value) {
20332034
if (fs == 0) {
20342035
if (isMultiline()) {
2036+
//We do not support autosize with multiline.
20352037
fontSize = DEFAULT_FONT_SIZE;
20362038
} else {
20372039
float height = bBox.toRectangle().getHeight() - borderWidth * 2;
@@ -2457,7 +2459,21 @@ protected static PdfArray processOptions(String[] options) {
24572459
return array;
24582460
}
24592461

2462+
/**
2463+
* Generate default appearance, /DA key.
2464+
*
2465+
* @param font preferred font. If {@link #getFont()} is not null, it will be used instead.
2466+
* @param fontSize preferred font size. If {@link PdfFormField#fontSize} is valid,
2467+
* it will be used instead.
2468+
* @return generated string
2469+
*/
24602470
protected String generateDefaultAppearanceString(PdfFont font, float fontSize, Color color, PdfResources res) {
2471+
if (this.fontSize >= 0) {
2472+
fontSize = this.fontSize;
2473+
}
2474+
if (this.font != null) {
2475+
font = this.font;
2476+
}
24612477
PdfStream stream = new PdfStream();
24622478
PdfCanvas canvas = new PdfCanvas(stream, res, getDocument());
24632479
canvas.setFontAndSize(font, fontSize);
@@ -2479,7 +2495,7 @@ protected String generateDefaultAppearanceString(PdfFont font, int fontSize, Pdf
24792495
}
24802496

24812497
protected Object[] getFontAndSize(PdfDictionary asNormal) throws IOException {
2482-
Object[] fontAndSize = new Object[2];
2498+
Object[] fontAndSize = new Object[3];
24832499
PdfDictionary normalResources = null;
24842500
PdfDictionary defaultResources = null;
24852501
PdfDocument document = getDocument();
@@ -2494,6 +2510,7 @@ protected Object[] getFontAndSize(PdfDictionary asNormal) throws IOException {
24942510
if ((normalFontDic != null || defaultFontDic != null) && defaultAppearance != null) {
24952511
Object[] dab = splitDAelements(defaultAppearance.toUnicodeString());
24962512
PdfName fontName = new PdfName(dab[DA_FONT].toString());
2513+
fontAndSize[2] = fontName;
24972514
PdfDictionary requiredFontDictionary = null;
24982515
if (normalFontDic != null && null != normalFontDic.getAsDictionary(fontName)) {
24992516
requiredFontDictionary = normalFontDic.getAsDictionary(fontName);
@@ -3036,12 +3053,34 @@ protected void drawPdfA2CheckAppearance(float width, float height, String value,
30363053
* @param font a {@link PdfFont}
30373054
* @param fontSize the size of the font
30383055
* @return a new {@link PdfFormXObject}
3056+
* @deprecated Will be removed in 7.2.
3057+
* @see #drawPushButtonAppearance(float, float, String, PdfFont, PdfName, float)
30393058
*/
3040-
protected PdfFormXObject drawPushButtonAppearance(float width, float height, String text, PdfFont font, float fontSize) {
3041-
PdfStream stream = new PdfStream().makeIndirect(getDocument());
3042-
PdfCanvas canvas = new PdfCanvas(stream, new PdfResources(), getDocument());
3059+
@Deprecated
3060+
protected PdfFormXObject drawPushButtonAppearance(float width, float height, String text,
3061+
PdfFont font, float fontSize) {
3062+
return drawPushButtonAppearance(width, height, text, font, null, fontSize);
30433063

3044-
PdfFormXObject xObject = new PdfFormXObject(new Rectangle(0, 0, width, height));
3064+
}
3065+
3066+
/**
3067+
* Draws the appearance for a push button.
3068+
*
3069+
* @param width the width of the pushbutton
3070+
* @param height the width of the pushbutton
3071+
* @param text the text to display on the button
3072+
* @param font a {@link PdfFont}
3073+
* @param fontName fontName in DR.
3074+
* @param fontSize the size of the font
3075+
* @return a new {@link PdfFormXObject}
3076+
*/
3077+
protected PdfFormXObject drawPushButtonAppearance(float width, float height, String text,
3078+
PdfFont font, PdfName fontName, float fontSize) {
3079+
PdfStream stream = (PdfStream) new PdfStream().makeIndirect(getDocument());
3080+
AppearanceResources resources = new AppearanceResources().addFontFromDefaultResources(fontName, font);
3081+
PdfCanvas canvas = new PdfCanvas(stream, resources, getDocument());
3082+
3083+
AppearanceXObject xObject = new AppearanceXObject(new Rectangle(0, 0, width, height));
30453084
if (backgroundColor == null) {
30463085
backgroundColor = ColorConstants.LIGHT_GRAY;
30473086
}
@@ -3056,7 +3095,8 @@ protected PdfFormXObject drawPushButtonAppearance(float width, float height, Str
30563095
xObject.getResources().addForm(form);
30573096
} else {
30583097
drawButton(canvas, 0, 0, width, height, text, font, fontSize);
3059-
setDefaultAppearance(generateDefaultAppearanceString(font, fontSize, color, new PdfResources()));
3098+
xObject.addFontFromDR(fontName, font);
3099+
setDefaultAppearance(generateDefaultAppearanceString(font, fontSize, color, resources));
30603100
xObject.getResources().addFont(getDocument(), font);
30613101
}
30623102
xObject.getPdfObject().getOutputStream().writeBytes(stream.getBytes());
Binary file not shown.

0 commit comments

Comments
 (0)