结论:别用itextsharp v4.x,慎用5.x;pdfsharp仅适合简单拼接且需手动保活流;生产环境推荐pdfpig(无许可证风险、.net 5+原生支持)或spire.pdf(api最省事)。

直接说结论:别用 iTextSharp v4.x,慎用 iTextSharp 5.x,PdfSharp 仅适合简单拼接且必须手动保活流;生产环境推荐 PdfPig(无许可证风险、.NET 5+ 原生支持)或商业库 Spire.PDF(API 最省事)。
为什么 iTextSharp 5.x 合并后中文变方块或报错?
根本不是“代码写错了”,而是它默认不嵌入中文字体,也不自动处理源 PDF 的字体字典。哪怕你用 BaseFont.CreateFont(@"simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED),只要源文件里用了未嵌入的 Noto Sans CJK 或 Adobe Song Std,渲染时照样空白或乱码。
- 必须显式调用
reader.SelectPages("1-")强制加载所有页对象,否则GetImportedPage()可能读到不完整结构 - 含 AcroForm 表单?
PdfCopy会丢字段,得换PdfSmartCopy,但性能下降 30% 以上 - 书签(Outline)完全不继承,要手动遍历
reader.Outlines并重映射页码偏移——稍有错位就跳转失败 - 错误信息如
Document has no pages或InvalidPdfException: PDF header not found,大概率是流提前关闭或 reader 未 fully initialized
PdfSharp 合并时提示 “Cannot access a closed Stream” 怎么办?
这是 PdfSharp 最经典也是最隐蔽的坑:它内部把整个 PDF 加载进 MemoryStream,但如果你用 using (var fs = File.OpenRead(path)) { new PdfDocument(fs); },fs 在 using 块结束时立刻关闭,后续 copy.AddPage() 就崩。
- 正确做法是:用
new PdfDocument(new MemoryStream(File.ReadAllBytes(path))),把字节全读进内存再构造 - 或者自己管理流生命周期:声明
FileStream变量在方法外层,确保它存活到output.Save()完成 -
PdfSharp不支持书签、表单、加密 PDF 解密,连GetPage(0).Size都可能返回 null —— 它压根没解析页面资源字典 - 合并后页码错乱?检查是否漏了
document.NewPage():每份源 PDF 插入前必须显式新建一页,否则内容会叠在上一页末尾
PdfPig 合并 PDF 为什么更稳?关键在哪?
因为它是真正按 PDF 规范解析对象树,不是“二进制缝合”。字体、图像流、交叉引用表、书签节点全部原样保留,不需要你手动注册字体或重映射 Outline。
- 安装只需
dotnet add package PdfPig,无额外依赖,.NET 5+ 直接跑 - 合并代码核心就三步:
PdfDocument.Open()→PdfDocumentBuilder→builder.AddPagesFromDocument(doc, start, count) - 源 PDF 有用户密码?传
new PdfPasswordProvider("123")即可;但 Owner Password(权限密码)不支持解密 - 页码索引从 0 开始:
AddPagesFromDocument(doc, 0, 2)是取第 0 和第 1 页,不是 0–2 页 - 注意:它不自动缩放页面尺寸。如果源 PDF 页面大小不一(A4 + Letter),合并后会保持原样——这不是 bug,是规范行为
Spire.PDF 为什么适合快速交付?
它把所有脏活都封装好了,连书签层级、页面尺寸归一化、字体回退都内置了,适合赶工期或非技术 PM 提需求的场景。
-
PdfDocument.MergeFiles(string[] paths)一行合并,支持 PDF 1.0–1.7 和部分 PDF/A - 指定页合并:
newPDF.InsertPageRange(pdfs[0], 1, 2)(注意:这里页码从 0 开始,参数却是 1 和 2 表示第 2–3 页) - 保留书签?加个
newPDF.MergeBookmarks = true就行,不用算页偏移 - 免费版限制:输出 PDF 顶部带水印,且单次操作最多处理 10 页——别在批量脚本里用免费版
- 大文件内存爆?启用
LoadFromFile(path, pageSize, password, memoryMode: true)切换为流式加载
真正容易被忽略的点是:PDF 合并不只是“把页面摞起来”。字体嵌入状态、交叉引用表完整性、对象流压缩方式、加密级别,任意一项不匹配都会导致 Acrobat 打不开或打印异常。别迷信“能运行就行”,上线前务必用不同 PDF 查看器(Acrobat、Edge、macOS 预览)各打开一遍。










