PDFBox Inconsistent PDTextField Autosize Behavior after setValue

烂漫一生 提交于 2019-12-31 05:45:32

问题


I am using Apache PDFBox for configuration of PDTextField's on a PDF document where I load Lato onto the document using:

font = PDType0Font.load(
    @j_pd_document,
    java.io.FileInputStream.new('/path/to/Lato-Regular.ttf')
) # => Lato-Regular

font_name = pd_default_resources.add(font).get_name # => F4

I then pass the font_name into a default_appearance_string for the PDTextField like so:

j_text_field.set_default_appearance("/#{font_name} 0 Tf 0 g") # where font_name is
                                                              # passed in from above

The issue now occurs when I proceed to invoke setValue on the PDTextField. Because I set the font_size in the defaultAppearanceString to 0, according to the library's example, the text should scale itself to fit in the text box's given area. However, the behaviour of this 'scale-to-fit' is inconsistent for certain fields: it does not always choose the largest font size to fit in the PDTextField. Might there be any further configuration that might allow for this to happen? Below are the PDFs where I've noticed this problem occurring.

Unfilled, with fonts loaded: http://www.filedropper.com/0postfontload

Filled, with inconsisteny textbox text sizing: http://www.filedropper.com/file_327

Side Note: I am using PDFBox through jruby which is just a integration layer that allows Ruby to invoke Java libraries. All java methods for the library available; a java method like thisExampleMethod would have a one-to-one translation into ruby this_example_method.


Updates

In response to comments, the appearances that are incorrect in the second uploaded file example are:

  • 1st page Resident Name field (two text fields that have text that is too small for the given input field size)
  • 2nd page Phone fields (four text fields that have text that overflows the given input field size)

回答1:


Especially the appearances of the Resident Name fields, the Phone fields, and the Care Providers Address fields appear conspicuous. Only the former two are mentioned by the OP.

Let's inspect these fields; all screen shots are made using Adobe Reader DC on MS Windows:

The Resident Name fields

The filled in Resident Name fields look like this

While the height is appropriate, the glyphs are narrower than they should be. Actually this effect can already be seen in the original PDF:

This horizontal compression is caused by the field widget rectangles having a different aspect ratio than the respectively matching normal appearance stream bounding box:

  • The widget rectangles: [ 45.72 601.44 118.924 615.24 ] and [ 119.282 601.127 192.486 614.927 ], i.e. 73.204*13.8 in both cases.
  • The appearance bounding box: [ 0 0 147.24 13.8 ], i.e. 147.24*13.8.

So they have the same height but the appearance bounding box is approximately twice as wide as the widget rectangle. Thus, the text drawn normally in the appearance stream gets compressed to half its width when the appearance is displayed in the widget rectangle.

When setting the value of a field PDFBox unfortunately re-uses the appearance stream as is and only updates details from the default appearance, i.e. font name, font size, and color, and the actual text value, apparently assuming the other properties of the appearance are as they are for a reason. Thus, the PDFBox output also shows this horizontal compression

To make PDFBox create a proper appearance, it is necessary to remove the old appearances before setting the new value.

The Phone fields

The filled in Phone fields look like this

and again there is a similar display in the original file

That only the first two letters are shown even though there is enough space for the whole word, is due to the configuration of these fields: They are configured as comb fields with a maximum length of 2 characters.

To have a value here set with PDFBox displayed completely and not so spaced out, you have to remove the maximum length (or at least have to make it no less than the length of your value) and unset the comb flag.

The Care Providers Address fields

Filled in they look like this:

Originally they look similar:

This vertical compression is again caused by the field widget rectangles having a different aspect ratio than the respectively matching normal appearance stream bounding box:

  • A widget rectangle: [ 278.6 642.928 458.36 657.96 ], i.e. 179.76*15.032.
  • The appearance bounding box: [ 0 0 179.76 58.56 ], i.e. 179.76*58.56.

Just like in the case of the Resident Name fields above it is necessary to remove the old appearances before setting the new value to make PDFBox create a proper appearance.

A complication

Actually there is an additional issue when filling in the Care Providers Address fields, after removing the old appearances they look like this:

This is due to a shortcoming of PDFBox: These fields are configured as multi line text fields. While PDFBox for single line text fields properly calculates the font size based on the content and later finely makes sure that the text vertically fits quite well, it proceeds very crudely for multi line fields, it selects a hard coded font size of 12 and does not fine tune the vertical position, see the code of the AppearanceGeneratorHelper methods calculateFontSize(PDFont, PDRectangle) and insertGeneratedAppearance(PDAnnotationWidget, PDAppearanceStream, OutputStream).

As in your form these address fields anyways are only one line high, an obvious solution would be to make these fields single line fields, i.e. clear the Multiline flag.

Example code

Using Java one can implement the solutions explained above like this:

final int FLAG_MULTILINE = 1 << 12;
final int FLAG_COMB = 1 << 24;

PDDocument doc = PDDocument.load(originalStream);
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();

PDType0Font font = PDType0Font.load(doc, fontStream, false);
String font_name = acroForm.getDefaultResources().add(font).getName();

for (PDField field : acroForm.getFieldTree()) {
    if (field instanceof PDTextField) {
        PDTextField textField = (PDTextField) field;
        textField.getCOSObject().removeItem(COSName.MAX_LEN);
        textField.getCOSObject().setFlag(COSName.FF, FLAG_COMB | FLAG_MULTILINE, false);;
        textField.setDefaultAppearance(String.format("/%s 0 Tf 0 g", font_name));
        textField.getWidgets().forEach(w -> w.getAppearance().setNormalAppearance((PDAppearanceEntry)null));
        textField.setValue("Test");
    }
}

(FillInForm test testFill0DropOldAppearanceNoCombNoMaxNoMultiLine)

Screen shots of the output of the example code

The Resident Name field value now is not vertically compressed anymore:

The Phone and Care Providers Address fields also look appropriate now:



来源:https://stackoverflow.com/questions/56938135/pdfbox-inconsistent-pdtextfield-autosize-behavior-after-setvalue

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!