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

如何用borb、pypdf或reportlab添加图片/二维码作为PDF注释

以注释形式添加图片到PDF的实现方案

当然可行,PDF规范支持将图片作为注释的外观,核心是通过注释字典中的/AP(外观字典)指定图片资源。以下是不同库的实现示例及PDF规范的关键字典说明:

1. 使用borb实现

borb提供了高层API直接支持自定义图片注释,无需手动操作底层PDF对象:

先安装依赖:

pip install borb

示例代码:

from borb.pdf import Document, Page, PDF
from borb.pdf.canvas.geometry.rectangle import Rectangle
from borb.pdf.canvas.layout.image.image import Image
from borb.pdf.annotation.custom_annotation import CustomAnnotation

# 新建PDF文档
doc = Document()
page = Page()
doc.add_page(page)

# 加载目标图片(支持本地路径或字节流)
image = Image("qrcode.png", width=100, height=100)

# 定义注释的位置与尺寸(左下坐标x=100, y=600,宽高各100)
annot_rect = Rectangle(100, 600, 100, 100)

# 创建自定义注释并绑定图片外观
image_annotation = CustomAnnotation(
    rect=annot_rect,
    appearance_state="Normal",
    normal_appearance=image
)

# 将注释添加到页面
page.add_annotation(image_annotation)

# 保存PDF
with open("borb_image_annot.pdf", "wb") as output_file:
    PDF.dumps(output_file, doc)

2. 使用PyPDF实现

PyPDF没有直接的高层API支持图片注释,需要手动构建PDF对象和注释字典:

先安装依赖:

pip install pypdf pillow

示例代码:

from pypdf import PdfWriter, PdfReader
from pypdf.generic import DictionaryObject, NameObject, RectangleObject, StreamObject
from PIL import Image
import io

# 读取现有PDF
reader = PdfReader("input.pdf")
writer = PdfWriter()
page = reader.pages[0]

# 加载图片并转换为字节流
img = Image.open("qrcode.png")
img_bytes = io.BytesIO()
img.save(img_bytes, format="PNG")
img_bytes.seek(0)

# 创建图片XObject(PDF中的图片资源)
img_xobj = StreamObject()
img_xobj.set_data(img_bytes.getvalue())
img_xobj.update({
    NameObject("/Type"): NameObject("/XObject"),
    NameObject("/Subtype"): NameObject("/Image"),
    NameObject("/Width"): img.width,
    NameObject("/Height"): img.height,
    NameObject("/ColorSpace"): NameObject("/DeviceRGB"),
    NameObject("/BitsPerComponent"): 8,
})

# 将图片XObject添加到页面资源
if "/Resources" not in page:
    page[NameObject("/Resources")] = DictionaryObject()
if "/XObject" not in page["/Resources"]:
    page["/Resources"][NameObject("/XObject")] = DictionaryObject()
img_name = NameObject("/ImgAnnot")
page["/Resources"]["/XObject"][img_name] = img_xobj

# 构建注释字典
annot = DictionaryObject()
annot[NameObject("/Type")] = NameObject("/Annot")
annot[NameObject("/Subtype")] = NameObject("/Stamp")  # 用Stamp类型保证阅读器兼容性
annot[NameObject("/Rect")] = RectangleObject([100, 600, 200, 700])  # 注释边界:左下(100,600)到右上(200,700)
annot[NameObject("/Contents")] = "图片注释"

# 构建注释的外观字典(Normal状态)
ap_dict = DictionaryObject()
form_stream = StreamObject()
# PDF绘图指令:保存状态→设置变换矩阵→绘制图片→恢复状态
form_stream.set_data("""
q
100 0 0 100 100 600 cm
/ImgAnnot Do
Q
""".encode("utf-8"))
form_stream.update({
    NameObject("/Type"): NameObject("/XObject"),
    NameObject("/Subtype"): NameObject("/Form"),
    NameObject("/BBox"): RectangleObject([0, 0, 100, 100]),
    NameObject("/Resources"): page["/Resources"],
})
ap_dict[NameObject("/N")] = form_stream
annot[NameObject("/AP")] = ap_dict

# 将注释添加到页面
if "/Annots" not in page:
    page[NameObject("/Annots")] = []
page["/Annots"].append(annot)

# 保存输出PDF
writer.add_page(page)
with open("pypdf_image_annot.pdf", "wb") as output_file:
    writer.write(output_file)

3. PDF规范核心字典说明

如果手动构建注释,需关注以下关键键值:

  • /Type: /Annot — 标识对象为注释
  • /Subtype: 可选/Stamp(兼容多数阅读器)或/Custom(自定义类型)
  • /Rect: 注释边界矩形,格式为[x1, y1, x2, y2](PDF坐标:左下为原点)
  • /AP: 外观字典,包含不同状态的外观资源:
    • /N: 必选,Normal状态下的外观,可直接绑定Image XObject,或用Form XObject包裹绘图指令
  • Image XObject需包含的属性:/Type=/XObject、/Subtype=/Image、/Width、/Height、/ColorSpace、/BitsPerComponent

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 14:33:22