即使可以恢复,追加模式也要求文档没有错误

时间:2017-11-14 08:47:54

标签: itext7

我使用追加模式签署的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。

3 个答案:

答案 0 :(得分:3)

这实际上是iText 7中创建混合参考文件的增量更新的错误。

错误情况

不幸的是,问题中的描述没有清楚地描述重现错误的方法。因此,错误可以像这样重现:

  1. 以附加模式标记OP的sample document(它不需要是签名用例)。

    此步骤 尚未创建相关错误。

  2. 在追加模式下再次标记步骤1的输出(同样不需要签名)。

    在此步骤中例外

    com.itextpdf.kernel.PdfException: Append mode requires a document without errors, even if recovery is possible.
    

    发生。

  3. 有问题的PDF

    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

Adob​​e 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 并通过它传递数据(并捕获结果)之前,让我继续。