必须设置许可证,否则unidoc/unipdf/v4合并PDF时会panic并报“license not set”;默认仅支持≤3页,超限即崩溃,需注册邮箱申请免费开发许可并用license.NewLicenseFromBytes()加载。
合并前必须设置许可证,否则 panic
用 unidoc/unipdf/v4 合并 pdf 时,不设 license 就会直接 panic 并报 "license not set"。这不是异常,是硬性限制:默认只允许处理 ≤3 页的 pdf,第 4 页起就崩。
实操建议:
- 去 https://www.php.cn/link/bca7ef2efe3dffdb134f0bdff92a2ebc 注册邮箱,申请免费开发许可,下载
pdf.license文件 - 在代码里用
license.NewLicenseFromBytes()加载,不能跳过 - 别改源码、别回退到 v2 分支——v3+ 已移除社区免费版,且旧版无法正确读取加密 PDF 或渲染文字
用 pdfcpu 合并更轻量,但不保留书签
pdfcpu 不需要 license,纯 Go 实现,无 CGO,适合容器部署。调用 api.MergeFiles() 即可完成合并,但有个关键缺失:它完全不支持 outline(书签)合并。
常见错误现象:
- 输入 PDF 带书签,合并后全丢失,且无任何 warning
- 误以为是代码漏写,实际是
pdfcpu v0.3.14根本没实现该功能
如果你必须保留书签结构,只能切回 unipdf,手动读取每个文件的 PDFReader.ReadOutline(),再用 PDFWriter.AddOutlineEntry() 重建,并修正 Dest.PageNum 偏移量。
页码越界和空文件必须显式校验
本地测试通过的合并逻辑,上线后常因三类边界问题失败:空文件、损坏 PDF、页码越界。
实操建议:
- 用
os.Stat()后,必须调pdfcpu.ValidateFile()或unipdf.NewReader()检查 error,不能只看文件大小 > 0 -
pdfcpu.ExtractPages()对"10-20"在只有 5 页的文件里会静默返回成功,但结果为空;需提前用pdfcpu.GetNumPages()校验范围 - 合并前对每个输入文件做
io.Copy(ioutil.Discard, file)简单流读取,可快速暴露 EOF 或解码错误
性能与选型:图像多就选 unipdf,纯文本优先 pdfcpu
两者都是纯 Go,但内存行为差异明显:
- 含大量图像或 OCG 图层的 PDF,
pdfcpu内存占用比unipdf高约 20%,GC 压力更大 -
unipdf的creator模块在生成带表格/样式的 PDF 时更稳定,pdfcpu的merge更适合日志归档类纯文本拼接 - 若要支持加密 PDF 合并,必须用
unipdf;pdfcpu对密码保护文档仅支持解密后操作,且不支持 owner password 的完整权限控制
真正容易被忽略的是:书签层级超过 3 级时,macOS 预览会自动折叠,不是代码问题,是 PDF 规范在部分阅读器上的兼容性限制——测试时得换 Adobe Acrobat 或 Chrome PDF Viewer 多验证几轮。



















