setValue之后,PDFBox不一致的PDTextField自动调整大小行为 [英] PDFBox Inconsistent PDTextField Autosize Behavior after setValue

查看:275
本文介绍了setValue之后,PDFBox不一致的PDTextField自动调整大小行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Apache PDFBox在PDF文档上配置PDTextField,在该文档中,我使用以下方法将Lato加载到文档中:

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

然后我将font_name传递给PDTextFielddefault_appearance_string,就像这样:

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

当我继续在PDTextField上调用setValue时,就会出现此问题.因为我将defaultAppearanceString中的font_size设置为0,所以根据库的PDTextField.可能还有其他配置可能使这种情况发生吗?以下是我注意到此问题发生的PDF.

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.

未填充,已加载字体: http://www.filedropper.com/0postfontload

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

已填充,文本框的文本大小不一致: http://www.filedropper.com/file_327

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

旁注:我正在通过jruby使用PDFBox,这只是一个允许Ruby调用Java库的集成层.该库的所有java方法都可用;像thisExampleMethod这样的java方法将对ruby this_example_method进行一对一转换.

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.

更新

为回应评论,第二个上载文件示例中出现的外观不正确:

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

  • 第一页居民姓名"字段(两个文本字段的文本对于给定的输入字段大小而言太小了)
  • 第二页电话"字段(四个文本字段的文字超出了给定的输入字段大小)

推荐答案

特别是,居民姓名"字段,电话"字段和护理提供者地址"字段的外观明显. OP仅提及前两个.

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.

让我们检查这些字段;所有屏幕截图都是使用MS Windows上的Adobe Reader DC制作的:

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

填写的居民姓名"字段如下所示:

The filled in Resident Name fields look like this

虽然高度合适,但字形比其应有的窄.实际上,这种效果已经可以在原始PDF中看到了:

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:

  • 小部件矩形:[ 45.72 601.44 118.924 615.24 ][ 119.282 601.127 192.486 614.927 ],在两种情况下均为73.204 * 13.8.
  • 外观边界框:[ 0 0 147.24 13.8 ],即147.24 * 13.8.
  • 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.

不幸的是,当设置字段PDFBox的值时,它会原样重新使用外观流,并且仅更新默认外观的详细信息,即字体名称,字体大小和颜色以及实际文本值,显然假定其他属性外观是有原因的.因此,PDFBox输出也显示了这种水平压缩

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

要使PDFBox创建合适的外观,必须在设置新值之前删除旧外观.

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

填写的电话"字段如下所示:

The filled in Phone fields look like this

在原始文件中再次出现类似的显示

and again there is a similar display in the original file

即使整个单词有足够的空间,也仅显示前两个字母,这是由于以下字段的配置所致:它们被配置为梳齿字段,最大长度为2个字符.

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.

要在此处设置的值与PDFBox一起完整显示而不间隔开,必须删除最大长度(或者至少使其不小于值的长度)并取消设置梳状标志.

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.

填充后,它们看起来像这样:

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:

  • 小部件矩形:[ 278.6 642.928 458.36 657.96 ],即179.76 * 15.032.
  • 外观边界框:[ 0 0 179.76 58.56 ],即179.76 * 58.56.
  • 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.

就像上面的居民名称"字段一样,在设置新值以使PDFBox创建合适的外观之前,有必要删除旧外观.

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.

实际上,在删除看似看起来很旧的外观后,填写护理提供者地址"字段时,还有一个额外的问题:

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

这是由于PDFBox的缺点:这些字段被配置为多行文本字段.虽然用于单行文本字段的PDFBox会根据内容正确计算字体大小,随后又很好地确保文本在垂直方向上非常合适,但对于多行字段,它的处理却非常粗糙,它选择了12的硬编码字体大小,而不会微调垂直位置,请参见AppearanceGeneratorHelper方法calculateFontSize(PDFont, PDRectangle)insertGeneratedAppearance(PDAnnotationWidget, PDAppearanceStream, OutputStream)的代码.

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).

在您的表单中,这些地址字段始终只有一行高,一个明显的解决方案是将这些字段设置为单行字段,即清除 Multiline 标志.

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.

使用Java可以实现上述解决方案,如下所示:

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");
    }
}

(居民名称"字段值现在不再垂直压缩:

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

电话和护理提供者的地址字段现在看起来也很合适:

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

这篇关于setValue之后,PDFBox不一致的PDTextField自动调整大小行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆