使用gofpdi库合并PDF遇异常:字节流导入后页面内容重复
gofpdi字节流合并PDF重复内容问题排查
我尝试用gofpdi库通过字节流合并两个PDF,结果生成的文件两页都是第二个PDF的内容;但换成从文件导入第二个PDF时,结果就正常。
问题代码(字节流导入版)
func test(pdfm bytes.Buffer, m pdf.Maroto, pdf2 bytes.Buffer) { pdf := gofpdf.New("P", "mm", "A4", "") w, h := m.GetPageSize() importer := gofpdi.NewImporter() rs := io.ReadSeeker(bytes.NewReader(pdfm.Bytes())) tpl1 := importer.ImportPageFromStream(pdf, &rs, 1, "/MediaBox") pdf.AddPage() importer.UseImportedTemplate(pdf, tpl1, 0, 0, w, h) importer2 := gofpdi.NewImporter() rs2 := io.ReadSeeker(bytes.NewReader(pdf2.Bytes())) // 修正原代码笔误:bytes()改为Bytes() tpl2 := importer2.ImportPageFromStream(pdf, &rs2, 1, "/MediaBox") pdf.AddPage() importer.UseImportedTemplate(pdf, tpl2, 0, 0, w, h) // 核心错误:使用了第一个importer实例 err := pdf.OutputFileAndClose("pdfs/example.pdf") if err != nil { fmt.Errorf("error in generating the output pdf file: %w", err) } }
正常代码(文件导入版)
func test(pdfm bytes.Buffer, m pdf.Maroto, pdf2 bytes.Buffer) { pdf := gofpdf.New("P", "mm", "A4", "") w, h := m.GetPageSize() importer := gofpdi.NewImporter() rs := io.ReadSeeker(bytes.NewReader(pdfm.Bytes())) tpl1 := importer.ImportPageFromStream(pdf, &rs, 1, "/MediaBox") pdf.AddPage() importer.UseImportedTemplate(pdf, tpl1, 0, 0, w, h) pdf.AddPage() importer2 := gofpdi.NewImporter() tpl2 := importer2.ImportPage(pdf, "test.pdf", 1, "/MediaBox") pdf.AddPage() importer.UseImportedTemplate(pdf, tpl2, 0, 0, w, h) err := pdf.OutputFileAndClose("pdfs/example.pdf") if err != nil { fmt.Errorf("error in generating the output pdf file: %w", err) } }
问题分析与修正
核心错误:模板使用实例不匹配
gofpdi的Importer实例内部会维护导入PDF的资源映射表,每个PDF的模板必须和对应的Importer实例绑定使用。字节流版本中,第二个PDF的模板tpl2是通过importer2导入的,但调用UseImportedTemplate时却用了第一个实例importer,导致资源引用混乱,最终重复渲染了第二个PDF的内容。次要问题:字节流处理冗余
bytes.NewReader返回的*bytes.Reader已经实现了io.ReadSeeker接口,不需要额外赋值给io.ReadSeeker类型变量再取地址,可简化写法。
修正后的字节流合并代码
func test(pdfm bytes.Buffer, m pdf.Maroto, pdf2 bytes.Buffer) { pdf := gofpdf.New("P", "mm", "A4", "") w, h := m.GetPageSize() // 处理第一个PDF importer1 := gofpdi.NewImporter() rs1 := bytes.NewReader(pdfm.Bytes()) tpl1 := importer1.ImportPageFromStream(pdf, &rs1, 1, "/MediaBox") pdf.AddPage() importer1.UseImportedTemplate(pdf, tpl1, 0, 0, w, h) // 处理第二个PDF importer2 := gofpdi.NewImporter() rs2 := bytes.NewReader(pdf2.Bytes()) tpl2 := importer2.ImportPageFromStream(pdf, &rs2, 1, "/MediaBox") pdf.AddPage() importer2.UseImportedTemplate(pdf, tpl2, 0, 0, w, h) // 使用对应的importer2实例 if err := pdf.OutputFileAndClose("pdfs/example.pdf"); err != nil { fmt.Printf("生成PDF失败:%v\n", err) } }
另外注意原代码中pdf2.bytes()是拼写错误,应改为pdf2.Bytes(),这也是隐性问题之一。
内容的提问来源于stack exchange,提问作者Pratik Saha Joy
相关产品推荐
相关产品推荐

