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

时间:2018-03-20 11:03:37

标签: java pdf digital-signature pdfbox

我们如何使用pdfbox恢复pdf中的最后一次增量更新?

例如 Original document Signed document

当我使用增量保存对原始文档进行数字签名(证书签名)时,我会收到签名文档。在检查签名文件的来源后,我可以看到" %% EOF"正在呈现2次。如果我手动删除最后一个" %% EOF"连同其内容,我可以看到PDF返回其初始状态,这与原始文档非常相似。

我该如何务实地做到这一点?

我正在使用PDFBOX v2.0.8

最诚挚的问候, 阿布舍克巴克

1 个答案:

答案 0 :(得分:2)

有更先进的方法,而且还有不太先进的方法。

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

为了搜索%%EOF标记,我们使用来自twitter / elephant-bird项目的StreamSearcher类,参见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类。 (有许多替代方案,例如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()重复使用相同的流。