Matthias
Matthias

Reputation: 21

PDFBox not printing form fields

I'm trying to print a post-processed (filled) PDF-Template, which was created in LibreOffice and contains filled out form field.

The PDFBox svn is nice and has a lot of examples how to do so. Getting the PDF and the AcroFormat of it is easy, and even editing and saving the modified PDF to disk works as expected. But this is not my goal. I want a PDF which has the fields filled out and then being removed with only the text remaining.

I tried everything on stackoverflow regarding PDFBox, from flatting the acroform to setting readonly properties on the fields and other meta info, installed the necessary fonts and much more. Everytime I printed the PDF to file, the text (edited and non edited) which was in a text field disappeared and the textfields were gone.

But then I tried to create a PDF from scratch with PDFBox and printing works like expected. The textfields were in the generated template and the printed pdf file contained the text I wanted, with the corresponding forms removed. So I used the PDF Debugger from PDFBox to analyse the structure of the PDF and noticed that within the preview of the debugger, my PDF does not contain the text in the text field, exported from LibreOffice. BUT in the tree structure the PDF Annotation is clearly there (/DV and /V) and looks quiet similar to the pdfbox created version, which is working.

For testing I created a simple pdf with just one text field with name "test" and content "Foobar". Also the background and border color were changed to see if anything was successfully printed out.

    PDDocument document = null;
    try {
        document = PDDocument.load(new File("<filepath>\\<filename>"));
    } catch (final InvalidPasswordException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (final IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    PrintFields.createDummyPDF("<filepath>\\<filename>");
    PrintFields.printFields(document); //debug output

    //Getting pdf meta infos
    final PDDocumentCatalog docCatalog = document.getDocumentCatalog();
    final PDAcroForm acroForm = docCatalog.getAcroForm();
    docCatalog.setAcroForm(acroForm);

    //setting the appearance
    final PDFont font = PDType1Font.HELVETICA;
    final PDResources resources = new PDResources();
    resources.put(COSName.getPDFName("Helv"), font);
    acroForm.setDefaultResources(resources);
    String defaultAppearanceString = "/Helv 0 Tf 0 g";
    acroForm.setDefaultAppearance(defaultAppearanceString);

    for(final PDField f : acroForm.getFields()) {
        if(f instanceof PDTextField) {
             defaultAppearanceString = "/Helv 12 Tf 0 0 1 rg";
            final List<PDAnnotationWidget> widgets = ((PDTextField)f).getWidgets();
            widgets.get(0).setAppearanceState(defaultAppearanceString);             
        }
    }

    for(final PDField f : acroForm.getFields()) {
        f.setReadOnly(true);
    }

    // save modified pdf to file 
    document.save("<filepath>\\<filename>");

    //print to file (to pdf)
    if (job.printDialog()) {
        try {
            // Desktop.getDesktop().print();
            job.print();
        } catch (final PrinterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


// copied from pdfbox examples
public static void createDummyPDF(final String path) throws IOException
{
    // Create a new document with an empty page.
    try (PDDocument document = new PDDocument())
    {
        final PDPage page = new PDPage(PDRectangle.A4);
        document.addPage(page);

        // Adobe Acrobat uses Helvetica as a default font and
        // stores that under the name '/Helv' in the resources dictionary
        final PDFont font = PDType1Font.HELVETICA;
        final PDResources resources = new PDResources();
        resources.put(COSName.getPDFName("Helv"), font);

        // Add a new AcroForm and add that to the document
        final PDAcroForm acroForm = new PDAcroForm(document);
        document.getDocumentCatalog().setAcroForm(acroForm);

        // Add and set the resources and default appearance at the form level
        acroForm.setDefaultResources(resources);

        // Acrobat sets the font size on the form level to be
        // auto sized as default. This is done by setting the font size to '0'
        String defaultAppearanceString = "/Helv 0 Tf 0 g";
        acroForm.setDefaultAppearance(defaultAppearanceString);

        // Add a form field to the form.
        final PDTextField textBox = new PDTextField(acroForm);
        textBox.setPartialName("SampleField");

        // Acrobat sets the font size to 12 as default
        // This is done by setting the font size to '12' on the
        // field level.
        // The text color is set to blue in this example.
        // To use black, replace "0 0 1 rg" with "0 0 0 rg" or "0 g".
        defaultAppearanceString = "/Helv 12 Tf 0 0 1 rg";
        textBox.setDefaultAppearance(defaultAppearanceString);

        // add the field to the acroform
        acroForm.getFields().add(textBox);

        // Specify the widget annotation associated with the field
        final PDAnnotationWidget widget = textBox.getWidgets().get(0);
        final PDRectangle rect = new PDRectangle(50, 750, 200, 50);
        widget.setRectangle(rect);
        widget.setPage(page);

        // set green border and yellow background
        // if you prefer defaults, just delete this code block
        final PDAppearanceCharacteristicsDictionary fieldAppearance
                = new PDAppearanceCharacteristicsDictionary(new COSDictionary());
        fieldAppearance.setBorderColour(new PDColor(new float[]{0,1,0}, PDDeviceRGB.INSTANCE));
        fieldAppearance.setBackground(new PDColor(new float[]{1,1,0}, PDDeviceRGB.INSTANCE));
        widget.setAppearanceCharacteristics(fieldAppearance);

        // make sure the widget annotation is visible on screen and paper
        widget.setPrinted(true);

        // Add the widget annotation to the page
        page.getAnnotations().add(widget);

        // set the field value
        textBox.setValue("Sample field");

        document.save(path);
    }
}
//copied from pdfbox examples
public static void processFields(final List<PDField> fields, final PDResources resources) {
fields.stream().forEach(f -> {
    f.setReadOnly(true);
    final COSDictionary cosObject = f.getCOSObject();
    final String value = cosObject.getString(COSName.DV) == null ?
                   cosObject.getString(COSName.V) : cosObject.getString(COSName.DV);
    System.out.println("Setting " + f.getFullyQualifiedName() + ": " + value);
    try {
        f.setValue(value);
    } catch (final IOException e) {
        if (e.getMessage().matches("Could not find font: /.*")) {
            final String fontName = e.getMessage().replaceAll("^[^/]*/", "");
            System.out.println("Adding fallback font for: " + fontName);
            resources.put(COSName.getPDFName(fontName), PDType1Font.HELVETICA);
            try {
                f.setValue(value);
            } catch (final IOException e1) {
                e1.printStackTrace();
            }
        } else {
            e.printStackTrace();
        }
    }
    if (f instanceof PDNonTerminalField) {
        processFields(((PDNonTerminalField) f).getChildren(), resources);
    }
});

I would expect that the pdfs generated by the document.save() and job.print() to look identical in the Viewer, but they do not. If I take the document.save() generated pdf with readonly disabled, I can use a PDF Viewer like FoxitReader to fill the form and print it again. This produces the right output. Using the job.print() version, leads to disappearing of the text contained in the (text) form field. Has anyone a clue why this is the case?

I'm using PDFBox 2.0.13 (latest release) and LibreOffice 6.1.4.2. Here are the refered files and here you can download the debugger (jar file, runnable with java -jar ).

Upvotes: 2

Views: 1661

Answers (0)

Related Questions