无法使用iTextSharp读取某些PDF文件

时间:2011-02-25 18:33:41

标签: c# pdf itext eof

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

它可以正常使用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打开其中一个文件并保存时,我可以用我的应用程序读取这个保存的文件。

文件是否已损坏,但仍然可以使用Adobe Reader打开?

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

无效的文件:Not-Ok-Version.pdf

一个有效的文件,打开后用Acrobat保存。在此处下载OK-Version.pdf

5 个答案:

答案 0 :(得分:9)

这是readPages的(java,对不起)来源:

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

trailer, catalog , 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)参考表,列出了所有对象的字节偏移和对象编号。列表,以及给出根对象&amp; PDF中对象的数量,以及'xref'中'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值。

问题:

  • 第二个预告片没有/上一个键。
  • 第二个外部参照表中的所有字节偏移都是错误的。
  • 是“流”对象的一部分,但该对象的开头是MISSING。流应该看起来像这样

1 0 obj
<</Type/SomeType/Length 123>>
stream
123 bytes of data
endstream
endobj

这个文件的结尾是由(压缩的我想象的)流的某些部分组成的...但是开头没有字典告诉我们它使用了什么过滤器以及它有多长(更不用说任何缺失的数据),你无法用它做任何事情。

我怀疑有人试图完全重建这个PDF,然后在他们的版本的开头不小心写了原始的70kb。 KABOOM。

似乎Adobe只是忽略了错误的附加更改。 iText也可以这样做,但你也可以

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

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

答案 1 :(得分:3)

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

答案 2 :(得分: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并且它仍然挂在同一行。

答案 3 :(得分:1)

当我下拉源并针对坏PDF运行时,当ReadPdf()调用try时,ReadDocObj()块中的"Invalid object number. at file pointer 16" 会出现例外:

tokens.StringValue

jRebuildXref()

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

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

答案 4 :(得分:0)

在将html转换为pdf

时,请确保您的html不包含hr标记
hdnEditorText.Value.Replace("\"", "'").Replace("<hr />", "").Replace("<hr/>", "")