使用pdfStamper进行多次传递可减小文件大小

时间:2016-01-04 21:19:56

标签: c# itextsharp

我正在使用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。

1 个答案:

答案 0 :(得分:1)

这种行为的原因很简单:

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

因此,

  • 在第一遍中,读者会在加载PDF时保留用于表单字段的所有对象,因为它们仍在使用。然后压模复制所有与表格字段相关的对象,即使由于展平而不再使用它们。
  • 在第二遍中,读者会在加载PDF时删除以前用于表单字段的所有对象,因为表单不再存在。因此压模不能再复制它们了。在此过程中不会发生展平,因为没有任何形式可以展平。

第一遍中的小尺寸减小可能是由于源文件中已存在少量未使用的未使用对象或iTest(夏普)的更好压缩。

第二遍的大尺寸减少最终是由于与表格字段相关的对象丢失。

关于你的问题

  

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

你做不到。压模通常不能简单地删除与表单相关的对象,因为它们也可能被不同的对象使用。它甚至无法检查这些用法,因为之前执行的其他压模操作可能会创建新的PDF对象,这些对象会引用相关对象,但这些新生成的PDF对象早已写入输出,压模无法再访问它们。

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

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