如何使用 PDFBOX 还原 pdf 中的增量更新?

How to revert incremental update in pdf using PDFBOX?

我们如何使用 pdfbox 恢复上次在 pdf 中完成的增量更新?

例如 Original document Signed document

当我使用增量保存对原始文档进行数字签名(认证签名)时,我得到了一个签名文档。检查签名文档的来源后,我可以看到“%%EOF”出现了 2 次。如果我手动删除最后一个“%%EOF”及其内容,我可以看到 PDF returns 到其初始状态,这与原始文档非常相似。

我怎样才能务实地做到这一点?

我正在使用 PDFBOX v2.0.8

此致, 阿布舍克

有更高级的方法,也有不太高级的方法。

这是最简单的一个:它搜索 %%EOF 标记,然后立即切断。这可能与以前的原始修订版不同,因为该标记后面可能跟有一个可选的 end-of-line 标记。但是,除非之前的修订版已签名或线性化,否则带有 end-of-line 标记的变体和没有标记的变体等同于 PDF 文件。

为了搜索 %%EOF 标记,我们使用 twitter/elephant-bird 项目中的 StreamSearcher class,参见。 this earlier stack overflow answer:

public List<Long> simpleApproach(InputStream pdf) throws IOException {
    StreamSearcher streamSearcher = new StreamSearcher("%%EOF".getBytes());
    List<Long> results = new ArrayList<>();
    long revisionSize = 0;
    long diff;
    while ((diff = streamSearcher.search(pdf)) > -1) {
        revisionSize += diff;
        results.add(revisionSize);
    }
    return results;
}

为了仅复制所需的字节数,我们使用 Guava ByteStreams class。 (有很多替代方案,例如 Apache Commons IO,但 Guava 恰好已经在我的测试项目依赖项中。)

List<Long> simpleSizes = null;
try (   InputStream resource = GET_DOCUMENT_INPUTSTREAM) {
    simpleSizes = simpleApproach(resource);
}

if (1 < simpleSizes.size()) {
    try (   InputStream resource = GET_DOCUMENT_INPUTSTREAM;
            OutputStream file = new FileOutputStream("previousRevision.pdf")) {
        InputStream revision = ByteStreams.limit(resource, simpleSizes.get(simpleSizes.size() - 2));
        ByteStreams.copy(revision, file);
    }
}

GET_DOCUMENT_INPUTSTREAM 可能是 new FileInputStream(PDF_PATH)new ByteArrayInputStream(PDF_BYTES) 或者您必须为 PDF 重复检索 InputStream 的任何方式。对于这些示例 (FileInputStreamByteArrayInputStream),您甚至可以使用 reset().

re-use 相同的流