Search code examples
javapdfpdfbox

PDF form field content unable to display in Acrobat after fill in using PDFBOX


I have a digital sign pdf with 2 form field having the same name. when i try fill up the field using PDFBOX and open it in Acrobat the field content is empty. It only will show the content when i click on the field.

This my code

    File inFile= new File("pdfFile/Untitled_sign.pdf");
    OutputStream outFile = new FileOutputStream("pdfFile/Untitled_sign_2.pdf");
    PDDocument pdfDocument = PDDocument.load(inFile);

    PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();

    Set<COSDictionary> cosDis=  new HashSet<>();
    if (acroForm != null) {
        List<PDField> fields = acroForm.getFields();
        //acroForm.setNeedAppearances(true);
        for (PDField field : fields) {
            if(field instanceof PDTextField) {
                System.out.println(field.getFullyQualifiedName());
                if(field.getFullyQualifiedName().equals("Text1")) {
                    try {
                        field.setValue("100");
                        System.out.println("New value: " + field.getValueAsString());
                        
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    field.getCOSObject().setNeedToBeUpdated(true);
                    cosDis.add(field.getCOSObject());
                }
            }
        }
        acroForm.getCOSObject().setNeedToBeUpdated(true);
        cosDis.add(acroForm.getCOSObject());
    }
      pdfDocument.saveIncremental(outFile,cosDis);

here the pdf https://drive.google.com/file/d/1SeGiPhoEqtkuKGHT3FG063d9lbtFrnt0/view?usp=sharing

and here the result https://drive.google.com/file/d/1LHxDuHIztRv-r27pYTmRYIwUEkdaX_75/view?usp=sharing

[EDIT]

after Tilman recommended using field.getWidgets().get(0).getAppearance().getCOSObject().setNeedToBeUpdated(true); it able to display correctly. But when i do digital sign again, the content will go back to original content. For example, I fill in the pdf with "test" and digital sign the pdf. (original pdf https://drive.google.com/file/d/1SoVgWMfRVbVsWVOSRRFU7bjyJARHFmZV/view?usp=sharing)

(first digital sign pdf https://drive.google.com/file/d/1sbklXp8s1R9OoH3xwJPZ54o0TUV_bl4m/view?usp=sharing)

after digital sign i used pdfbox to change the content from "test" to "100". it able to display "100" correctly in acrobat. (pdf with "100" https://drive.google.com/file/d/13ViNcGJ7g0d6Kcxn8MsGQKF9DMFCD-1a/view?usp=sharing)

but if i digital sign again it will change back to "test" (second digital sign https://drive.google.com/file/d/1uiv4UddZHnMBNzNE7LlIg7Gb1bzUVLlM/view?usp=sharing) This the new code i added but is this the same. when it digital sign the content will chnage back to "test"

PDDocument pdfDocument = PDDocument.load(inFile);

    PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();

    Set<COSDictionary> cosDis=  new HashSet<>();
    if (acroForm != null) {
        List<PDField> fields = acroForm.getFields();
        for (PDField field : fields) {
            if(field instanceof PDTextField) {
                if(field.getFullyQualifiedName().equals("Text1")) {
                    try {
                        field.setValue("200");
                        System.out.println("New value: " + field.getValueAsString());
                        
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    field.getCOSObject().setNeedToBeUpdated(true);
                    for(PDAnnotationWidget wed: field.getWidgets()) {
                        wed.getAppearance().getCOSObject().setNeedToBeUpdated(true);
                        wed.getCOSObject().setNeedToBeUpdated(true);
                    }
                    COSDictionary fieldDictionary = field.getCOSObject();
                    COSDictionary dictionary = (COSDictionary) fieldDictionary.getDictionaryObject(COSName.AP);
                    if(dictionary!=null) {
                    dictionary.setNeedToBeUpdated(true);
                    COSStream stream = (COSStream) dictionary.getDictionaryObject(COSName.N);
                    stream.setNeedToBeUpdated(true);
                    }
                    while (fieldDictionary != null)
                    {
                        fieldDictionary.setNeedToBeUpdated(true);
                        fieldDictionary = (COSDictionary) fieldDictionary.getDictionaryObject(COSName.PARENT);
                    }
                }
            }
        }
        acroForm.setSignaturesExist(true);
        acroForm.setAppendOnly(true);
        acroForm.getCOSObject().setDirect(true);
        acroForm.getCOSObject().setNeedToBeUpdated(true);
        //acroForm.setNeedAppearances(true);
        COSObject pdfFields = acroForm.getCOSObject().getCOSObject(COSName.FIELDS);
        if (pdfFields != null) {
            pdfFields.setNeedToBeUpdated(true);
        }
        pdfDocument.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true);
        cosDis.add(pdfDocument.getDocumentCatalog().getCOSObject());
        cosDis.add(acroForm.getCOSObject());
    }
      pdfDocument.saveIncremental(outFile,cosDis);

Solution

  • Thank you Tilman Hausherr. the solution i found is by setNeedToBeUpdated() in the COSName.AP and COSName.N inside the COSName.KIDS.

    PDF structure

    here my final code.

        PDDocument pdfDocument = PDDocument.load(inFile);
        PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();
        Set<COSDictionary> cosDis=  new HashSet<>();
        if (acroForm != null) {
            List<PDField> fields = acroForm.getFields();
            for (PDField field : fields) {
                if(field instanceof PDTextField) {
                    if(field.getFullyQualifiedName().equals("Text1")) {
                        try {
                            field.setValue("200");
                            System.out.println("New value: " + field.getValueAsString());
                            
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        field.getCOSObject().setNeedToBeUpdated(true);
                        cosDis.add(field.getCOSObject());
                        for(PDAnnotationWidget wed: field.getWidgets()) {
                            wed.getAppearance().getCOSObject().setNeedToBeUpdated(true);
                            wed.getCOSObject().setNeedToBeUpdated(true);
                             cosDis.add(wed.getAppearance().getCOSObject());
                             cosDis.add(wed.getCOSObject());
                        }
                        COSDictionary fieldDictionary = field.getCOSObject();
                        COSDictionary dictionary = (COSDictionary) fieldDictionary.getDictionaryObject(COSName.AP);
                        if(dictionary!=null) {
                           dictionary.setNeedToBeUpdated(true);
                           cosDis.add(dictionary);
                           COSStream stream = (COSStream) dictionary.getDictionaryObject(COSName.N);
                           stream.setNeedToBeUpdated(true);
                           cosDis.add(stream);
                        }else {
                            COSArray dictionary2 = (COSArray) fieldDictionary.getDictionaryObject(COSName.KIDS);
                            for (int i = 0; i < dictionary2.size(); i++)
                            {
                                COSDictionary kidAp=(COSDictionary) ((COSDictionary)dictionary2.getObject(i)).getDictionaryObject(COSName.AP);
                                if(kidAp!=null) {
                                    kidAp.setNeedToBeUpdated(true);
                                    cosDis.add(kidAp);
                                    COSStream kidApstream = (COSStream) kidAp.getDictionaryObject(COSName.N);
                                    kidApstream.setNeedToBeUpdated(true);
                                    cosDis.add(kidApstream);
                                }
                            }
                        }
                        while (fieldDictionary != null)
                        {
                            fieldDictionary.setNeedToBeUpdated(true);
                            cosDis.add(fieldDictionary);
                            fieldDictionary = (COSDictionary) fieldDictionary.getDictionaryObject(COSName.PARENT);
                        }
                    }
                }
            }
            acroForm.setSignaturesExist(true);
            acroForm.setAppendOnly(true);
            acroForm.getCOSObject().setDirect(true);
            acroForm.getCOSObject().setNeedToBeUpdated(true);
            
            //acroForm.setNeedAppearances(true);
            COSObject pdfFields = acroForm.getCOSObject().getCOSObject(COSName.FIELDS);
            if (pdfFields != null) {
                pdfFields.setNeedToBeUpdated(true);
            }
            pdfDocument.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true);
            cosDis.add(pdfDocument.getDocumentCatalog().getCOSObject());
            cosDis.add(acroForm.getCOSObject());
        }
          pdfDocument.saveIncremental(outFile,cosDis);
    

    Hope this help. ;)