【问题标题】:Using iTextSharp to write data to PDF works great, but Acrobat Reader asks 'Do you want to save changes' when closing file使用 iTextSharp 将数据写入 PDF 效果很好,但 Acrobat Reader 在关闭文件时询问“是否要保存更改”
【发布时间】:2012-09-16 04:12:10
【问题描述】:

我正在使用 iTextSharp 5.3.2.0 向包含 W-2 表单的现有 PDF 文件添加信息。一切正常,PDF 文件在写入浏览器的响应流时看起来很棒;但是,当用户查看完 PDF 后,系统会询问他“是否要在关闭前保存对 'W2.pdf' 的更改?”每次他从网页查看文档时。

在试图缩小问题范围时,我实际上已经删除了所有修改,但问题仍然存在。这是我的代码的简单版本,我的数据写入调用被注释掉了:

PdfReader pdfReader = new PdfReader(dataSource.ReportTemplate);

using(MemoryStream outputStream = new MemoryStream())
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream))
{
   //dataSource.DrawDataFields(pdfStamper);
   pdfStamper.FormFlattening = true;
   return outputStream;
}

在这种情况下,“空”PDF 被写入浏览器并且看起来不错,但是当我关闭 Acrobat 窗口时,我仍然被询问“是否要保存”。

此时我认为源 PDF 文件有问题。但是,当我将 PDF 文件的原始字节发送回浏览器时,使用下面的代码时不会询问我“是否要保存”的问题。

byte[] bytes = File.ReadAllBytes(dataSource.ReportTemplate);

using (MemoryStream outputStream = new MemoryStream())
{
    outputStream.Write(bytes, 0, bytes.Length);
    return outputStream;
}

我的结论是 iTextSharp 在打开 PDF 并将字节写入流的过程中对 PDF 做了一些“坏事”,但我是 iTextSharp 的新手,很容易遗漏一些东西。

FWIW,这是我们正在谈论的 Acobat Reader 10.1.4。

编辑:用作模板的原始 PDF 大小约为 80K。如果我查看通过浏览器流式传输的临时文件,iTextSharp 编写的 PDF 文件大约为 150K。但是,当我对 Acrobat Reader 提出的“保存更改”问题回答“是”时,生成的文件再次约为 80K。 iTextSharp 肯定对这个文件做了一些意想不到的事情。

【问题讨论】:

标签: c# pdf-generation itextsharp


【解决方案1】:

不工作:

public byte[] MergeDataByDrawing(int copies)
{
    PdfReader pdfReader = new PdfReader(reportTemplate);

    using (MemoryStream outputStream = new MemoryStream())
    using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream))
    {
        pdfStamper.FormFlattening = true;
        return outputStream.GetBuffer();
    }
} 

工作:

public byte[] MergeDataByDrawing(int copies)
{
    PdfReader pdfReader = new PdfReader(reportTemplate);

    using (MemoryStream outputStream = new MemoryStream())
    using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream))
    {
        pdfStamper.FormFlattening = true;
        return outputStream.ToArray();
    }
}

似乎 GetBuffer 方法有问题。我不明白为什么,但我会接受结果!

Props to MKL for giving me an ideaFredrik for the right example at the right time

【讨论】:

  • MemoryStream.GetBuffer() 可能会将垃圾添加到流中包含的实际数据中。 See the documentation。因此,在使用 iTextSharp 时,请始终调用 ToArray()
  • PDF 从下到上阅读。 PDF 阅读器期望最终字节为%%EOF。如果在最后出现%%EOF 之后添加了其他字节,一些读者会尝试修复这个问题。 ToArray() 能解决您的问题吗?在这种情况下,无需将 PDF 发送给我。为了确保您得到了正确的解决方案,您可以比较GetBuffer()ToArray() 产生的字节数。如果ToArray() 生成的字节数较少,则问题已解决。
  • 是的,ToArray() 几乎将返回的字节数减少了一半!一切都很好。
  • Android/Java 有类似的修复方法吗?
【解决方案2】:

http://itextpdf.com/history/?branch=52&node=521

修正 AcroForms:在某些情况下,Adobe Reader X 会询问您是否要 关闭扁平化的 PDF 表单后“保存更改”。这是由于 /AcroForm 字典中存在一些不必要的条目(例如 使用 OOo 创建表单时添加的实例)。

我是修复此错误的布鲁诺。我记得它发生在 Adob​​e Reader 10 中,但不是在 Adob​​e Reader 9 中。我能够修复这个错误,因为报告它的人是向我发送显示此行为的 PDF 的客户。

如果您愿意分享您的 PDF,我们可以查看一下应该从 /AcroForm 字典中删除哪些其他条目。我只删除了使用 Open Office 创建表单时添加的那些。如果您不想共享 PDF,原因将永远是个谜。

【讨论】:

  • 我很想分享我的 PDF - 我应该如何把它给你?我会说我试图做一个“pdfReader.Catalog.Remove(PdfName.ACROFORM)”,但没有效果。
猜你喜欢
  • 1970-01-01
  • 2016-03-05
  • 2018-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-29
  • 2011-01-29
  • 1970-01-01
相关资源
最近更新 更多