2

I'm writing an app that uses PDFbox library to fill fields in a PDF file.
In one of those field, I'm setting the text to be written in Hebrew letters.
When I run the code on my Android device, I get the following log:

java.lang.IllegalArgumentException: This font type only supports 8-bit code points
    at com.tom_roush.pdfbox.pdmodel.font.PDType1Font.encode(PDType1Font.java:317)
    at com.tom_roush.pdfbox.pdmodel.font.PDFont.encode(PDFont.java:264)
    at com.tom_roush.pdfbox.pdmodel.font.PDFont.getStringWidth(PDFont.java:293)
    at com.tom_roush.pdfbox.pdmodel.interactive.form.PlainTextFormatter.format(PlainTextFormatter.java:183)
    at com.tom_roush.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.insertGeneratedAppearance(AppearanceGeneratorHelper.java:360)
    at com.tom_roush.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.setAppearanceContent(AppearanceGeneratorHelper.java:224)
    at com.tom_roush.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.setAppearanceValue(AppearanceGeneratorHelper.java:128)
    at com.tom_roush.pdfbox.pdmodel.interactive.form.PDTextField.constructAppearances(PDTextField.java:247)
    at com.tom_roush.pdfbox.pdmodel.interactive.form.PDTerminalField.applyChange(PDTerminalField.java:221)
    at com.tom_roush.pdfbox.pdmodel.interactive.form.PDTextField.setValue(PDTextField.java:202)
    at com.package.app.MainActivity.lambda$checkPdf$4$MainActivity(MainActivity.java:128)
    at com.package.app.MainActivity$$Lambda$2.run(Unknown Source:18)
    at java.lang.Thread.run(Thread.java:764)

I've tried to find some information about it all over Stack Overflow, but none of the answers I found is related to filling forms. It's all related to PDPageContentStream.

This is how I fill the form in my code:

try {
    PDDocument document = PDDocument.load(getAssets().open("file.pdf"));
    PDDocumentCatalog docCatalog = document.getDocumentCatalog();
    PDAcroForm acroForm = docCatalog.getAcroForm();

    // Fill the text field
    ((PDTextField) acroForm.getField("name")).setValue("בדיקה");

    File root = android.os.Environment.getExternalStorageDirectory();

    String path = root.getAbsolutePath() + "/test.pdf";
    document.save(path);
    document.close();
} catch (IOException e) {
    Log.e("e", e.getMessage());
}

Can you please help me solve this error and fill Hebrew letters in a form using PDFbox?

Ido Naveh
  • 2,442
  • 3
  • 26
  • 57
  • 1
    Don't know if this also works for PDFBox for Android, but this answer shows how to replace a field font: https://stackoverflow.com/questions/47995062/ – Tilman Hausherr Feb 04 '19 at 11:02
  • @TilmanHausherr Thanks! That really helped. The only problem I have right now, is that the Hebrew text is being shown from left to right, while it should be shown as right to left. Do you have any idea what to do about it? – Ido Naveh Feb 04 '19 at 16:20
  • Ooops, I forgot that one, sorry :-( No, there is no solution for it, not even in PDFBox for desktop. All you could do not is to hack the PDFBox for Android source code, i.e. PlainTextFormatter to reverse the string when it is Hebrew and without any numbers or other stuff that isn't RTL, maybe with icu4j. – Tilman Hausherr Feb 04 '19 at 16:29
  • @TilmanHausherr OK, thank you anyway! – Ido Naveh Feb 04 '19 at 18:41

1 Answers1

0

I used this answer to change the font of the field's text. The only problem is that now the text was facing the wrong direction, so I changed the direction of the string:

try {
    PDDocument document = PDDocument.load(getAssets().open("file.pdf"));
    PDDocumentCatalog docCatalog = document.getDocumentCatalog();
    PDAcroForm acroForm = docCatalog.getAcroForm();
    PDResources dr = acroForm.getDefaultResources();

    PDFont liberationSans = PDType0Font.load(document, getAssets().open("com/tom_roush/pdfbox/resources/ttf/LiberationSans-Regular.ttf"));
    COSName fontName = dr.add(liberationSans);
    Iterator<PDField> it = acroForm.getFields().iterator();
    while (it.hasNext()) {
        PDField field = it.next();
        if (field instanceof PDTextField) {
            PDTextField textField = (PDTextField) field;
            String da = textField.getDefaultAppearance();

            // replace font name in default appearance string
            Pattern pattern = Pattern.compile("\\/(\\w+)\\s.*");
            Matcher matcher = pattern.matcher(da);
            String oldFontName = matcher.group(1);
            da = da.replaceFirst(oldFontName, fontName.getName());

            textField.setDefaultAppearance(da);
        }
    }

    // Fill the text field
    ((PDTextField) acroForm.getField("name")).setValue(new StringBuilder("בדיקה").reverse().toString());

    File root = android.os.Environment.getExternalStorageDirectory();

    String path = root.getAbsolutePath() + "/test.pdf";
    document.save(path);
    document.close();
} catch (IOException e) {
    Log.e("e", e.getMessage());
}
Ido Naveh
  • 2,442
  • 3
  • 26
  • 57
  • But now the problem is that the logical content of the field is also reversed - important when the form is read by a computer. A possible solution would be to do a low-level reassignment of the original string with `field.getCOSObject().setString(COSName.V, string)`. – Tilman Hausherr Feb 18 '19 at 08:18