How to use TTF font with PDFBox AcroForm and then flatten document?

1.2k Views Asked by At

I have been trying to make a fillable PDF file with LibreOffice Writer 7.2.2.2. Here is how the document looks like: enter image description here All fields right of the vertical lines are form textboxes, each one having its own name(tbxOrderId, tbxFullName...). Each textbox uses SF Pro Text Light as font. Only the one on the bottom right(tbxTotal) - Total €123.00 has Oswald Regular. The document looks alright when I fill these fields with LibreOffice Writer.

Below this are my export settings. I chose Archive PDF A-2b in order to embed the fonts into the document. enter image description here

Here is the output when I run pdffonts to the exported PDF file. enter image description here

However, when I run the following code which just changes the values of tbxOrderId and tbxTotal, the output PDF document is missing these fonts.

public class Start {
    public static void main(String[] args) {
        try {
            PDDocument pDDocument = PDDocument.load(new File("/media/stoyank/Elements/Java/tmp/Receipt.pdf"));
            PDAcroForm pDAcroForm = pDDocument.getDocumentCatalog().getAcroForm();

            PDField field = pDAcroForm.getField("tbxOrderId");
            field.setValue("192753");
            field = pDAcroForm.getField("tbxTotal");
            field.setValue("Total: €192.00");

            pDAcroForm.flatten();
            pDDocument.save("/media/stoyank/Elements/Java/tmp/output.pdf");
            pDDocument.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

This is how the output document looks like: enter image description here

I tried to add the font manually by referring to this Stackoverflow question, but still no success:

PDDocument pDDocument = PDDocument.load(new File("/media/stoyank/Elements/Java/tmp/Receipt.pdf"));
PDAcroForm pDAcroForm = pDDocument.getDocumentCatalog().getAcroForm();

InputStream font_file = ClassLoader.getSystemResourceAsStream("Oswald-Regular.ttf");
PDType0Font font = PDType0Font.load(pDDocument, font_file, false);
if (font_file != null) font_file.close();

PDResources resources = pDAcroForm.getDefaultResources();
if (resources == null) resources = new PDResources();

resources.put(COSName.getPDFName("Oswald-Regular"), font);
pDAcroForm.setDefaultResources(resources);
pDAcroForm.refreshAppearances();

PDField field = pDAcroForm.getField("tbxOrderId");
field.setValue("192753");
field = pDAcroForm.getField("tbxTotal");
field.setValue("Total: €192.00");

pDAcroForm.flatten();
pDDocument.save("/media/stoyank/Elements/Java/tmp/output.pdf");
pDDocument.close();

After I write into these textbox fields, I want to flatten the document.

Here is my folder structure:

enter image description here

System: Ubuntu 20.04

Also, here is a link to the ODT file that I then export to a PDF and the exported PDF.

1

There are 1 best solutions below

6
Tilman Hausherr On

Your file doesn't have correct appearance streams for the fields, this is a bug from the software that created the PDF. Call pDAcroForm.refreshAppearances(); as early as possible.

The code in pastebin is fine (it is based on CreateSimpleFormWithEmbeddedFont.java example), except that you should keep the default resources and not start with empty resources. So your code should look like this:

pDAcroForm.refreshAppearances();

PDType0Font formFont = PDType0Font.load(pDDocument, ...input stream..., false);

PDResources resources = pDAcroForm.getDefaultResources();
if (resources == null)
{
    resources = new PDResources();
    pDAcroForm.setDefaultResources(resources);
}

final String fontName = resources.add(formFont).getName();

// 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 = "/" + fontName + " 0 Tf 0 g";

PDTextField field = (PDTextField) (pDAcroForm.getField("tbxTotal"));
field.setDefaultAppearance(defaultAppearanceString);
field.setValue("Total: €192.00");

enter image description here