使用 PDFBox Annotation constructAppearances() 方法获取 OutOfMemoryError

Getting OutOfMemoryError with PDFBox Annotation constructAppearances() method

一言以蔽之

我一直在开发一个获取 pdf 的程序,突出显示一些单词(通过 pdfbox 标记注释)并保存新的 pdf。

为了让这些注释在某些查看器(如 pdf.js 上可见),需要在将标记注释添加到页面注释列表之前调用 pdAnnotationTextMarkup.constructAppearances()。

但是,通过这样做,我在处理包含数千个标记注释的大型文档时遇到了 OutOfMemoryError。

我想知道是否有办法防止这种情况发生。

(这是 的 sequel 的一种,但与此关系不大)

技术规格:

PDFBox 2.0.17
Java 11.0.6+10,采用OpenJDK
MacOS Catalina 10.15.2, 16gb, x86_64

我的代码

//my pdf has 216 pages     
for (int pageIndex = 0; pageIndex < numberOfPages; pageIndex++) {
    PDPage page = document.getPage(pageIndex);
    List<PDAnnotation> annotations = page.getAnnotations();

    // each coordinate obj represents a hl annotation. crashing with 7.816 elements
    for (CoordinatePoint coordinate : coordinates) {
        PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
        txtMark.setRectangle(pdRectangle);
        txtMark.setQuadPoints(quadPoints);
        txtMark.setColor(getColor());
        txtMark.setTitlePopup(coordinate.getHintDescription());
        txtMark.setReadOnly(true);

        // this is what makes everything visible on pdf.js and what causes the Java heap space error
        txtMark.constructAppearances();

        annotations.add(txtMark);
    }
}

当前结果

这是导致问题的大量 pdf 文档: https://pdfhost.io/v/I~nu~.6G_French_Intensive_Care_Society_International_congress_Ranimation_2016.pdf

我的程序试图在整个 216 页中添加 7.816 注释。

和堆栈跟踪:

[main] INFO highlight.PDFAnnotation - Highlighting 13613_2016_Article_114.pdf...
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at org.apache.pdfbox.io.ScratchFile.<init>(ScratchFile.java:128)
    at org.apache.pdfbox.io.ScratchFile.getMainMemoryOnlyInstance(ScratchFile.java:143)
    at org.apache.pdfbox.cos.COSStream.<init>(COSStream.java:61)
    at org.apache.pdfbox.pdmodel.interactive.annotation.handlers.PDAbstractAppearanceHandler.createCOSStream(PDAbstractAppearanceHandler.java:106)
    at org.apache.pdfbox.pdmodel.interactive.annotation.handlers.PDHighlightAppearanceHandler.generateNormalAppearance(PDHighlightAppearanceHandler.java:136)
    at org.apache.pdfbox.pdmodel.interactive.annotation.handlers.PDHighlightAppearanceHandler.generateAppearanceStreams(PDHighlightAppearanceHandler.java:59)
    at org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup.constructAppearances(PDAnnotationTextMarkup.java:175)
    at org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup.constructAppearances(PDAnnotationTextMarkup.java:147)
    at highlight.PDFAnnotation.drawHLAnnotations(PDFAnnotation.java:288)

我已经尝试将我的 jvm xmx 和 xms 参数增加到 -Xmx10g -Xms10g,这只是稍微推迟了崩溃。

我想要什么

我想避免这个内存问题,并且仍然能够在 pdf.js 查看器中看到我的注释。不调用 constructAppearances 过程要快得多,我没有这个问题,但是注释只能在某些 pdf 查看器上看到,比如 Adob​​e。

有什么建议吗?我是不是做错了什么或者遗漏了什么?

在即将发布的2.0.19版本中,构建外观如下:

annotation.constructAppearances(document);

在 2.0.18 及更早版本中,您需要自己初始化外观处理程序:

setCustomAppearanceHandler(new PDHighlightAppearanceHandler(annotation, document));

该行可以在 2.0.19 中删除,因为这是默认的外观处理程序。

为什么会这样?因此,文档公共内存 space ("scratch file") 用于注释处理程序,而不是每次都创建一个新的(这很大)。后者是在调用 new COSStream() 而不是 document.getDocument().createCOSStream() 时完成的。

所有这些当然只有在做很多注释时才重要。

相关 PDFBox 问题:PDFBOX-4772 and PDFBOX-4080