使用Golang将HTML转换为PDF的方法与实践

使用Golang将HTML转换为PDF的方法与实践 我们需要将HTML转换为PDF,并且要求毫秒级的处理速度。 请问在这方面最好的开源库是什么?

2 回复

更多关于使用Golang将HTML转换为PDF的方法与实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中实现毫秒级HTML转PDF,推荐使用chromedp库,它通过控制Chrome/Chromium浏览器实现高质量转换。以下是示例代码:

package main

import (
    "context"
    "io/ioutil"
    "log"
    "time"

    "github.com/chromedp/chromedp"
)

func htmlToPDF(htmlContent string, outputPath string) error {
    // 创建上下文
    ctx, cancel := chromedp.NewContext(context.Background())
    defer cancel()

    // 设置超时时间
    ctx, cancel = context.WithTimeout(ctx, 100*time.Millisecond)
    defer cancel()

    var pdfBuffer []byte
    
    // 执行转换任务
    err := chromedp.Run(ctx,
        chromedp.Navigate("about:blank"),
        chromedp.ActionFunc(func(ctx context.Context) error {
            // 注入HTML内容
            frameTree, err := chromedp.FrameTree(ctx)
            if err != nil {
                return err
            }
            err = chromedp.Navigate(frameTree.Root.Frame.ID, "data:text/html,"+htmlContent).Do(ctx)
            return err
        }),
        chromedp.Sleep(50*time.Millisecond), // 等待页面渲染
        chromedp.ActionFunc(func(ctx context.Context) error {
            // 生成PDF
            var err error
            pdfBuffer, _, err = chromedp.PrintToPDF().
                WithPrintBackground(true).
                WithPaperWidth(8.27).  // A4宽度(英寸)
                WithPaperHeight(11.69). // A4高度(英寸)
                Do(ctx)
            return err
        }),
    )

    if err != nil {
        return err
    }

    // 保存PDF文件
    return ioutil.WriteFile(outputPath, pdfBuffer, 0644)
}

func main() {
    html := `
        <html>
            <body>
                <h1>测试文档</h1>
                <p>这是一个HTML转PDF的测试。</p>
            </body>
        </html>
    `
    
    start := time.Now()
    err := htmlToPDF(html, "output.pdf")
    elapsed := time.Since(start)
    
    if err != nil {
        log.Fatal(err)
    }
    
    log.Printf("转换完成,耗时: %v", elapsed)
}

对于更高性能的场景,可以考虑以下优化方案:

  1. 使用浏览器池
type BrowserPool struct {
    pool chan *chromedp.Ctx
}

func NewBrowserPool(size int) *BrowserPool {
    pool := make(chan *chromedp.Ctx, size)
    for i := 0; i < size; i++ {
        ctx, _ := chromedp.NewContext(context.Background())
        pool <- ctx
    }
    return &BrowserPool{pool: pool}
}

func (bp *BrowserPool) Convert(html string) ([]byte, error) {
    ctx := <-bp.pool
    defer func() { bp.pool <- ctx }()
    
    // 转换逻辑
    return generatePDF(ctx, html)
}
  1. 预渲染优化
func preRenderSetup(ctx context.Context) error {
    return chromedp.Run(ctx,
        chromedp.EmulateViewport(1920, 1080),
        chromedp.ActionFunc(func(ctx context.Context) error {
            // 预加载字体和样式
            return chromedp.Evaluate(`
                const style = document.createElement('style');
                style.textContent = '@import url("https://fonts.googleapis.com/css2?family=Roboto");';
                document.head.appendChild(style);
            `, nil).Do(ctx)
        }),
    )
}
  1. 并行处理
func batchConvert(htmls []string) []string {
    var wg sync.WaitGroup
    results := make([]string, len(htmls))
    
    for i, html := range htmls {
        wg.Add(1)
        go func(idx int, content string) {
            defer wg.Done()
            output := fmt.Sprintf("output_%d.pdf", idx)
            err := htmlToPDF(content, output)
            if err == nil {
                results[idx] = output
            }
        }(i, html)
    }
    
    wg.Wait()
    return results
}

关键配置参数:

// 性能优化配置
pdfOpts := chromedp.PrintToPDF().
    WithPreferCSSPageSize(true).
    WithPrintBackground(true).
    WithMarginTop(0.4).
    WithMarginBottom(0.4).
    WithMarginLeft(0.4).
    WithMarginRight(0.4).
    WithScale(1.0)

chromedp的优势在于:

  • 支持现代CSS和JavaScript
  • 渲染质量与Chrome浏览器一致
  • 可通过无头模式减少资源占用
  • 支持并发处理

对于简单的HTML转换,也可以考虑go-wkhtmltopdf,但chromedp在渲染质量和性能方面表现更优。

回到顶部