这是 readPages 的(java,抱歉)源代码:
protected internal void ReadPages() {
catalog = trailer.GetAsDict(PdfName.ROOT);
rootPages = catalog.GetAsDict(PdfName.PAGES);
pageRefs = new PageRefs(this);
}
trailer,
目录,
rootPages , and
pageRefs`都是PdfReader的成员变量。
如果只是缺少 PDF 的预告片或根/目录对象,那么您的 PDF 就严重损坏了。外部参照表更有可能有点偏离,并且有问题的对象根本不完全是它们应该在的位置(这很糟糕,但可以恢复)。
但是,当 PdfReader 第一次打开 PDF 时,它会解析文件中的所有对象,并将它们转换为适当的 PdfObject 派生类。
它没有做的是检查外部参照表声明的对象编号和从文件实际匹配中读取的对象编号。极不可能,但有可能。糟糕的软件可能会以错误的顺序写出他们的 PDF 对象,但会保持外部参照表中的字节偏移正确。使用文件中特定字节偏移量的数字覆盖外部参照表中的对象编号的软件会很好。
iText 不好。
我还是想看PDF。
是的。那个PDF坏了。具体来说:
该文件的前 70kb 左右定义了一个非常干净的小 PDF。然后将更改附加到 PDF 中。
检查那个。有人试图将更改附加到 PDF 并失败。很糟糕。为了理解到底有多糟糕,让我解释一下 PDF 的一些内部语法,用这个例子来说明:
%%PDF1.6
1 0 obj
<</Type/SomeObject ...>>
endobj
2 0 obj
<</Type/SomeOtherObj /Ref 1 0 R>>
endobj
3 0 obj
...
endobj
<etc>
xref
0 10
0000000000 65535 f
0000000010 00001 n
0000000049 00002 n
0000000098 00003 n
...
trailer
<</Root 4 0 R /Size 10>>
startxref 124
%%EOF
所以我们有一个标题/版本“%%PDF1.v”、一个对象列表(这里称为字典)、一个交叉 (x) 引用表,其中列出了列表中所有对象的字节偏移量和对象编号,和一个预告片,给出根对象和 PDF 中的对象数量,以及“外部参照”中“x”的字节偏移量。
您可以将更改附加到现有 PDF。为此,您只需在现有 %%EOF 之后添加任何新的或更改的对象、对这些新对象的交叉引用表和预告片。附加更改的尾部应包含一个 /Prev 键,其中包含与前一个交叉引用表的字节偏移量。
在您的 NOT-OKAY pdf 中,有人试图将更改附加到 PDF,并且失败了。
原始 PDF 仍然存在,完好无损。这就是 Reader 向您展示的内容,也是您保存 PDF 时获得的内容。我在十六进制编辑器中的第一个 %%EOF 之后破解了所有内容,并且文件很好。
所以这是你的 NOT-OKAY pdf 的布局:
%PDF1.4.1
1 0 obj...
2 through 7
xref
0 7
<healthy xref>
trailer <</Size 8 /Root 6 0 R /Info 7 0 R>>
startxref 68308
%%EOF
到现在为止还挺好。这就是事情变得丑陋的地方
<binary garbage>
endstream
endobj
xref
0 7
<horribly wrong xref>
trailer <</ID [...] /Info 1 0 R /Root 2 0 R /Size 7>>
startxref 223022
%%EOF
该部分唯一正确的是 startxref 值。
问题:
- 第二个预告片没有 /Prev 键。
- 第二个外部参照表中的所有字节偏移量都是错误的。
- 它是“流”对象的一部分,但该对象的开头缺失。流应该看起来像这样
1 0 obj
<</Type/SomeType/Length 123>>
stream
123 bytes of data
endstream
endobj
该文件的末尾由(我想是压缩的)流的某些部分组成......但一开始没有字典告诉我们它使用什么过滤器以及它有多长(更不用说任何丢失的数据),你不能用它做任何事情。
我怀疑有人试图完全重建这个 PDF,然后不小心在他们版本的开头写了原来的 70kb。卡布姆。
看起来 Adobe 只是忽略了不良的附加更改。iText 也可以这样做,但你也可以:
当 iText 无法打开 PDF 时:
1.向后搜索文件以查找倒数第二个%%EOF
. 忽略最后的那个,我们想要文件的前一个状态。2. 删除倒数第二个%%EOF
(如果有)之后的所有内容,然后尝试再次打开它。
可悲的是,这个损坏的 PDF 可能与“原始”70kb 完全不同,然后一些 IO 错误覆盖了文件的第一部分。不太可能,但没有办法确定。