4

我有一个 Win32 应用程序,它使用 iTextSharp 读取 PDF,它将图像作为印章插入到文档中。

它适用于我们一年多来处理的 99% 的文件,但现在有些文件无法读取。当我执行下面的代码时:

string inputfile = "C:\test.pdf";
PdfReader reader = new PdfReader(inputfile);

它给出了例外:

System.NullReferenceException occurred
  Message="Object reference not set to an instance of an object."
  Source="itextsharp"
  StackTrace:
       em iTextSharp.text.pdf.PdfReader.ReadPages()
       em iTextSharp.text.pdf.PdfReader.ReadPdf()
       em iTextSharp.text.pdf.PdfReader..ctor(String filename, Byte[] ownerPassword)
       em iTextSharp.text.pdf.PdfReader..ctor(String filename)
       em MyApp.insertSeal() na C:\MyApp\Stamper.cs:linha 659

引发这些异常的 pdf 文件通常可以由 adobe pdf 读取,当我使用 Acrobat 打开其中一个文件并保存它时,我可以使用我的应用程序读取这个保存的文件。

文件是否已损坏但仍可使用 Adob​​e Reader 打开?

我与您分享两个文件样本。

一个不起作用的文件:Not-Ok-Version.pdf

在使用 Acrobat 打开并保存后,该文件可以正常工作。在这里下载OK-Version.pdf

4

5 回答 5

9

这是 readPages 的(java,抱歉)源代码:

protected internal void ReadPages() {
  catalog = trailer.GetAsDict(PdfName.ROOT);
  rootPages = catalog.GetAsDict(PdfName.PAGES);
  pageRefs = new PageRefs(this);
}

trailer,目录,rootPages , andpageRefs`都是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。卡布姆。

看起来 Adob​​e 只是忽略了不良的附加更改。iText 也可以这样做,但你也可以

当 iText 无法打开 PDF 时:
1.向后搜索文件以查找倒数第二个%%EOF. 忽略最后的那个,我们想要文件的前一个状态。2. 删除倒数第二个%%EOF(如果有)之后的所有内容,然后尝试再次打开它。

可悲的是,这个损坏的 PDF 可能与“原始”70kb 完全不同,然后一些 IO 错误覆盖了文件的第一部分。不太可能,但没有办法确定。

于 2011-03-22T17:38:03.517 回答
3

考虑到它们现在已经达到 5.0 版,我的猜测是您会看到越来越多的 PDF 写入您的 iTextSharp 版本不支持的 PDF 版本规范。可能是时候进行升级了。

于 2011-02-25T18:38:21.093 回答
2

也许这会对某人有所帮助......我的代码工作了多年,开始挂在从 PDF 文件中读取书签(下面的大纲变量)。事实证明,当代码从 .NET 4.0 更新到 .NET 4.5 时,它就崩溃了。
当我将它回滚到 .NET 4.0 时,它又可以工作了。

        RandomAccessFileOrArray raf = null;
        PdfReader reader1 = null;
        System.Collections.ArrayList outlines = null;
        raf = new iTextSharp.text.pdf.RandomAccessFileOrArray(sFile);
        reader1 = new iTextSharp.text.pdf.PdfReader(raf, null);
        outlines = iTextSharp.text.pdf.SimpleBookmark.GetBookmark(reader1);

仅作说明,同一个 VS Web 应用程序项目使用 AjaxControlToolkit(来自 NuGet)。在我回滚之前,我还将 iTextSharp 更新到了 5.5.5 版,它仍然挂在同一行。

于 2015-02-18T23:00:20.217 回答
1

当我拉下源代码并针对错误的 PDF 运行它时,ReadPdf()在第 4 个try块中调用时出现异常ReadDocObj()

"Invalid object number. at file pointer 16"

tokens.StringValuej

@Mark Storer,你是 iText 的人,所以这对你来说可能意味着什么。

从更高的层次来看,至少在我看来,似乎在RebuildXref()调用时(我假设是在读取无效 PDF 时)它会重建trailer,但不会重建catalog. 后者是 NRE 所抱怨的。再说一次,这只是一个猜测。

于 2011-03-24T15:05:01.240 回答
0

还要确保您的 html 在将 html 转换为 pdf 时不包含 hr 标签

hdnEditorText.Value.Replace("\"", "'").Replace("<hr />", "").Replace("<hr/>", "")
于 2014-10-08T12:14:33.400 回答