当前位置: 首页 > news >正文

Go 语言 PDF 生成库综合比较与实践指南

概述

在 Go 语言生态系统中,有多种 PDF 生成和处理方案可供选择。本文将深入比较主流 Go PDF 库,并提供实际应用场景的解决方案,帮助开发者根据项目需求做出合适的选择。

核心库对比分析

以下是各 PDF 库的功能对比表格:

特性go-pdffpdfunidocpdfcpuwkhtmltopdfchromedp
创建 PDF⚠️
编辑 PDF
HTML 转 PDF⚠️
表格支持
中文字体
开源协议MITAGPLAGPL/商业Apache 2.0LGPLMIT
性能
学习曲线

详细库分析与代码示例

1. go-pdf - 简单轻量

package mainimport ("github.com/signintech/gopdf""log"
)func main() {pdf := gopdf.GoPdf{}pdf.Start(gopdf.Config{Unit: "pt", PageSize: gopdf.Rect{W: 595.28, H: 841.89}})pdf.AddPage()// 添加中文字体支持err := pdf.AddTTFFont("simsun", "./fonts/simsun.ttf")if err != nil {log.Fatal(err)}err = pdf.SetFont("simsun", "", 14)if err != nil {log.Fatal(err)}pdf.SetXY(50, 50)pdf.Cell(nil, "你好,世界!")pdf.SetXY(50, 70)pdf.Cell(nil, "这是使用go-pdf生成的中文PDF")pdf.WritePdf("simple.pdf")
}

2. fpdf - 功能丰富

package mainimport ("github.com/jung-kurt/gofpdf""fmt"
)func main() {pdf := gofpdf.New("P", "mm", "A4", "")pdf.AddPage()// 设置字体pdf.SetFont("Arial", "B", 16)pdf.Cell(40, 10, "Hello, World!")// 创建表格pdf.Ln(12)pdf.SetFont("Arial", "", 12)headers := []string{"ID", "Name", "Score"}data := [][]string{{"1", "Alice", "95"},{"2", "Bob", "88"},{"3", "Charlie", "92"},}// 绘制表格for _, header := range headers {pdf.CellFormat(40, 7, header, "1", 0, "C", false, 0, "")}pdf.Ln(-1)for _, line := range data {for _, cell := range line {pdf.CellFormat(40, 6, cell, "1", 0, "L", false, 0, "")}pdf.Ln(-1)}// 添加链接pdf.Ln(10)pdf.SetFont("", "U", 12)pdf.SetTextColor(0, 0, 255)pdf.WriteLinkString(10, 50, "Visit Google", "https://google.com")err := pdf.OutputFileAndClose("table.pdf")if err != nil {fmt.Println("Error:", err)}
}

3. unidoc - 企业级解决方案

package mainimport ("github.com/unidoc/unipdf/v3/creator""github.com/unidoc/unipdf/v3/model""log"
)func main() {c := creator.New()// 创建封面c.CreateFrontPage(func(args creator.FrontpageFunctionArgs) {p := args.Pager := args.Rect// 添加标题para := c.NewStyledParagraph()para.SetWidth(r.Width)para.SetTextAlignment(creator.TextAlignmentCenter)title := para.Append("公司报告")title.Style.FontSize = 30title.Style.Color = creator.ColorRGBFrom8bit(0, 0, 0)p.Draw(para, creator.DrawRect{X: r.X,Y: r.Y + 300,W: r.Width,H: 50,})})// 添加内容页c.NewPage()p := c.NewParagraph("这是报告正文内容")p.SetFontSize(12)p.SetPos(50, 50)c.Draw(p)// 添加表格table := c.NewTable(3)table.SetColumnWidths(0.2, 0.5, 0.3)// 表头headers := []string{"ID", "名称", "价格"}for _, h := range headers {cell := table.NewCell()p := c.NewParagraph(h)p.SetFontSize(10)p.SetColor(creator.ColorRGBFrom8bit(255, 255, 255))cell.SetBackgroundColor(creator.ColorRGBFrom8bit(0, 0, 150))cell.SetBorder(creator.CellBorderSideAll, creator.CellBorderStyleSingle, 1)cell.SetContent(p)}// 表格数据data := [][]string{{"1", "产品A", "$100"},{"2", "产品B", "$200"},{"3", "产品C", "$300"},}for _, row := range data {for _, cellData := range row {cell := table.NewCell()p := c.NewParagraph(cellData)p.SetFontSize(10)cell.SetBorder(creator.CellBorderSideAll, creator.CellBorderStyleSingle, 1)cell.SetContent(p)}}table.SetPos(50, 100)c.Draw(table)err := c.WriteToFile("report.pdf")if err != nil {log.Fatal(err)}
}

4. HTML 转 PDF 方案

wkhtmltopdf 集成
package mainimport ("fmt""os/exec""strings"
)func generatePDFWithWKHTML(htmlContent, outputPath string) error {// 将HTML内容保存为临时文件tmpfile := "/tmp/template.html"err := os.WriteFile(tmpfile, []byte(htmlContent), 0644)if err != nil {return err}// 调用wkhtmltopdfcmd := exec.Command("wkhtmltopdf","--page-size", "A4","--orientation", "Portrait","--margin-top", "15mm","--margin-right", "15mm","--margin-bottom", "15mm","--margin-left", "15mm",tmpfile, outputPath)output, err := cmd.CombinedOutput()if err != nil {return fmt.Errorf("wkhtmltopdf error: %s, output: %s", err, string(output))}return nil
}func main() {html := `<!DOCTYPE html><html><head><meta charset="UTF-8"><style>body { font-family: Arial, sans-serif; }h1 { color: #3366cc; }table { border-collapse: collapse; width: 100%; }th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }th { background-color: #f2f2f2; }</style></head><body><h1>销售报告</h1><table><tr><th>产品</th><th>数量</th><th>价格</th></tr><tr><td>产品A</td><td>10</td><td>$100</td></tr><tr><td>产品B</td><td>5</td><td>$200</td></tr></table></body></html>`err := generatePDFWithWKHTML(html, "sales_report.pdf")if err != nil {fmt.Println("Error:", err)}
}
chromedp 方案
package mainimport ("context""io/ioutil""log""time""github.com/chromedp/cdproto/page""github.com/chromedp/chromedp"
)func generatePDFWithChrome(url, outputPath string) error {ctx, cancel := chromedp.NewContext(context.Background())defer cancel()ctx, cancel = context.WithTimeout(ctx, 30*time.Second)defer cancel()var buf []byteerr := chromedp.Run(ctx,chromedp.Navigate(url),chromedp.WaitReady("body"),chromedp.ActionFunc(func(ctx context.Context) error {var err errorbuf, err = page.PrintToPDF().WithPrintBackground(true).WithPaperWidth(8.27).  // A4 width in inchesWithPaperHeight(11.69). // A4 height in inchesWithMarginTop(0.5).WithMarginBottom(0.5).WithMarginLeft(0.5).WithMarginRight(0.5).Do(ctx)return err}),)if err != nil {return err}return ioutil.WriteFile(outputPath, buf, 0644)
}// 从HTML字符串生成PDF
func generatePDFFromHTML(htmlContent, outputPath string) error {// 创建临时HTML文件tmpfile := "/tmp/chrome_temp.html"if err := ioutil.WriteFile(tmpfile, []byte(htmlContent), 0644); err != nil {return err}return generatePDFWithChrome("file://"+tmpfile, outputPath)
}func main() {html := `<!DOCTYPE html><html><body><h1>Hello ChromeDP!</h1></body></html>`err := generatePDFFromHTML(html, "chrome_output.pdf")if err != nil {log.Fatal(err)}
}

高级应用场景

1. 动态报表生成

package mainimport ("github.com/jung-kurt/gofpdf""time"
)type ReportData struct {Title     stringDate      time.TimeItems     []ReportItemSummary   string
}type ReportItem struct {Name      stringValue     float64Change    float64
}func GenerateReport(data ReportData, filename string) error {pdf := gofpdf.New("P", "mm", "A4", "")pdf.AddPage()// 标题pdf.SetFont("Arial", "B", 16)pdf.CellFormat(0, 10, data.Title, "", 1, "C", false, 0, "")pdf.Ln(5)// 日期pdf.SetFont("Arial", "", 12)pdf.CellFormat(0, 10, data.Date.Format("2006年01月02日"), "", 1, "R", false, 0, "")pdf.Ln(10)// 表格pdf.SetFont("Arial", "B", 12)pdf.CellFormat(70, 10, "项目", "1", 0, "C", false, 0, "")pdf.CellFormat(40, 10, "数值", "1", 0, "C", false, 0, "")pdf.CellFormat(40, 10, "变化", "1", 1, "C", false, 0, "")pdf.SetFont("Arial", "", 12)for _, item := range data.Items {pdf.CellFormat(70, 8, item.Name, "1", 0, "L", false, 0, "")pdf.CellFormat(40, 8, fmt.Sprintf("%.2f", item.Value), "1", 0, "R", false, 0, "")// 根据变化值设置颜色if item.Change >= 0 {pdf.SetTextColor(0, 128, 0) // 绿色} else {pdf.SetTextColor(255, 0, 0) // 红色}pdf.CellFormat(40, 8, fmt.Sprintf("%.2f%%", item.Change), "1", 1, "R", false, 0, "")pdf.SetTextColor(0, 0, 0) // 恢复黑色}// 总结pdf.Ln(10)pdf.SetFont("Arial", "I", 12)pdf.MultiCell(0, 8, data.Summary, "", "L", false)return pdf.OutputFileAndClose(filename)
}

2. PDF 合并与处理

package mainimport ("github.com/pdfcpu/pdfcpu/pkg/api""github.com/pdfcpu/pdfcpu/pkg/pdfcpu""log"
)// MergePDFs 合并多个PDF文件
func MergePDFs(inputPaths []string, outputPath string) error {return api.MergeCreateFile(inputPaths, outputPath, pdfcpu.NewDefaultConfiguration())
}// ExtractPages 从PDF中提取指定页面
func ExtractPages(inputPath, outputPath string, pages []string) error {return api.ExtractPagesFile(inputPath, outputPath, pages, pdfcpu.NewDefaultConfiguration())
}// AddWatermark 添加水印
func AddWatermark(inputPath, outputPath, watermarkText string) error {config := pdfcpu.NewDefaultConfiguration()// 创建水印wm, err := pdfcpu.ParseTextWatermarkDetails(watermarkText, "scale:0.8, rotation:45, opacity:0.2", pdfcpu.POINTS)if err != nil {return err}return api.AddWatermarksFile(inputPath, outputPath, nil, wm, config)
}func main() {// 合并PDF示例files := []string{"file1.pdf", "file2.pdf"}err := MergePDFs(files, "merged.pdf")if err != nil {log.Fatal(err)}// 添加水印示例err = AddWatermark("document.pdf", "document_watermarked.pdf", "CONFIDENTIAL")if err != nil {log.Fatal(err)}
}

性能优化建议

  1. 批量处理:对于大量 PDF 生成任务,使用缓冲和批量处理减少 I/O 操作
  2. 资源复用:复用字体、模板等资源,避免重复加载
  3. 并发处理:合理使用 goroutine 并行生成多个 PDF
  4. 缓存机制:对静态内容生成的 PDF 实施缓存策略
  5. 选择合适的库:根据需求选择最合适的库,避免功能过剩
// 并发生成PDF示例
func GeneratePDFsConcurrently(templates []TemplateData) {var wg sync.WaitGroupsem := make(chan struct{}, 10) // 限制并发数for i, template := range templates {wg.Add(1)sem <- struct{}{}go func(index int, data TemplateData) {defer wg.Done()defer func() { <-sem }()filename := fmt.Sprintf("output_%d.pdf", index)err := GeneratePDF(data, filename)if err != nil {log.Printf("Error generating %s: %v", filename, err)}}(i, template)}wg.Wait()
}

结论与推荐

根据不同的应用场景,推荐以下选择:

  1. 简单文本 PDF:使用go-pdf,轻量且简单
  2. 表格和复杂布局:选择fpdf,功能丰富且稳定
  3. 企业级应用:考虑unidoc(注意许可证)或pdfcpu
  4. HTML 转 PDF
    • 简单场景:wkhtmltopdf
    • 需要 JavaScript 渲染:chromedp
  5. PDF 处理操作:使用pdfcpu进行合并、拆分、水印等操作

在实际项目中,可以考虑组合使用多个库,例如使用fpdf生成内容,使用pdfcpu进行后期处理,以达到最佳的效果和性能平衡。


文章转载自:

http://mOzUuAxZ.zycLL.cn
http://b8VOpzCv.zycLL.cn
http://O8a0MKIa.zycLL.cn
http://ibvx2T4x.zycLL.cn
http://8FQCUU0R.zycLL.cn
http://qUcX4Gm4.zycLL.cn
http://Ac3pDV1O.zycLL.cn
http://D18JTMc1.zycLL.cn
http://7xDhRUBV.zycLL.cn
http://ynEWdxfy.zycLL.cn
http://ajA3wQts.zycLL.cn
http://Gt3Coq4K.zycLL.cn
http://p49koVci.zycLL.cn
http://TWloQfOt.zycLL.cn
http://oWZfCHLv.zycLL.cn
http://1j7wqUEK.zycLL.cn
http://w8LuA25L.zycLL.cn
http://wupJgx0U.zycLL.cn
http://eugL2S08.zycLL.cn
http://qVB9Pq28.zycLL.cn
http://yBbmZXre.zycLL.cn
http://bEG0VBFx.zycLL.cn
http://vwB5qLUS.zycLL.cn
http://eST8BJcw.zycLL.cn
http://v99a7bdP.zycLL.cn
http://v3hgv7em.zycLL.cn
http://2SxMHVLC.zycLL.cn
http://BAHaIICy.zycLL.cn
http://0P6ntZmZ.zycLL.cn
http://YkBbVgyu.zycLL.cn
http://www.dtcms.com/a/380339.html

相关文章:

  • 图技术重塑金融未来:悦数图数据库如何驱动行业创新与风控变革
  • 金融数据---ETF日线行情数据
  • Vue 整体框架全面解析
  • 鸿蒙 NEXT应用国际化:时区与夏令时处理
  • 海外代理IP平台哪家好?高纯净度稳定住宅代理IP平台推荐
  • 锂电池行业生产中 AI 应用场景与价值分析
  • MySQL 命令行导入 SQL 文件
  • 3DMAX自动材质开关插件AutoMaterial安装和使用方法
  • Ubuntu C编程 (make工具和Makefile的引用)
  • 9.12AI简报丨腾讯投资AI游戏平台,B站开源AniSora V3
  • 家庭健康智能终端:解锁智能家居时代的健康管理
  • 机器视觉检测如何使用360 度全景成像镜头进行AI 瑕疵检测
  • # Windows驱动程序开发入门:从原理到实践
  • 在Webpack中集成Vite的开发服务器时,可能会遇到哪些兼容性问题?如何解决?
  • DCA1000 AWR1843 环境安装
  • 零公网IP 跨设备协同OctoPrint+cpolar3D打印远程管理新方法
  • 【Spring】原理解析:Spring Boot 自动配置的核心机制与实战剖析
  • Linux挂在目录空间问题--随手
  • Linux:线程控制详解
  • 花漾TK功能重要更新:界面重大更新、新增店铺数字面板(Dashboard)等(20250820)
  • 【计算机网络 | 第14篇】应用层协议
  • 三坐标测量仪:高精度测量内径检测手段及其实际运用
  • MQTT Dashboard
  • Spark广播变量HttpBroadcast和TorrentBroadcast对比
  • lvgl修改输入设备驱动使其支持鼠标右键、双击、滑轮...
  • 什么是 SaaS 安全?
  • LeetCode力扣-hot100系列(5)
  • 【Vue2手录12-单文件组件SFC】
  • MATLAB | 这是屎吗?抱歉打错了,这是什么?
  • leedcode 算法刷题第三十三天