我正在使用 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 第一次输出最小的文件大小?
编辑
从扁平化表单的 block 中删除压缩代码会产生相同的结果,但最终大小稍大一些,为 105KB。
最佳答案
这种行为的原因很简单:
- 当您将文档加载到
PdfReader
时,未使用的对象会立即被删除。 (如果您在部分模式下工作则不会,但您不会那样做。) - 当您关闭
PdfStanper
时,它会从它标记的PdfReader
复制所有对象并添加一些自己的、尚未写入的信息。
因此,
- 在您的第一遍中,阅读器在加载 PDF 时保留所有用于表单字段的对象,因为它们仍然在使用。然后压模复制所有这些与表单字段相关的对象,即使它们由于扁平化而不再使用。
- 在您的第二遍中,阅读器在加载 PDF 时丢弃了以前用于表单字段的所有对象,因为表单已不复存在。压模因此不能再复制它们。在此遍中不会发生扁平化,因为不再有可扁平化的形式。
第一遍中的小尺寸减小可能是由于源文件中已经存在少量未使用的对象或 iTest(Sharp) 更好的压缩。
第二遍中尺寸的大幅减小肯定是由于与表单字段相关的对象被丢弃。
关于你的问题
how can I get iTextSharp to output the smallest file size the first time
你不能。压模一般不能简单地丢弃与表格相关的对象,因为它们也可能被不同的对象使用。它甚至无法检查此类用法,因为之前执行的其他压模操作可能已经创建了新的 PDF 对象,这些对象确实引用了那些有问题的对象,但这些新生成的 PDF 对象早已被写入输出,压模无法再访问它们。
不过,您可以通过使用 MemoryStream
作为第 1 遍的输出和第 2 遍的输入来防止中间 PDF 出现在光盘上。
如果您想知道为什么 PdfStamper
不将那些新创建的对象保存在内存中以便以后检查未使用的对象:iText(Sharp) 是在创建服务器应用程序和大型 PDF 时考虑的;在这种情况下,应该尽早写入数据并释放内存。
关于c# - 使用 pdfStamper 多次通过可减少文件大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34600054/