如何将pdfrw的PdfReader对象转换为字节数组或文件流?内存中PDF表单编辑技术问询
在内存中处理pdfrw编辑后的PDF(无需写入本地文件)
我正在为一款PDF编辑器应用开发一个简单的概念验证示例,用Python脚本展示如何用pdfrw库编辑带表单的PDF。现在遇到一个问题:我不想把编辑后的PDF写入本地文件,因为文件的打开/关闭会由外部代码处理,希望所有操作都在内存中完成,返回字节流或io.BytesIO对象,而不是本地文件。
我的代码大致如下:
import pdfrw from io import BytesIO class FormFiller: def __fill_pdf__(self, input_pdf_filestream : bytes, data_dict : dict): template_pdf : pdfrw.PdfReader = pdfrw.PdfReader(input_pdf_filestream) # 这里是表单填充的逻辑 for page in template_pdf.pages: annotations = page['/Annots'] if annotations: for annot in annotations: if annot['/Subtype'] == '/Widget' and '/T' in annot: field_name = annot['/T'][1:-1] # 去掉前后的括号 if field_name in data_dict: annot.update(pdfrw.PdfDict(V=f"{data_dict[field_name]}")) annot.update(pdfrw.PdfDict(Ff=1)) # 设置为只读(可选) return template_pdf def fillForm(self,mapper): value_mapping : dict = mapper.getValues() filled_pdf : pdfrw.PdfReader = self.__fill_pdf__(self.filestream, value_mapping) # 关键节点:如何把filled_pdf转为内存中的字节流? # pdfrw的PdfWriter似乎只能写入本地文件? def __init__(self, filestream : bytes): self.filestream : bytes = filestream
解决方案:用BytesIO让pdfrw在内存中输出
别担心,pdfrw的PdfWriter其实完全支持写入内存流,只是可能文档没强调这点!你只需要用io.BytesIO作为输出目标,而不是传本地文件名。
修改你的fillForm方法,改成这样:
from io import BytesIO def fillForm(self, mapper): value_mapping = mapper.getValues() filled_pdf = self.__fill_pdf__(self.filestream, value_mapping) # 创建一个空的内存字节流 output_stream = BytesIO() # 用PdfWriter把编辑好的PDF写入这个内存流 writer = pdfrw.PdfWriter() writer.write(output_stream, filled_pdf) # 一定要把流的指针移到开头!不然外部代码读的时候会从末尾开始,拿不到内容 output_stream.seek(0) # 这里可以返回BytesIO对象,或者如果需要字节数组的话用output_stream.getvalue() return output_stream
关键细节说明:
PdfWriter.write()的第一个参数不是只能传字符串文件名,它接受任何实现了文件接口的对象——BytesIO正好符合要求,它在内存中模拟了文件的行为。- 写完之后必须调用
seek(0),因为写入操作会把指针移到流的末尾,后续读取操作需要从开头开始才能拿到完整内容。 - 如果外部代码需要的是原始字节数组而不是
BytesIO对象,直接返回output_stream.getvalue()就可以了,这个方法会返回流中的所有字节。
备选方案:如果pdfrw不够用,可以换这些库
如果后续你发现pdfrw对某些复杂PDF表单的支持不太好,或者需要更多高级功能,这些库也能很好支持内存中处理PDF:
- PyPDF2/PyPDF4:表单填充的API更直观,同样支持用
BytesIO做内存输出,社区活跃度也更高。 - pdfplumber:虽然主打PDF提取,但配合其他库也能做表单编辑,对复杂PDF的兼容性不错。
不过就你当前的需求来说,用BytesIO配合pdfrw完全能解决问题,没必要更换库。
内容的提问来源于stack exchange,提问作者Maciej Witkowski
相关产品推荐
相关产品推荐

