gofpdf生成中文PDF需手动加载中文字体、显式管理分页、格式化数字后再写入,并确保调用Output()输出完整二进制流,否则出现方块、panic、错位或文件损坏。

gofpdf.New() 初始化时字体路径没设对,PDF 里中文全是方块
gofpdf 默认不带中文字体,New() 创建实例后若直接写中文,会显示为空白或方块。这不是编码问题,是字体资源缺失。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
gofpdf.NewCustom(&gofpdf.Rect{W: 210, H: 297}, "pt", "A4", gocv.DefaultFontData)不行——DefaultFontData是英文的 - 必须手动加载中文字体:下载
simhei.ttf或NotoSansCJKsc-Regular.ttf,放到项目目录(如./fonts/),再调用pdf.AddUTF8Font("simhei", "", "./fonts/simhei.ttf") - 加载后必须用
pdf.SetFont("simhei", "", 12)切换字体,否则仍走默认 Latin 字体 - 注意路径是相对
os.Getwd()的,不是相对于源文件;用filepath.Abs("./fonts/...")更稳
AddPage() 后调用 Cell() 报 panic: runtime error: index out of range
常见于循环生成表格行时,忘了在每页开头调用 AddPage(),或在页尾强行写内容超出边界。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
-
Cell()和MultiCell()都依赖当前光标位置,而光标在页底不会自动换页——gofpdf不像浏览器那样“流式布局” - 每次写新行前,先用
pdf.GetY()检查是否快到底部(比如 A4 高 297mm,留 20mm 页脚,则临界值 ≈ 277) - 超限时要显式
pdf.AddPage(),再用pdf.SetY(30)重置 Y 坐标(避免贴顶) - 别依赖
AutoPageBreak:它只对MultiCell()生效,且需提前SetAutoPageBreak(true, 20)
用 Write() 写数字金额时小数点错位、千分位混乱
Write() 是纯文本流式输出,不处理数字格式化。直接传 123456.789 会输出成 123456.789,但发票要求 ¥123,456.79。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- Go 标准库没有内置金额格式化,别用
fmt.Sprintf("%.2f", x)—— 它不加千分位,也不处理负号对齐 - 推荐用
github.com/leekchan/accounting:初始化a := accounting.Accounting{Symbol: "¥", Precision: 2, Thousand: ",", Decimal: "."},再a.FormatMoney(123456.789) - 如果不想引入依赖,手写也简单:
strconv.FormatFloat(x, 'f', 2, 64)+ 正则补千分位(注意负数和小数点位置) - 务必在写入 PDF 前完成格式化,
Write()只吃字符串
生成 PDF 后打开提示“文件已损坏”,但 Chrome 能看
本质是 PDF 文件头或交叉引用表(xref)写错,常见于并发写入或未调用 Output()。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 确认最后一步是
err := pdf.Output(&gofpdf.ImageOptions{ImageType: "png"}, "invoice.pdf")或buf := pdf.Output(nil)—— 少了这步,文件就是空壳 - 并发场景下,每个 goroutine 必须用独立
*gofpdf.GoPdf实例;共用一个实例会因内部状态竞争导致 xref 错乱 - 写文件时别用
ioutil.WriteFile直接写[]byte,要用os.WriteFile或os.Create+buf.WriteTo(f),确保二进制完整 - 最简验证法:用
file invoice.pdf命令看是否识别为 “PDF document”;不是就说明Output()没执行或返回了 nil











