在日常办公或数据处理中,我们经常需要将多张图片(如扫描件、截图、照片等)合并为一个PDF文件,方便分享或归档。虽然市面上有很多工具可以完成这一任务,但通过Python脚本实现不仅灵活可控,还能根据需求定制布局(如横向/纵向、纸张大小等)。本文将介绍如何使用Python的FPDF和Pillow库高效实现图片转PDF,并支持中文参数和错误处理。
一、核心功能需求
在开发图片转PDF工具时,通常需要满足以下需求:
- 多图合并:支持将多张图片合并为一个PDF。
- 自定义布局 :
- 支持横向或纵向页面方向。
- 支持标准纸张大小(如A4、A3)或自定义尺寸。
- 图片自适应:图片按比例缩放以适应页面,避免变形。
- 错误处理:跳过损坏的图片,保证程序稳定性。
- 中文友好:参数支持中文(如"纵向"、"横向")。
二、技术选型
- FPDF:轻量级PDF生成库,支持自定义页面尺寸和图片插入。
- Pillow(PIL):图片处理库,用于获取图片尺寸和格式转换。
- glob:文件路径匹配,方便批量读取图片。
三、完整代码实现
以下是支持中文参数、自定义布局和错误处理的完整代码:
python
import os
import glob
from fpdf import FPDF
from PIL import Image
def images_to_pdf_fpdf(
image_paths,
output_pdf_path,
paper_size="A4", # 纸张大小(默认A4)
direction="纵向" # 布局方向(默认纵向,支持"横向")
):
"""
将多张图片合并为PDF,支持自定义纸张大小和方向(纵向/横向)
参数:
image_paths: 图片路径列表(支持通配符,如 '*.jpg')
output_pdf_path: 输出PDF路径
paper_size: 纸张大小(默认'A4',支持'A3'/'Letter'/'Legal'或自定义元组,如(200, 300))
direction: 布局方向(默认'纵向',可选'横向')
"""
# 定义标准纸张尺寸(单位:毫米)
paper_sizes = {
"A4": (210, 297),
"A3": (297, 420),
"Letter": (215.9, 279.4),
"Legal": (215.9, 355.6),
}
# 校验纸张大小参数
if isinstance(paper_size, str):
if paper_size.upper() in paper_sizes:
width_mm, height_mm = paper_sizes[paper_size.upper()]
else:
raise ValueError(f"未知的纸张大小: {paper_size}。支持的值: {list(paper_sizes.keys())} 或自定义元组(如 (200, 300))")
elif isinstance(paper_size, (tuple, list)) and len(paper_size) == 2:
width_mm, height_mm = paper_size
else:
raise ValueError("paper_size 必须是预定义名称(如 'A4')或 (width_mm, height_mm) 元组")
# 校验方向参数
direction = direction.lower()
if direction not in ["纵向", "横向"]:
raise ValueError("direction 必须是 '纵向' 或 '横向'")
# 根据方向调整宽高(横向时交换宽高)
if direction == "横向":
width_mm, height_mm = height_mm, width_mm
# 创建 PDF 对象
pdf = FPDF(unit="mm", format=(width_mm, height_mm)) # 直接传入宽高
for image_path in image_paths:
try:
# 打开图片并获取尺寸(转换为毫米)
img = Image.open(image_path)
img_width, img_height = img.size
img_width_mm = img_width * 0.264583 # 像素 → 毫米(1像素 ≈ 0.264583毫米)
img_height_mm = img_height * 0.264583
# 计算缩放比例(适应当前页面尺寸)
scale_width = width_mm / img_width_mm
scale_height = height_mm / img_height_mm
scale = min(scale_width, scale_height)
# 计算缩放后的图片尺寸
new_width_mm = img_width_mm * scale
new_height_mm = img_height_mm * scale
# 添加页面并插入图片(居中)
pdf.add_page()
x = (width_mm - new_width_mm) / 2
y = (height_mm - new_height_mm) / 2
pdf.image(image_path, x=x, y=y, w=new_width_mm, h=new_height_mm)
except Exception as e:
print(f"警告:图片 {image_path} 处理失败,跳过。错误: {e}")
# 保存 PDF
pdf.output(output_pdf_path)
print(f"PDF 已生成:{output_pdf_path}")
# 示例用法
if __name__ == "__main__":
# 获取所有JPG图片(使用raw字符串避免转义)
image_paths = glob.glob(r'E:\Python\learning\图片转PDF\img\*流水.jpg')
output_pdf_path = "1-3月银行流水.pdf"
# 调用方式1:默认A4纵向
images_to_pdf_fpdf(image_paths, output_pdf_path)
# 调用方式2:A4横向
images_to_pdf_fpdf(image_paths, output_pdf_path, paper_size="A4", direction="横向")
# 调用方式3:自定义纸张大小(200x300毫米)纵向
images_to_pdf_fpdf(image_paths, output_pdf_path, paper_size=(200, 300), direction="纵向")
四、代码解析
1. 纸张大小与方向处理
- 标准纸张 :通过字典
paper_sizes定义常见尺寸(如A4、A3)。 - 自定义尺寸 :支持传入元组(如
(200, 300))。 - 方向调整 :横向时交换宽高(
width_mm, height_mm = height_mm, width_mm)。
2. 图片自适应缩放
- 像素转毫米:1像素 ≈ 0.264583毫米。
- 缩放比例:取宽高缩放比例的最小值,确保图片完整显示。
- 居中布局 :计算图片在页面中的偏移量(
x和y)。
3. 错误处理
- 捕获单张图片处理时的异常(如损坏图片),打印警告并跳过。
- 参数校验:检查
paper_size和direction的有效性。
4. 中文参数支持
- 将方向参数命名为
direction,接受"纵向"或"横向"。 - 内部统一转换为小写(
direction.lower()),避免大小写敏感问题。
五、使用场景示例
| 需求 | 调用方式 |
|---|---|
| 默认A4纵向 | images_to_pdf_fpdf(image_paths, output_pdf_path) |
| A4横向 | images_to_pdf_fpdf(image_paths, output_pdf_path, direction="横向") |
| 自定义200x300毫米纵向 | images_to_pdf_fpdf(image_paths, output_pdf_path, paper_size=(200, 300), direction="纵向") |
六、注意事项
- 图片方向 :
- 代码仅调整PDF页面方向,不旋转图片内容 。如果图片本身是横向的,建议先用Pillow旋转图片(如
img.rotate(90))。
- 代码仅调整PDF页面方向,不旋转图片内容 。如果图片本身是横向的,建议先用Pillow旋转图片(如
- 路径问题 :
- 使用
glob.glob(r'...')(raw string)避免Windows路径转义错误。
- 使用
- 性能优化 :
- 对于大量图片,可考虑添加进度条(如
tqdm库)。
- 对于大量图片,可考虑添加进度条(如
七、总结
通过Python实现图片转PDF,不仅灵活高效,还能满足个性化需求(如自定义布局、错误处理等)。本文的代码支持中文参数、标准/自定义纸张大小和横向/纵向布局,适合办公自动化场景。你可以根据实际需求进一步扩展功能(如添加水印、调整图片质量等)。
完整代码与示例 已开源至GitHub:点击查看(示例链接需替换为实际仓库地址)。
希望这篇文章能帮助你轻松实现图片转PDF!如果有任何问题或建议,欢迎在评论区交流。 🚀