Apache PDFBox 表单填充 TrueType 文本间距问题

Apache PDFBox Form Fill TrueType text spacing issue

我正在使用 Apache PDFBox 填写 PDF 表单。我使用的是一种名为 'Impact' 的 TrueType 字体(不是默认字体),非常标准。在模板中,我有一个名为 "Title" 的字段,其中分配了 Impact 字体。我使用下面的代码获取该模板并使用其中包含多个单词的值填充该字段。

问题是当您查看创建的 PDF 时,单词之间有很大的空格。如果您在 Acrobat 中打开 PDF 并单击该字段,文本会改变并且大间距会消失。以任何方式编辑该字段将永久纠正该问题,但我生成的表格不会在事后更改。

我用默认字体(在本例中为 Helvetica)尝试了相同的实验,但上述问题不存在。我可以创建一个空白表单并添加一个字段并设置自定义字体并复制问题。

我读到类似的问题在 2.0.0 中得到解决,PDFBOX-2062 但它是为了更改字体大小,而不是自定义字体。

我正在使用 PDFBox 版本 2.0.1。

public static void main(String[] args) throws IOException {

    String formTemplate = "/BLANK.pdf";
    String outputPDF = "/FillFormField.pdf";

    // load the documents
    PDDocument pdfDocument = PDDocument.load(new File(formTemplate));

    // get the document catalog
    PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();

    // as there might not be an AcroForm entry a null check is necessary
    if (acroForm != null)
    {
        PDTextField field = (PDTextField) acroForm.getField( "Title" );
        field.setValue("Low Mileage Beauty");
    }

    // Save and close the filled out form.
    pdfDocument.save(outputPDF);
    pdfDocument.close();

}

问题是由两个因素共同造成的:

  • PDFBox 编写文本时的一个怪癖和
  • 源 PDF 中的字体对象不一致。

PDFBox 怪癖

将文本写入内容流时,PDFBox 将每个 Unicode 代码点转换为一个名称,并在从倒置字体编码生成的映射中查找该名称。

本例中的字体编码为MacRomanEncoding。在该编码中(和 WinAnsiEncoding 中类似)有两个到名称 space 的映射,请参见。 PDF 规范 ISO 32000-1 的附件 D2,其中一个在 table:

中给出
          CHAR CODE (OCTAL)
CHAR NAME  STD MAC WIN PDF
...
     space 040 040 040 040
...

和脚注 6 中的一个:

  1. The SPACE character shall also be encoded as 312 in MacRomanEncoding and as 240 in WinAnsiEncoding. This duplicate code shall signify a nonbreaking space; it shall be typographically the same as (U+003A) SPACE.

倒置字体编码只能有一个名称值space恰好是八进制312(= 十进制 202)。

由于两个 space 字形预计 在排版上相同,这个怪癖应该是无害的。但是:

PDF 中的字体不一致

PDF 中的字体 Impact 定义为普通 space 字形的宽度为 176,不间断 space 字形的宽度为 750。因此,它们在排版上有很大差异。

由于 PDF 中的 Impact 被定义为具有 MacRomanEncoding(这里有一些无关紧要的微小变化),但是,这两个字形是必需的("shall" 表示要求)印刷相同,参见。上面引用的脚注。

如何处理这个

第一个快速的选择是,正如@Tilman 已经在评论中推荐的那样,

to set acroForm.setNeedAppearances(true)

这设置了一个标志,指示 PDF 查看器它应该重新创建外观内容流。不过,这可能不适用于某些预览器。

下一个选项是修复包含不一致字体定义的源 PDF。

最终 PDFBox 可能想要摆脱这个怪癖。虽然在排版上绘制哪个 space 变体应该没有区别,但选择不间断的变体是一种诱人的命运。