如何使用Golang在现有PDF文件底部插入自定义新文本?
核心实现思路
你遇到的核心问题是无法确定插入坐标,实际上只要先读取PDF每页的页面尺寸和现有内容的边界,就可以自动计算出正确的插入位置,不需要提前知晓PDF的原有内容。
可行方案1:复用现有pdft、ledongthuc/pdf依赖实现
无需引入新的第三方库,只需要先计算坐标再调用原有Insert方法即可:
- 调用
ledongthuc/pdf的接口读取目标页的页面宽高,以及所有文本元素的最低Y坐标(PDF默认坐标原点在左下角,Y值越小位置越靠下) - 按照你需要的留白、文本字号计算插入位置:插入Y坐标 = 现有内容最低Y坐标 - 预留间距 - 文本高度
- 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
相关产品推荐
相关产品推荐

