我使用追加模式签署的PDF将从Office Word 2016导出。
这是我的档案:word.pdf
我收到此错误消息:
com.itextpdf.kernel.PdfException: Append mode requires a document without errors, even if recovery is possible.
我使用的是iText7 7.0.4。
答案 0 :(得分:3)
这实际上是iText 7中创建混合参考文件的增量更新的错误。
不幸的是,问题中的描述没有清楚地描述重现错误的方法。因此,错误可以像这样重现:
以附加模式标记OP的sample document(它不需要是签名用例)。
此步骤 尚未创建相关错误。
在追加模式下再次标记步骤1的输出(同样不需要签名)。
在此步骤中例外
com.itextpdf.kernel.PdfException: Append mode requires a document without errors, even if recovery is possible.
发生。
OP的PDF特别是混合参考文件。根据PDF规范(ISO 32000-1)这样的文件
可供读者阅读,仅用于支持PDF 1.5之前的PDF版本。除了交叉引用流引用的对象流中的对象之外,此类文件还包含标准交叉引用表引用的对象。
如果是这些文件, startxref 偏移量指向1.5之前的交叉引用表的开头,预告片 XRefStm 条目指向1.5交叉引用流。
PDF规范进一步规定了
XRefStm条目不得用于主要交叉引用部分的预告字典中,而只能用于更新交叉引用部分。
因此文件中有趣的构造:
18 0 obj
<</Type/ObjStm/N 10/First 67/Filter/FlateDecode/Length 357>>
stream
[...object stream data...]
endstream
endobj
[...]
25 0 obj
<</Type/XRef/Size 25/W[ 1 4 2] /Root 1 0 R/Info 9 0 R/ID[<8812105F6F93284DAEF240C8C1FC4C4E><8812105F6F93284DAEF240C8C1FC4C4E>] /Filter/FlateDecode/Length 97>>
stream
[...cross reference stream data...]
endstream
endobj
xref
0 26
[...cross reference table with 25 entries, objects in object stream are marked free...]
trailer
<</Size 26/Root 1 0 R/Info 9 0 R/ID[<8812105F6F93284DAEF240C8C1FC4C4E><8812105F6F93284DAEF240C8C1FC4C4E>] >>
startxref
[points to the preceding cross reference table]
48341
%%EOF
xref
0 0
[...empty incremental update cross reference table...]
trailer
[XRefStm points to the cross reference stream in object 25]
<</Size 26/Root 1 0 R/Info 9 0 R/ID[<8812105F6F93284DAEF240C8C1FC4C4E><8812105F6F93284DAEF240C8C1FC4C4E>] /Prev 48341/XRefStm 48045>>
startxref
[points to the empty incremental update cross reference table]
49017
%%EOF
因此,虽然看起来很滑稽,但这种结构是正确的。
当阅读原始文档时,iText 7识别出该文档包含交叉引用表和交叉引用流,并选择交叉引用流。 (实际上PdfReader.readXrefSection
首先读取空的交叉引用表,然后在预告片中找到 XRefStm 条目,然后读取交叉引用流。)
创建增量更新时,iText 7会记住源PDF已通过交叉引用流进行解析,因此使用完全压缩,即特别是它使用对象流和交叉引用流。
在创建交叉引用流时,它会将上一个条目设置为原始PDF指向的最终 startxref ,即空交叉引用表,而不是它实际使用的交叉引用流。
不允许使用此类混合构造(指向交叉引用表的交叉引用流为上一个)。
因此,第一步中的iText在其结果文档中创建了一个无效的交叉引用结构,因此,在第二步中发现了一个损坏的PDF来处理和抱怨。
答案 1 :(得分:0)
您尝试在追加模式中更改的文档已损坏。最有可能的是,交叉引用表中定义的字节偏移量与PDF对象的实际字节位置不对应。
在你的情况下,我在文件末尾看到一些奇怪的东西:
xref
0 26
0000000010 65535 f
0000000017 00000 n
0000000166 00000 n
0000000222 00000 n
0000000492 00000 n
0000000755 00000 n
0000000932 00000 n
0000001180 00000 n
0000001233 00000 n
0000001286 00000 n
0000000011 65535 f
0000000012 65535 f
0000000013 65535 f
0000000014 65535 f
0000000015 65535 f
0000000016 65535 f
0000000017 65535 f
0000000018 65535 f
0000000019 65535 f
0000000020 65535 f
0000000000 65535 f
0000001961 00000 n
0000002154 00000 n
0000044863 00000 n
0000048000 00000 n
0000048045 00000 n
trailer
<</Size 26/Root 1 0 R/Info 9 0 R/ID[<8812105F6F93284DAEF240C8C1FC4C4E><8812105F6F93284DAEF240C8C1FC4C4E>] >>
startxref
48341
%%EOF
xref
0 0
trailer
<</Size 26/Root 1 0 R/Info 9 0 R/ID[<8812105F6F93284DAEF240C8C1FC4C4E><8812105F6F93284DAEF240C8C1FC4C4E>] /Prev 48341/XRefStm 48045>>
startxref
49017
%%EOF
你有一张带有两个预告片的PDF。一个预告片声称存储在流中的交叉引用表:
/XRefStm 48045
同时在字节位置49017处指示交叉引用表的开始:
startxref
49017
另一个预告片声称有一个未压缩的交叉引用表,它从字节位置48341开始:
startxref
48341
确实:有一个未压缩的交叉引用流:
xref
0 26
0000000010 65535 f
0000000017 00000 n
您了解档案中的不一致吗?
当您使用追加模式时,iText不会更改原始文档的任何内容:不会更改单个字节;在原始文件的最终%%EOF
标记之后添加新字节。但是,当原始文件被破坏时,iText拒绝执行此操作。我希望你理解这个理由:如果iText允许你这样做,你会让情况变得更糟。
要解决此问题,您需要先修复损坏的文件。这可以通过&#34;操纵&#34;文档没有更改任何内容,但在正常模式下执行此操作,而不是在追加模式下执行此操作。
您是否尝试过删除额外的预告片。我扔掉了:
xref
0 0
trailer
<</Size 26/Root 1 0 R/Info 9 0 R/ID[<8812105F6F93284DAEF240C8C1FC4C4E><8812105F6F93284DAEF240C8C1FC4C4E>] /Prev 48341/XRefStm 48045>>
startxref
49017
%%EOF
Adobe Reader在删除这些字节后没有抱怨。
答案 2 :(得分:0)
因此,由于该页面在该错误的搜索结果中排名较高,但没有提供太多恢复步骤,所以我想我已经发布了如何解决此问题。
给定:
我发现 iTextSharp 中的某些操作会强制恢复。这并不完全“干净”,因为它会修改文件,但是由于您收到此错误,您可能更关心完成某些事情,而不是完全符合 PDF 规范。
解决方法基本上只是向 PDF 添加一个空的文本位。就我而言,这让我可以继续处理收到的文件。
public byte[] InsertEmptyText(byte[] file)
{
var customText = new CustomText();
customText.FontSize = 1;
customText.Align = TextAlign.Right;
customText.Text = "";
customText.StartingPointPosition = new System.Drawing.Point(50, 50);
customText.PageNumber = 1;
PdfInsertObject pi = new PdfInsertObject();
pi.LoadPdfDocument(file);
pi.AddText(customText);
return pi.InsertObjects();
}
在创建 PdfReader 并通过它传递数据(并捕获结果)之前,让我继续。