Skip to content

Commit fe1c221

Browse files
committed
Reconstruct checkbox type when its in Apearance characteristics
DEVSIX-2121
1 parent 6f4835a commit fe1c221

File tree

11 files changed

+74
-21
lines changed

11 files changed

+74
-21
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.itextpdf.commons.datastructures;
2+
3+
/**
4+
* A simple container that can hold a value.
5+
* This is class is used to make the autoporting of primitive types easier.
6+
* For example autoporting enums will convert them to non nullable types.
7+
* But if you embed them in a NullableContainer, the autoporting will convert them to nullable types.
8+
*/
9+
public class NullableContainer<T> {
10+
11+
private final T value;
12+
13+
/**
14+
* Creates a new {@link NullableContainer} instance.
15+
*
16+
* @param value the value
17+
*/
18+
public NullableContainer(T value) {
19+
this.value = value;
20+
}
21+
22+
/**
23+
* Gets the value.
24+
*
25+
* @return the value
26+
*/
27+
public T getValue() {
28+
return value;
29+
}
30+
}

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

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ This file is part of the iText (R) project.
2222
*/
2323
package com.itextpdf.forms.fields;
2424

25+
import com.itextpdf.commons.datastructures.NullableContainer;
2526
import com.itextpdf.commons.utils.ExperimentalFeatures;
2627
import com.itextpdf.commons.utils.MessageFormatUtil;
2728
import com.itextpdf.forms.fields.borders.FormBorderFactory;
29+
import com.itextpdf.forms.fields.properties.CheckBoxType;
2830
import com.itextpdf.forms.form.FormProperty;
2931
import com.itextpdf.forms.form.element.Button;
3032
import com.itextpdf.forms.form.element.CheckBox;
@@ -74,7 +76,6 @@ This file is part of the iText (R) project.
7476
import com.itextpdf.layout.properties.Leading;
7577
import com.itextpdf.layout.properties.OverflowPropertyValue;
7678
import com.itextpdf.layout.properties.Property;
77-
import com.itextpdf.layout.properties.RenderingMode;
7879
import com.itextpdf.layout.properties.TextAlignment;
7980
import com.itextpdf.layout.properties.TransparentColor;
8081
import com.itextpdf.layout.properties.UnitValue;
@@ -1228,6 +1229,7 @@ protected void drawCheckBoxAndSaveAppearance(String onStateName) {
12281229
if (rect == null) {
12291230
return;
12301231
}
1232+
reconstructCheckBoxType();
12311233
createCheckBox();
12321234
if (getWidget().getNormalAppearanceObject() == null) {
12331235
getWidget().setNormalAppearance(new PdfDictionary());
@@ -1258,11 +1260,12 @@ protected void drawCheckBoxAndSaveAppearance(String onStateName) {
12581260
getWidget().setNormalAppearance(normalAppearance);
12591261

12601262
final PdfDictionary mk = new PdfDictionary();
1263+
12611264
// We put the zapfDingbats code of the checkbox in the MK dictionary to make sure there is a way
12621265
// to retrieve the checkbox type even if the appearance is not present.
12631266
mk.put(PdfName.CA,
1264-
new PdfString(PdfCheckBoxRenderingStrategy.CHECKBOX_TYPE_ZAPFDINGBATS_CODE.get(parent.checkType)));
1265-
1267+
new PdfString(PdfCheckBoxRenderingStrategy.ZAPFDINGBATS_CHECKBOX_MAPPING.getByKey(
1268+
parent.checkType.getValue())));
12661269
getWidget().put(PdfName.MK, mk);
12671270
setCheckBoxAppearanceState(onStateName);
12681271
}
@@ -1277,6 +1280,29 @@ private void setCheckBoxAppearanceState(String onStateName) {
12771280
}
12781281
}
12791282

1283+
private void reconstructCheckBoxType() {
1284+
1285+
// if checkbox type is null it means we are reading from a document and we need to retrieve the type from the
1286+
// mk dictionary in the ca
1287+
if (parent.checkType == null) {
1288+
PdfDictionary oldMk = getWidget().getAppearanceCharacteristics();
1289+
if (oldMk != null) {
1290+
PdfString oldCa = oldMk.getAsString(PdfName.CA);
1291+
if (oldCa != null && PdfCheckBoxRenderingStrategy.ZAPFDINGBATS_CHECKBOX_MAPPING.containsValue(
1292+
oldCa.getValue())) {
1293+
parent.checkType = new NullableContainer<>(
1294+
PdfCheckBoxRenderingStrategy.ZAPFDINGBATS_CHECKBOX_MAPPING.getByValue(oldCa.getValue()));
1295+
// we need to set the font size to 0 to make sure the font size is recalculated
1296+
fontSize = 0;
1297+
}
1298+
}
1299+
}
1300+
// if its still null default to default value
1301+
if (parent.checkType == null) {
1302+
parent.checkType = new NullableContainer<>(CheckBoxType.CROSS);
1303+
}
1304+
}
1305+
12801306
private void createCheckBox() {
12811307
if (!(formFieldElement instanceof CheckBox)) {
12821308
// Create it one time and re-set properties during each widget regeneration.
@@ -1287,7 +1313,7 @@ private void createCheckBox() {
12871313
formFieldElement.setProperty(Property.FONT_SIZE, UnitValue.createPointValue(getFontSize()));
12881314
setModelElementProperties(getRect(getPdfObject()));
12891315
((CheckBox) formFieldElement).setPdfAConformanceLevel(getPdfAConformanceLevel());
1290-
((CheckBox) formFieldElement).setCheckBoxType(parent.checkType);
1316+
((CheckBox) formFieldElement).setCheckBoxType(parent.checkType.getValue());
12911317
}
12921318

12931319
private void setModelElementProperties(Rectangle rectangle) {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This file is part of the iText (R) project.
2222
*/
2323
package com.itextpdf.forms.fields;
2424

25+
import com.itextpdf.commons.datastructures.NullableContainer;
2526
import com.itextpdf.commons.utils.Base64;
2627
import com.itextpdf.commons.utils.MessageFormatUtil;
2728
import com.itextpdf.forms.PdfAcroForm;
@@ -119,7 +120,7 @@ public class PdfFormField extends AbstractPdfFormField {
119120
protected ImageData img;
120121
protected PdfFormXObject form;
121122

122-
protected CheckBoxType checkType = CheckBoxType.CROSS;
123+
protected NullableContainer<CheckBoxType> checkType = null;
123124

124125
private String displayValue;
125126

@@ -1065,7 +1066,7 @@ public PdfFormField setCheckType(CheckBoxType checkType) {
10651066
if (checkType == null) {
10661067
checkType = CheckBoxType.CROSS;
10671068
}
1068-
this.checkType = checkType;
1069+
this.checkType = new NullableContainer<>(checkType);
10691070
if (getPdfAConformanceLevel() != null) {
10701071
return this;
10711072
}

forms/src/main/java/com/itextpdf/forms/form/renderer/checkboximpl/PdfCheckBoxRenderingStrategy.java

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This file is part of the iText (R) project.
2222
*/
2323
package com.itextpdf.forms.form.renderer.checkboximpl;
2424

25+
import com.itextpdf.commons.datastructures.BiMap;
2526
import com.itextpdf.forms.fields.properties.CheckBoxType;
2627
import com.itextpdf.forms.form.renderer.CheckBoxRenderer;
2728
import com.itextpdf.forms.logs.FormsLogMessageConstants;
@@ -38,25 +39,20 @@ This file is part of the iText (R) project.
3839
import com.itextpdf.layout.properties.Property;
3940
import com.itextpdf.layout.renderer.DrawContext;
4041

41-
import java.util.Collections;
42-
import java.util.HashMap;
43-
import java.util.Map;
44-
4542
/**
4643
* This class is used to draw a checkBox icon in PDF mode this is the default strategy for drawing a checkBox.
4744
*/
4845
public final class PdfCheckBoxRenderingStrategy implements ICheckBoxRenderingStrategy {
49-
public static final Map<CheckBoxType, String> CHECKBOX_TYPE_ZAPFDINGBATS_CODE;
46+
public static final BiMap<CheckBoxType, String> ZAPFDINGBATS_CHECKBOX_MAPPING;
5047

5148
static {
52-
Map<CheckBoxType, String> initialMap = new HashMap<>();
53-
initialMap.put(CheckBoxType.CHECK, "4");
54-
initialMap.put(CheckBoxType.CIRCLE, "l");
55-
initialMap.put(CheckBoxType.CROSS, "8");
56-
initialMap.put(CheckBoxType.DIAMOND, "u");
57-
initialMap.put(CheckBoxType.SQUARE, "n");
58-
initialMap.put(CheckBoxType.STAR, "H");
59-
CHECKBOX_TYPE_ZAPFDINGBATS_CODE = Collections.unmodifiableMap(initialMap);
49+
ZAPFDINGBATS_CHECKBOX_MAPPING = new BiMap<>();
50+
ZAPFDINGBATS_CHECKBOX_MAPPING.put(CheckBoxType.CHECK, "4");
51+
ZAPFDINGBATS_CHECKBOX_MAPPING.put(CheckBoxType.CIRCLE, "l");
52+
ZAPFDINGBATS_CHECKBOX_MAPPING.put(CheckBoxType.CROSS, "8");
53+
ZAPFDINGBATS_CHECKBOX_MAPPING.put(CheckBoxType.DIAMOND, "u");
54+
ZAPFDINGBATS_CHECKBOX_MAPPING.put(CheckBoxType.SQUARE, "n");
55+
ZAPFDINGBATS_CHECKBOX_MAPPING.put(CheckBoxType.STAR, "H");
6056

6157
}
6258

@@ -93,7 +89,7 @@ public void drawCheckBoxContent(DrawContext drawContext, CheckBoxRenderer checkB
9389
final float customBorderWidth = border == null ? 1 : borderWidth;
9490
DrawingUtil.drawCross(canvas, rectangle.getWidth(), rectangle.getHeight(), customBorderWidth);
9591
} else {
96-
final String text = CHECKBOX_TYPE_ZAPFDINGBATS_CODE.get(checkBoxType);
92+
final String text = ZAPFDINGBATS_CHECKBOX_MAPPING.getByKey(checkBoxType);
9793
final PdfFont fontContainingSymbols = loadFontContainingSymbols();
9894
float fontSize = calculateFontSize(checkBoxRenderer, fontContainingSymbols, text, rectangle, borderWidth);
9995
drawZapfdingbatsIcon(fontContainingSymbols, text, fontSize, rectangle, canvas);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ public void keepCheckTypeTest() throws IOException, InterruptedException {
233233

234234
try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(srcPdf), new PdfWriter(outPdf))) {
235235
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
236-
form.getField("checkField").setValue("Yes", false);
236+
form.getField("checkField").setValue("Yes");
237237
}
238238

239239
Assert.assertNull(new CompareTool().compareByContent(outPdf, cmpPdf, destinationFolder, "diff_"));

0 commit comments

Comments
 (0)