【问题标题】:Multiple passes with pdfStamper reduces file size使用 pdfStamper 多次通过可减少文件大小
【发布时间】:2023-04-04 16:18:01
【问题描述】:

我正在使用 iTextSharp 填写 PDF 上的一些表单域。

PdfReader pdfReader = new PdfReader(templateFile);
//http://stackoverflow.com/questions/17852902/disable-extended-features-with-itextsharp Prevent annoying "extended features disabled" warning in Adobe Reader
pdfReader.RemoveUsageRights();
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(fileName, FileMode.Create), PdfWriter.VERSION_1_7);
pdfStamper.SetFullCompression();
pdfStamper.Writer.CompressionLevel = PdfStream.BEST_COMPRESSION;
AcroFields pdfFormFields = pdfStamper.AcroFields;

// set form pdfFormFields
pdfFormFields.SetField("field1", "value1");
pdfFormFields.SetField("field2", "value2");
pdfFormFields.SetField("field3", "value3");
//etc

pdfStamper.FormFlattening = false;
// close the pdf

pdfStamper.Close();

填写 PDF 字段后,我不会立即将表单展平,以便可以根据需要进行手动更改。进行手动更改后,我打开 PDF,设置最大压缩率,展平表单,保存并关闭文档。

//Move the original file so I can recreate it without editable form fields
string tempFileName = filename + ".temp";
File.Move(filename, tempFileName);

using (PdfReader pdfReader = new PdfReader(tempFileName))
{
    using (PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(filename, FileMode.Create), PdfWriter.VERSION_1_7))
    {
        pdfStamper.SetFullCompression();
        pdfStamper.Writer.CompressionLevel = PdfStream.BEST_COMPRESSION;

        // flatten the form to remove editting options
        pdfStamper.FormFlattening = true;

        pdfStamper.Close();
    }

    pdfReader.Close();
}

//Delete the original temp file
File.Delete(tempFileName);

我第一次直接运行上面的代码来压缩和展平PDF,每个文件的大小略有减小,从300KB到256KB。但是,如果我第二次运行上面的代码,文件大小会大大减少,从 256KB 到 95KB。随后的运行不会进一步更改文件大小。我的问题是,如何让 iTextSharp 第一次输出最小的文件大小?

编辑

从使表单变平的块中删除压缩代码会产生相同的结果,尽管最终大小略大,为 105KB。

【问题讨论】:

  • 明确一点,当您说“我第一次运行此代码”时,您是指您多次运行的第二个代码块吗?
  • 我认为原因是在第一遍中使用的资源 b 字段仍然嵌入在 PDF 中(展平仅在关闭时发生,因此很长一段时间内这些资源被引用)并且仅在第二遍中删除。你能分享一个填写好的 PDF 来重现这个问题吗?
  • @ChrisHaas,这是正确的。在 PDF 上多次传递第二个代码块会导致此问题。

标签: c# itextsharp


【解决方案1】:

这种行为的原因很简单:

  • 当您将文档加载到PdfReader 时,未使用的对象会立即被丢弃。 (如果您在部分模式下工作,则不会,但您不这样做。)
  • 当您关闭 PdfStanper 时,它会复制 PdfReader 中的所有对象,并添加一些自己的尚未写入的信息。

因此,

  • 在您的第一遍中,阅读器会在加载 PDF 时保留所有用于表单域的对象,因为那时它们仍在使用。然后压模复制所有与表单域相关的对象,即使它们由于展平而不再使用。
  • 在您的第二遍中,阅读器在加载 PDF 时丢弃以前用于表单域的所有对象,因为该表单不再存在。因此,压模不能再复制它们。在此过程中不会发生展平,因为不再有可以展平的形式。

第一遍的小幅减小可能是由于源文件中已有少量未使用的杂散对象或 iTest(Sharp) 更好地压缩。

第二遍中的大幅减小肯定是由于丢弃了表单字段相关的对象。

关于你的问题

如何让 iTextSharp 第一次输出最小的文件大小

你不能。压模一般不能简单地丢弃与表单相关的对象,因为它们也可能被不同的对象使用。它甚至无法检查这种用法,因为之前执行的其他压模操作可能已经创建了新的 PDF 对象,这些对象确实引用了那些有问题的对象,但是这些新生成的 PDF 对象早已被写入输出并且压模无法再访问它们。

不过,您可以做的是通过使用MemoryStream 作为第 1 遍的输出和第 2 遍的输入来防止中间 PDF 出现在光盘上。


如果您想知道为什么PdfStamper 不将这些新创建的对象保留在内存中以便以后检查未使用的对象:iText(Sharp) 的创建考虑了服务器应用程序和大 PDF;在这种情况下,应该尽早写入数据并释放内存。

【讨论】:

  • 要使用内存流,请按照 mkl 的回答 here
猜你喜欢
  • 2020-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-25
  • 2011-01-10
  • 1970-01-01
相关资源
最近更新 更多