更快的大型PDF页眉和页脚
This article was translated from English: Does it need improvement?
Translated
View the article in English
在单次处理中为非常大的PDF添加页眉和页脚会很慢。 以固定大小的页面块处理文档,渲染每个批次,然后合并各部分以减少总渲染时间,同时保持整份文档的页码连续。
解决方案
1. 将页面索引拆分为批次
选择一个块大小,将文档的页面索引分组为固定大小的批次,例如每300页一批。 较小的块单独渲染得更快,但在最后增加了更多的合并工作。
2. 将每个批次复制到其自身的文档中
使用CopyPages提取当前批次的页面,生成一个独立的文档进行渲染。
3. 使用连续编号渲染页眉和页脚
将FirstPageNumber设置为块的起始页,以便编号贯穿整个文档而不是在每个块中从1重新开始。
4. 保存每个块并处置它
将每个块写入临时文件并处置它。 在下一批次之前释放块,以防止在运行过程中内存增加。
5. 将块合并为最终的PDF
重新打开临时文件,使用AppendPdf按顺序附加它们,保存结果,然后删除临时文件。
using IronPdf;
var pdf = PdfDocument.FromFile("input.pdf");
string headerHtml = "<div style='font-size:10px;'>Header</div>";
string footerHtml = "<div style='text-align:right;font-size:10px;'>Page {page} of {total-pages}</div>";
int chunkSize = 300;
var pageChunks = Enumerable.Range(0, pdf.PageCount)
.GroupBy(i => i / chunkSize)
.Select(g => g.ToArray())
.ToList();
var tempFiles = new List<string>();
foreach (var indexes in pageChunks)
{
var chunkPdf = pdf.CopyPages(indexes);
int globalStartPage = indexes.First() + 1;
chunkPdf.AddHtmlHeadersAndFooters(new ChromePdfRenderOptions
{
FirstPageNumber = globalStartPage, // keeps numbering continuous
HtmlHeader = new HtmlHeaderFooter { HtmlFragment = headerHtml, MaxHeight = 40 },
HtmlFooter = new HtmlHeaderFooter { HtmlFragment = footerHtml, MaxHeight = 40 }
});
string tempFile = Path.GetTempFileName() + ".pdf";
chunkPdf.SaveAs(tempFile);
chunkPdf.Dispose();
tempFiles.Add(tempFile);
}
// Merge the chunks back into one document.
var finalPdf = new PdfDocument(tempFiles.First());
foreach (var file in tempFiles.Skip(1))
{
using var part = new PdfDocument(file);
finalPdf.AppendPdf(part);
}
finalPdf.SaveAs("output.pdf");
finalPdf.Dispose();
// Clean up temp files.
foreach (var file in tempFiles)
File.Delete(file);
using IronPdf;
var pdf = PdfDocument.FromFile("input.pdf");
string headerHtml = "<div style='font-size:10px;'>Header</div>";
string footerHtml = "<div style='text-align:right;font-size:10px;'>Page {page} of {total-pages}</div>";
int chunkSize = 300;
var pageChunks = Enumerable.Range(0, pdf.PageCount)
.GroupBy(i => i / chunkSize)
.Select(g => g.ToArray())
.ToList();
var tempFiles = new List<string>();
foreach (var indexes in pageChunks)
{
var chunkPdf = pdf.CopyPages(indexes);
int globalStartPage = indexes.First() + 1;
chunkPdf.AddHtmlHeadersAndFooters(new ChromePdfRenderOptions
{
FirstPageNumber = globalStartPage, // keeps numbering continuous
HtmlHeader = new HtmlHeaderFooter { HtmlFragment = headerHtml, MaxHeight = 40 },
HtmlFooter = new HtmlHeaderFooter { HtmlFragment = footerHtml, MaxHeight = 40 }
});
string tempFile = Path.GetTempFileName() + ".pdf";
chunkPdf.SaveAs(tempFile);
chunkPdf.Dispose();
tempFiles.Add(tempFile);
}
// Merge the chunks back into one document.
var finalPdf = new PdfDocument(tempFiles.First());
foreach (var file in tempFiles.Skip(1))
{
using var part = new PdfDocument(file);
finalPdf.AppendPdf(part);
}
finalPdf.SaveAs("output.pdf");
finalPdf.Dispose();
// Clean up temp files.
foreach (var file in tempFiles)
File.Delete(file);
Imports IronPdf
Imports System.IO
Imports System.Linq
Dim pdf = PdfDocument.FromFile("input.pdf")
Dim headerHtml As String = "<div style='font-size:10px;'>Header</div>"
Dim footerHtml As String = "<div style='text-align:right;font-size:10px;'>Page {page} of {total-pages}</div>"
Dim chunkSize As Integer = 300
Dim pageChunks = Enumerable.Range(0, pdf.PageCount) _
.GroupBy(Function(i) i \ chunkSize) _
.Select(Function(g) g.ToArray()) _
.ToList()
Dim tempFiles = New List(Of String)()
For Each indexes In pageChunks
Dim chunkPdf = pdf.CopyPages(indexes)
Dim globalStartPage As Integer = indexes.First() + 1
chunkPdf.AddHtmlHeadersAndFooters(New ChromePdfRenderOptions With {
.FirstPageNumber = globalStartPage,
.HtmlHeader = New HtmlHeaderFooter With {.HtmlFragment = headerHtml, .MaxHeight = 40},
.HtmlFooter = New HtmlHeaderFooter With {.HtmlFragment = footerHtml, .MaxHeight = 40}
})
Dim tempFile As String = Path.GetTempFileName() & ".pdf"
chunkPdf.SaveAs(tempFile)
chunkPdf.Dispose()
tempFiles.Add(tempFile)
Next
' Merge the chunks back into one document.
Dim finalPdf = New PdfDocument(tempFiles.First())
For Each file In tempFiles.Skip(1)
Using part = New PdfDocument(file)
finalPdf.AppendPdf(part)
End Using
Next
finalPdf.SaveAs("output.pdf")
finalPdf.Dispose()
' Clean up temp files.
For Each file In tempFiles
File.Delete(file)
Next
$vbLabelText
$csharpLabel
Page {page} of {total-pages}这样的页脚从第一个块到最后一个块始终一致。
没有FirstPageNumber,每个块都从第1页重新开始编号。
调试提示
- 调整块大小:上面的值(300)是可调整的,块的效果取决于您的工作负载。
- 考虑合并过程:总时间是每块渲染加上最终合并,因此在比较时请考虑额外的过程。
- 在非常大的作业中保持内存稳定:在合并过程中定期执行垃圾回收,并使用
MaxDynamicHFPagesPerBatch调节浏览器池可以有所帮助。
准备开始了吗?
Nuget 下载 20,296,129 | 版本: 2026.7 刚刚发布

