必须用PIL.Image.open(path).convert("RGB")强制转RGB模式,因PDF不支持RGBA、LA或P模式,否则合并时会报ValueError;convert("RGB")丢弃alpha通道,需先粘贴到白色背景再转换。

用 PIL.Image 打开图片并统一转为 RGB 模式
PDF 不支持 RGBA、LA 或 P 模式(如带透明通道的 PNG),直接合并会报错 ValueError: image mode not supported。必须先转换——哪怕原图是 PNG,也要显式转成 RGB。
实操建议:
- 用
Image.open(path).convert("RGB")强制转换,别依赖默认行为 - 如果图片尺寸差异大,建议统一缩放到相同宽度(比如 800 像素宽,保持宽高比),避免 PDF 页面比例混乱
- 注意:
convert("RGB")会丢弃 alpha 通道,若需保留背景色,先用Image.new("RGB", img.size, (255,255,255))粘贴再转
用 PyPDF2 或 reportlab?选 fitz(PyMuPDF)更稳
PyPDF2 本质不生成 PDF,只拼接已有 PDF 页面;reportlab 需手动布局、写入图像流,对多图批量处理太重。真正适合“图→PDF”的是 fitz(PyMuPDF)——它能直接把 PIL 图像对象写入新 PDF。
安装与基础写法:
立即学习“Python免费学习笔记(深入)”;
pip install PyMuPDF
关键代码片段:
import fitz
doc = fitz.open() # 新建空 PDF
for img_path in image_list:
img = Image.open(img_path).convert("RGB")
pdf_bytes = img.convert("RGB").tobytes("png") # 转 PNG 字节流
img_pdf = fitz.open("pdf", fitz.Pixmap(fitz.csRGB, img.width, img.height, pdf_bytes))
doc.insert_pdf(img_pdf, start_at=-1)
doc.save("output.pdf")注意:fitz.Pixmap 构造时务必传入 fitz.csRGB,否则可能颜色失真。
用 img2pdf 是最轻量且无渲染误差的选择
如果不需要在 PDF 中加文字、页眉页脚,img2pdf 是零依赖、零失真、速度最快的方案。它不经过图像解码/重编码,直接把原始 JPEG/PNG 数据嵌入 PDF 流,体积小、保真度高。
实操要点:
- 安装:
pip install img2pdf - 路径必须是 bytes 或 pathlib.Path,不能是 PIL.Image 对象;所以先保存临时文件或用
io.BytesIO缓存 - JPEG 图片无需转模式,PNG 若含透明通道会报错,需提前用 PIL 去 alpha(同上)
- 控制页面大小:用
img2pdf.mm_to_pt((210, 297))指定 A4 尺寸,避免图片拉伸
常见报错和绕过方式
OSError: cannot write mode RGBA as JPEG:不是 PDF 报错,是调用 .save(..., format="JPEG") 时发生的——说明你误用了 JPEG 保存中间步骤。PDF 合成过程完全不需要保存 JPEG 文件。
ValueError: not enough image data:多见于用 img2pdf 时传了空 bytes 或文件路径不存在,检查 os.path.exists()。
RuntimeError: PDF does not contain any pages:用 fitz 时忘了 doc.save(),或 insert_pdf() 的目标文档被 close 了。
真正容易被忽略的是 DPI 处理:PIL 默认按 72 DPI 渲染,但打印常用 300 DPI。如果最终 PDF 要打印,用 fitz.Rect 显式设置页面尺寸(单位是磅),比依赖图像自身 DPI 更可靠。



















