You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Golang在现有PDF文件底部插入自定义新文本?

核心实现思路

你遇到的核心问题是无法确定插入坐标,实际上只要先读取PDF每页的页面尺寸和现有内容的边界,就可以自动计算出正确的插入位置,不需要提前知晓PDF的原有内容。


可行方案1:复用现有pdft、ledongthuc/pdf依赖实现

无需引入新的第三方库,只需要先计算坐标再调用原有Insert方法即可:

  1. 调用ledongthuc/pdf的接口读取目标页的页面宽高,以及所有文本元素的最低Y坐标(PDF默认坐标原点在左下角,Y值越小位置越靠下)
  2. 按照你需要的留白、文本字号计算插入位置:插入Y坐标 = 现有内容最低Y坐标 - 预留间距 - 文本高度
  3. X坐标可根据对齐需求设置:左对齐仅需要留30磅左右的左边距,居中/右对齐直接将插入宽度设为页面总宽度减去左右边距,再传入对应的对齐参数即可

参考代码

先实现页面信息读取函数:

import (
    "bytes"
    "github.com/ledongthuc/pdf"
    "github.com/signintech/pdft"
)

// 获取指定页的页面宽度、高度,以及现有内容的最低Y坐标
func getPageInfo(pdfBytes []byte, pageNum int) (width, height, minY float64, err error) {
    reader, err := pdf.NewReader(pdfBytes, int64(len(pdfBytes)))
    if err != nil {
        return 0, 0, 0, err
    }
    page := reader.Page(pageNum)
    mediaBox := page.MediaBox()
    width = mediaBox.Width()
    height = mediaBox.Height()
    minY = height // 初始值为页面顶部坐标

    // 遍历所有文本元素,找到最靠下的Y坐标
    texts, err := page.GetText()
    if err != nil {
        return 0, 0, 0, err
    }
    for _, text := range texts {
        if text.Y < minY {
            minY = text.Y
        }
    }
    return width, height, minY, nil
}

再调用插入方法:

func addTextToPDFBottom(pdfBytes []byte, insertText string, pageNum int) ([]byte, error) {
    // 1. 获取页面信息
    width, _, minY, err := getPageInfo(pdfBytes, pageNum)
    if err != nil {
        return nil, err
    }

    // 2. 自定义参数:左边距30磅,和原有内容间距15磅,插入文本字号12磅
    const (
        marginX = 30.0
        gap = 15.0
        textHeight = 12.0
    )
    insertY := minY - gap - textHeight

    // 3. 调用pdft插入文本
    var pt pdft.PDFt
    err = pt.ReadFrom(bytes.NewBuffer(pdfBytes))
    if err != nil {
        return nil, err
    }
    // align参数:0左对齐,1居中,2右对齐,这里设为1居中
    err = pt.Insert(insertText, pageNum, marginX, insertY, width - 2*marginX, textHeight, 1)
    if err != nil {
        return nil, err
    }

    // 4. 输出处理后的[]byte
    var outputBuf bytes.Buffer
    err = pt.SaveTo(&outputBuf)
    if err != nil {
        return nil, err
    }
    return outputBuf.Bytes(), nil
}

注意事项

  • 如果现有内容已经贴近页面底部,没有足够空白放置新文本,可以先调整页面的MediaBox高度,给底部新增20-30磅的空白区域,再在新增区域插入文本,避免覆盖原有内容
  • 插入西里尔文文本时,需要提前给pdft库加载支持西里尔字符的字体,避免出现乱码

可行方案2:使用封装度更高的UniPDF库,无需手动计算坐标

如果不想自己处理坐标逻辑,可以直接使用UniPDF库的内置页脚添加功能,直接传入文本就会自动放置在每页底部,不需要手动计算位置:

import (
    "bytes"
    "github.com/unidoc/unipdf/v3/model"
    "github.com/unidoc/unipdf/v3/common/license"
)

func addFooterToPDF(pdfBytes []byte, footerText string) ([]byte, error) {
    // 初始化UniPDF许可,开源版可使用AGPL许可
    err := license.SetLicenseKeyAGPL("Your AGPL License Key", "Your Company Name")
    if err != nil {
        return nil, err
    }

    reader, err := model.NewPdfReaderFromBytes(pdfBytes)
    if err != nil {
        return nil, err
    }
    numPages, err := reader.GetNumPages()
    if err != nil {
        return nil, err
    }

    writer := model.NewPdfWriter()
    for i := 1; i <= numPages; i++ {
        page, err := reader.GetPage(i)
        if err != nil {
            return nil, err
        }
        // 12号黑色字,自动添加到页脚居中位置
        err = page.AddFooter(footerText, 12, model.NewPdfColorDeviceRGB(0, 0, 0))
        if err != nil {
            return nil, err
        }
        writer.AddPage(page)
    }

    var outputBuf bytes.Buffer
    err = writer.Write(&outputBuf)
    if err != nil {
        return nil, err
    }
    return outputBuf.Bytes(), nil
}

注意事项

UniPDF开源版采用AGPL协议,商用场景需要购买商业授权。


内容的提问来源于stack exchange,提问作者Aliden Umarov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 03:06:02