当前位置: 首页 > 知识库问答 >
问题:

PDFBox setValue后PDTextField自动调整大小行为不一致

白博赡
2023-03-14

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

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,如下所示:

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

现在,当我继续调用PDTextField上的设置值时,就会出现问题。由于我将默认外观字符串中的字体大小设置为0,因此根据库的示例,文本应自行缩放以适应文本框的给定区域。但是,对于某些字段,这种“按大小缩放”的行为是不一致的:它并不总是在PDTextField中选择最大的字体大小。是否有任何进一步的配置允许这种情况发生?下面是我注意到出现此问题的PDF。

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

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

旁注:我通过jruby使用PDFBox,jruby只是一个允许Ruby调用Java库的集成层。库可用的所有java方法;像这样的java方法可以一对一地转换为ruby方法。

更新

针对评论,第二个上载文件示例中不正确的外观包括:

  • 第1页居民姓名字段(两个文本字段的文本对于给定的输入字段大小来说太小)
  • 第二页电话字段(四个文本字段的文本溢出了给定的输入字段大小)

共有1个答案

苍嘉澍
2023-03-14

尤其是居民姓名字段、电话字段和护理提供者地址字段的外观更为明显。OP只提到前两个。

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

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

虽然高度是适当的,但图示符比应该的窄。实际上,这种效果已在原始PDF中看到:

这种水平压缩是由字段窗口小部件矩形的纵横比不同于分别匹配的正常外观流边界框引起的:

  • 小部件矩形: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

因此,它们具有相同的高度,但外观边界框的宽度大约是小部件矩形的两倍。因此,当外观显示在窗口小部件矩形中时,通常在外观流中绘制的文本会压缩到其宽度的一半。

设置字段值时,PDFBox不幸地重新使用了外观流原样,仅更新默认外观的详细信息,即字体名称、字体大小和颜色以及实际文本值,显然,由于某种原因,该外观的其他属性都是原样。因此,PDFBox输出也显示了这种水平压缩

要使PDFBox创建正确的外观,必须先删除旧外观,然后再设置新值。

填写的电话字段如下所示

同样,原始文件中也有类似的显示

即使整个单词有足够的空间,也只显示前两个字母,这是由于这些字段的配置:它们被配置为最大长度为2个字符的组合字段。

要在PDFBox完全显示且没有如此间隔的情况下设置此处的值,必须删除最大长度(或至少必须使其不小于值的长度)并取消设置梳标志。

填充它们看起来像这样:

最初它们看起来很相似:

这种垂直压缩也是由字段窗口小部件矩形的纵横比不同于分别匹配的正常外观流边界框引起的:

  • 小部件矩形:[278.6 642.928 458.36 657.96],即179.76*15.032
  • 外观边界框:[0 0 179.76 58.56],即179.76*58.56

与上面的常驻名称字段一样,在设置新值以使PDFBox创建正确的外观之前,需要删除旧外观。

实际上,在删除旧外观后,填写“护理提供者地址”字段时还有一个问题,它们看起来像这样:

这是由于PDFBox的一个缺点:这些字段被配置为多行文本字段。虽然单行文本字段的PDFBox会根据内容正确计算字体大小,然后精细地确保文本垂直贴合得很好,但对于多行字段,它进行得非常粗糙,它选择了12的硬编码字体大小,并且不会微调垂直位置,请参阅外观GeneratorHelper方法计算ateFontSize(PDFont, PDRectgle)插入Generated外观(PDAnnotationWidget, PD外观Stream, OutputStream)的代码。

由于在您的表单中,这些地址字段无论如何都只有一行高,一个明显的解决方案是将这些字段设置为单行字段,即清除多行标志。

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

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测试测试Fill0DropoldAppearanceNoCombNomaxNoMultiline)

现在不再垂直压缩常驻名称字段值:

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

 类似资料:
  • 我是JavaFX的新手,目前我试图构建一个小型聊天窗口。为此,我为我的Listview获得了以下自定义单元格布局。 网格 我使用外部HBox,所以我可以像whatsapp一样对齐消息。。。(左右对齐)。在我的GridPane中,我得到了两列,消息(标签)在左侧,其他一些随机的东西在右侧(时间戳,一些小图标)。现在我需要的是:GridPane/左列/标签的高度应该根据文本消息的长度动态地增长/收缩。

  • Android最近增加了根据视图大小以及最小和最大文本大小调整TextViews文本大小的支持。 https://developer.Android.com/guide/topics/ui/look-and-feel/autosizing-textView.html 不幸的是,他们不支持EditTexts,那么EditText还有其他的替代方案吗?

  • 问题内容: 我一直试图(徒劳地)建立一个页面,当我更改窗口大小时,其元素将重新调整大小。我可以在CSS中使用它来处理图像,但是没有问题,但是我似乎无法在文本上完成相同的操作,而且我不确定在CSS中是否有可能。而且我似乎找不到能完成此任务的jQuery脚本。 当用户调整窗口大小时,我实质上希望页面能够动态流畅地缩放,而无需用户调用页面缩放。通过css在我的img div上这可以正常工作,但对于文本则

  • 问题内容: 我在一个网格中嵌套了两个网格。不幸的是,右边的嵌套网格设置行的高度,以使左边和右边的网格都具有相同的高度,额外的空间在class的div之间共享。如何设置右侧嵌套网格的行以调整内容的大小,使其与左侧嵌套行的高度相同? 问题答案: 您可以尝试 参考 您也可以只使用或

  • 我在使用gmap组件时遇到了一个小问题:当我试图使组件可调整大小时(即在CSS的帮助下将地图的高度和宽度都设置为100%),组件会收缩,地图本身也会变得不可见。但如果设置了固定的高度/宽度,则组件工作良好。有没有一种方法可以自动调整GMAP的大小?

  • 所以,我试图在JavaFX中显示一个棋盘。我将不得不执行不同的操作和绘制一些瓷砖,所以我选择使用画布为每个瓷砖和一个网格窗格为我以网格的方式排列它们。 不幸的是,我有一些问题与网格瓷砖的大小;我想让我的整个棋盘自动适应它的大小来适应场景。因此,我在GridPane的height和width属性中添加了一个ChangeListener,它负责调整瓷砖的大小。这只在窗口变大时起作用,当窗口缩小到更小的