Author: msahyoun
Date: Tue Mar 24 20:41:28 2026
New Revision: 1932517
Log:
PDFBOX-6150: use display value for appearance
Added:
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestUtils.java
Modified:
pdfbox/branches/2.0/pdfbox/pom.xml
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDComboBox.java
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoiceTest.java
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestRadioButtons.java
Modified: pdfbox/branches/2.0/pdfbox/pom.xml
==============================================================================
--- pdfbox/branches/2.0/pdfbox/pom.xml Tue Mar 24 20:24:04 2026
(r1932516)
+++ pdfbox/branches/2.0/pdfbox/pom.xml Tue Mar 24 20:41:28 2026
(r1932517)
@@ -845,6 +845,19 @@
</configuration>
</execution>
<execution>
+ <id>PDFBOX-6150</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>wget</goal>
+ </goals>
+ <configuration>
+
<url>https://issues.apache.org/jira/secure/attachment/13080392/test-form.pdf</url>
+
<outputDirectory>${project.build.directory}/pdfs</outputDirectory>
+ <outputFileName>PDFBOX-6150.pdf</outputFileName>
+
<sha512>da6c630d2683937bce60f70302176f16531b36300b69d2d8585c15819b7965bf6c0c2f6fe101743d66b3dbb70e7eb0383614b669878641a480b9ea1a6d02510f</sha512>
+ </configuration>
+ </execution>
+ <execution>
<id>PDFBOX-6178</id>
<phase>generate-test-resources</phase>
<goals>
@@ -876,4 +889,3 @@
</build>
</project>
-
Modified:
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java
==============================================================================
---
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java
Tue Mar 24 20:24:04 2026 (r1932516)
+++
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java
Tue Mar 24 20:41:28 2026 (r1932517)
@@ -212,6 +212,18 @@ public abstract class PDChoice extends P
}
/**
+ * This will check if the field has dedicated display and export values.
+ *
+ * @return true if export and display values are different
+ */
+ public boolean hasSeparateExportAndDisplayValues()
+ {
+ List<String> exportValues = getOptionsExportValues();
+ List<String> displayValues = getOptionsDisplayValues();
+ return !exportValues.equals(displayValues);
+ }
+
+ /**
* This will get the indices of the selected options - the 'I' key.
* <p>
* This is only needed if a choice field allows multiple selections and
Modified:
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDComboBox.java
==============================================================================
---
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDComboBox.java
Tue Mar 24 20:24:04 2026 (r1932516)
+++
pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDComboBox.java
Tue Mar 24 20:41:28 2026 (r1932517)
@@ -84,6 +84,16 @@ public final class PDComboBox extends PD
if (!values.isEmpty())
{
+ if (hasSeparateExportAndDisplayValues())
+ {
+ List<String> displayValues = getOptionsDisplayValues();
+ int index = getOptions().indexOf(values.get(0));
+ if (index != -1 && index < displayValues.size())
+ {
+ apHelper.setAppearanceValue(displayValues.get(index));
+ return;
+ }
+ }
apHelper.setAppearanceValue(values.get(0));
}
else
Modified:
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java
==============================================================================
---
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java
Tue Mar 24 20:24:04 2026 (r1932516)
+++
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java
Tue Mar 24 20:41:28 2026 (r1932517)
@@ -20,13 +20,9 @@ import static org.junit.Assert.assertEqu
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.List;
-import org.apache.pdfbox.cos.COSString;
-import org.apache.pdfbox.pdfparser.PDFStreamParser;
import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -88,8 +84,8 @@ public class ControlCharacterTest {
PDField field = acroForm.getField("pdfbox-space");
field.setValue("SPACE SPACE");
- List<String> pdfboxValues = getStringsFromStream(field);
- List<String> acrobatValues =
getStringsFromStream(acroForm.getField("acrobat-space"));
+ List<String> pdfboxValues = TestUtils.getStringsFromStream(field);
+ List<String> acrobatValues =
TestUtils.getStringsFromStream(acroForm.getField("acrobat-space"));
assertEquals(pdfboxValues, acrobatValues);
}
@@ -100,8 +96,8 @@ public class ControlCharacterTest {
PDField field = acroForm.getField("pdfbox-cr");
field.setValue("CR\rCR");
- List<String> pdfboxValues = getStringsFromStream(field);
- List<String> acrobatValues =
getStringsFromStream(acroForm.getField("acrobat-cr"));
+ List<String> pdfboxValues = TestUtils.getStringsFromStream(field);
+ List<String> acrobatValues =
TestUtils.getStringsFromStream(acroForm.getField("acrobat-cr"));
assertEquals(pdfboxValues, acrobatValues);
}
@@ -112,8 +108,8 @@ public class ControlCharacterTest {
PDField field = acroForm.getField("pdfbox-lf");
field.setValue("LF\nLF");
- List<String> pdfboxValues = getStringsFromStream(field);
- List<String> acrobatValues =
getStringsFromStream(acroForm.getField("acrobat-lf"));
+ List<String> pdfboxValues = TestUtils.getStringsFromStream(field);
+ List<String> acrobatValues =
TestUtils.getStringsFromStream(acroForm.getField("acrobat-lf"));
assertEquals(pdfboxValues, acrobatValues);
}
@@ -124,8 +120,8 @@ public class ControlCharacterTest {
PDField field = acroForm.getField("pdfbox-crlf");
field.setValue("CRLF\r\nCRLF");
- List<String> pdfboxValues = getStringsFromStream(field);
- List<String> acrobatValues =
getStringsFromStream(acroForm.getField("acrobat-crlf"));
+ List<String> pdfboxValues = TestUtils.getStringsFromStream(field);
+ List<String> acrobatValues =
TestUtils.getStringsFromStream(acroForm.getField("acrobat-crlf"));
assertEquals(pdfboxValues, acrobatValues);
}
@@ -136,8 +132,8 @@ public class ControlCharacterTest {
PDField field = acroForm.getField("pdfbox-lfcr");
field.setValue("LFCR\n\rLFCR");
- List<String> pdfboxValues = getStringsFromStream(field);
- List<String> acrobatValues =
getStringsFromStream(acroForm.getField("acrobat-lfcr"));
+ List<String> pdfboxValues = TestUtils.getStringsFromStream(field);
+ List<String> acrobatValues =
TestUtils.getStringsFromStream(acroForm.getField("acrobat-lfcr"));
assertEquals(pdfboxValues, acrobatValues);
}
@@ -148,8 +144,8 @@ public class ControlCharacterTest {
PDField field = acroForm.getField("pdfbox-linebreak");
field.setValue("linebreak\u2028linebreak");
- List<String> pdfboxValues = getStringsFromStream(field);
- List<String> acrobatValues =
getStringsFromStream(acroForm.getField("acrobat-linebreak"));
+ List<String> pdfboxValues = TestUtils.getStringsFromStream(field);
+ List<String> acrobatValues =
TestUtils.getStringsFromStream(acroForm.getField("acrobat-linebreak"));
assertEquals(pdfboxValues, acrobatValues);
}
@@ -160,8 +156,8 @@ public class ControlCharacterTest {
PDField field = acroForm.getField("pdfbox-paragraphbreak");
field.setValue("paragraphbreak\u2029paragraphbreak");
- List<String> pdfboxValues = getStringsFromStream(field);
- List<String> acrobatValues =
getStringsFromStream(acroForm.getField("acrobat-paragraphbreak"));
+ List<String> pdfboxValues = TestUtils.getStringsFromStream(field);
+ List<String> acrobatValues =
TestUtils.getStringsFromStream(acroForm.getField("acrobat-paragraphbreak"));
assertEquals(pdfboxValues, acrobatValues);
}
@@ -171,27 +167,4 @@ public class ControlCharacterTest {
{
document.close();
}
-
- private List<String> getStringsFromStream(PDField field) throws IOException
- {
- PDAnnotationWidget widget = field.getWidgets().get(0);
- PDFStreamParser parser = new
PDFStreamParser(widget.getNormalAppearanceStream());
-
- Object token = parser.parseNextToken();
-
- List<String> stringValues = new ArrayList<String>();
-
- while (token != null)
- {
- if (token instanceof COSString)
- {
- // TODO: improve the string output to better match
- // trimming as Acrobat adds spaces to strings
- // where we don't
- stringValues.add(((COSString)
token).getString().trim());
- }
- token = parser.parseNextToken();
- }
- return stringValues;
- }
}
Modified:
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoiceTest.java
==============================================================================
---
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoiceTest.java
Tue Mar 24 20:24:04 2026 (r1932516)
+++
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoiceTest.java
Tue Mar 24 20:41:28 2026 (r1932517)
@@ -20,6 +20,8 @@ import static org.junit.Assert.assertEqu
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -29,6 +31,7 @@ import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.internal.util.io.IOUtil;
/**
* Test for the PDChoice class.
@@ -145,5 +148,53 @@ public class PDChoiceTest
assertEquals(options, choiceField.getOptions());
}
+ /*
+ * Set here the value of a choice field to a value with a display value
that is different
+ * from the export value and check that the correct display value is used
in the appearance stream.
+ * See PDFBOX-6150
+ */
+ @Test
+ public void PDFBox6150() throws IOException
+ {
+ PDDocument document = null;
+ File pdfFile = new File("target/pdfs/PDFBOX-6150.pdf");
+
+ if (!pdfFile.exists())
+ {
+ return; // Skip test if PDF not available
+ }
+
+ // Load document, set value, and save to memory
+ try
+ {
+ document = PDDocument.load(pdfFile);
+ PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
+ PDChoice field = (PDChoice) acroForm.getField("shipping_country");
+
+ field.setValue("DE");
+
+ assertTrue("The fields value should be set to DE",
"DE".equals(field.getValue().get(0)));
+
+ // Read the content of the normal appearance stream and check that
it contains the display value for DE
+ // which is Deutschland
+ List<String> content = TestUtils.getStringsFromStream(field);
+ boolean hasContent = false;
+ for (String item : content)
+ {
+ System.out.println(item);
+ if ("Deutschland".equals(item))
+ {
+ hasContent = true;
+ break;
+ }
+ }
+ assertTrue("The content should contain the display value for DE
which is Deutschland", hasContent);
+
+ document.close();
+ }
+ finally
+ {
+ IOUtil.closeQuietly(document);
+ }
+ }
}
-
Modified:
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestRadioButtons.java
==============================================================================
---
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestRadioButtons.java
Tue Mar 24 20:24:04 2026 (r1932516)
+++
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestRadioButtons.java
Tue Mar 24 20:41:28 2026 (r1932517)
@@ -477,6 +477,7 @@ public class TestRadioButtons
containsSequence(asBytes, new byte[]{(byte) 0xE4}));
document.save(baos);
+ document.save(new File("/home/msahyoun/test.pdf"));
}
finally
{
Added:
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestUtils.java
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++
pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestUtils.java
Tue Mar 24 20:41:28 2026 (r1932517)
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.form;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSString;
+import org.apache.pdfbox.pdfparser.PDFStreamParser;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
+
+/**
+ * Utility class for form-related tests.
+ */
+public class TestUtils
+{
+ /**
+ * Extract strings from a PDF field's normal appearance stream.
+ *
+ * @param field the PDF field
+ * @return list of strings found in the appearance stream
+ * @throws IOException if an error occurs while parsing the stream
+ */
+ public static List<String> getStringsFromStream(PDField field) throws
IOException
+ {
+ PDAnnotationWidget widget = field.getWidgets().get(0);
+ PDFStreamParser parser = new
PDFStreamParser(widget.getNormalAppearanceStream());
+
+ Object token = parser.parseNextToken();
+
+ List<String> stringValues = new ArrayList<String>();
+
+ while (token != null)
+ {
+ if (token instanceof COSString)
+ {
+ // TODO: improve the string output to better match
+ // trimming as Acrobat adds spaces to strings
+ // where we don't
+ stringValues.add(((COSString)
token).getString().trim());
+ }
+ token = parser.parseNextToken();
+ }
+ return stringValues;
+ }
+}