PDFBox嵌入式TTF字体无法工作

7

我正在使用PDFBox从现有的PDF模板构建文档,以便打开文件、添加文本并保存。它很好用,但是当尝试使用外部TTF字体时就会出现问题。我尝试了不同的方法并搜索了两天的解决方案,但PDFBox上没有太多的信息。

下面是一些代码,使用字体“Tardy Kid”,因为它不会被误认为是其他任何东西,并且不太可能成为任何标准库的一部分。

代码执行良好,从println中显示“TardyKid”(表明字体已加载并且名称可获取),并显示文本——但它是用Helvetica字体显示的。代码中更复杂的部分使用getStringWidth()来计算宽度,似乎也表明成功加载了宽度表。它只是不能正确地显示。

该代码在一个较大程序的上下文中运行,该程序打开现有的PDF文档(一个模板)并向其添加文本。除此之外,它似乎都正常工作。

 public void setText ( PDDocument document, String text ) throws IOException {
     int lastPage = document.getNumberOfPages() - 1;
     PDPage page = (PDPage) document.getDocumentCatalog().getAllPages().get(lastPage);
     PDPageContentStream contentStream = null;
     try {
         contentStream = new PDPageContentStream(document,page,true,true,false);
         File fontFile = new File(m_fontDir, "Tardy_Kid.ttf");
         PDFont font = PDTrueTypeFont.loadTTF(document, fontFile);
         Color color =  new Color(196, 18, 47);
         float x = 100f, y = 700f;
         System.out.println(font.getBaseFont());
         contentStream.setFont(font, 32);
         contentStream.setNonStrokingColor(color);
         contentStream.beginText();
         contentStream.moveTextPositionByAmount(x,y);
         contentStream.drawString(text);
         contentStream.endText();
     } finally {
         if (contentStream != null) {
             contentStream.close();
         }
     }
 }

经过进一步测试,似乎只有在为另一段文本再次调用SetFont之后才会出现问题。所有文本似乎都会恢复到上次设置的字体。如果我只设置一段文本或多个使用相同字体(Tardy Kid)的文本,则可以正常工作。 - Glenn Reid
3个回答

5
我找到了答案。我不确定这是否是PDFBox中的一个错误,但如果您在同一页上打开/关闭多次内容流(由PDPageContentStream返回),它将无法正常工作。因此,在setText例程内部打开/关闭内容流在同一页上调用该例程多次时无效。将流移动到例程外部,并为整个页面打开/关闭流似乎可以解决此问题(以及其他一些问题)。
文档或示例代码中没有提到这一点,而且非常微妙。我会称之为错误,特别是因为它“工作”(不会引发任何异常),但会在页面上创建不确定和/或错误的结果。

2

我曾经遇到过类似的问题,这是由于pom更新时在构建war文件时破坏了pdf模板文件。

堆栈跟踪显示“无法读取TimesNewRoman,Bold字体的嵌入式TTF”,当然,在看到与“pushback size”相关的错误后,我们设置了一个新的属性值以继续(我看到的异常参考:org.apache.pdfbox.exceptions.WrappedIOException: Could not push back 480478 bytes in order to reparse stream. Try increasing push back buffer using system property org.apache.pdfbox.baseParser.pushBackSize)。

我们花了一段时间,但在解压war并尝试在war中打开pdf文件后,我们注意到它已经损坏了,但源中的pdf文件没有损坏。

我们问题的根本原因是我们在pom中为资源文件夹添加了“filtering”。我们这样做是为了使用一些反射在我们的健康检查页面中获取一些值,但这却破坏了pdf文件,我们从以下参考资料中找出了原因:https://bitbucket.org/petermr/xhtml2stm/issues/12/pdf-files-are-being-corrupted-at-some

以下是我们设置的过滤示例:

<resources>
    <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
    </resource>
</resources>

我们的解决方案是从pom中删除这个内容,并重新设计我们在健康页面获取信息的方法。

0
经过多年的发展,PDFBOX接近3.0.0版本的发布(但官方版本为2.0.23),上述问题(特别是Unicode)似乎可以使用PDType0Font.load()解决(在2.0版本的迁移指南这里中提到),根据SO上的大部分问题。
我曾经遇到同样的问题,后来发现在使用PDDocument.saveIncremental()时出了问题——我认为这需要仔细考虑(已知需要仔细考虑),因为你需要在许多不容易立即找到的地方调用getCOSObject().setNeedToBeUpdated(true)。所以,为了缩小可能出现的问题范围,请检查一下简单的PDDocument.save()是否可行。

顺便说一下,我确实检查了其他建议,即只打开和写入一次PDPageContentStream,以及检查字体本身是否被Maven资源过滤器损坏,但它们都不是问题所在。为了排除第二个问题,并提供信息,如果您需要LiberationSans-Regular TTF字体,它作为资源嵌入在PDFBOX中, 不需要将其添加到您自己的资源中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接