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;    
+    }
+}

Reply via email to