如何使用 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
的任何方式。对于这些示例 (FileInputStream
、ByteArrayInputStream
),您甚至可以使用 reset()
.
re-use 相同的流
我们如何使用 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
的任何方式。对于这些示例 (FileInputStream
、ByteArrayInputStream
),您甚至可以使用 reset()
.