Python图片转换PDF:专业指南与代码实现

Python图片转换PDF:专业指南与代码实现

在日常工作中,我们经常需要将多张图片合并成一个PDF文件,以便于存储、分享或打印。Python提供了多种库和方法来实现图片到PDF的转换,从简单的脚本到复杂的自动化流程,都能高效完成。本文将详细介绍几种常用方法,并提供可运行的代码示例。

为什么选择Python进行图片转PDF?

Python作为一门通用编程语言,拥有丰富的第三方库生态系统,特别适合处理文件转换任务。使用Python进行图片转PDF的优势包括:

  • 自动化能力:可以轻松实现批量处理,减少手动操作
  • 跨平台:在Windows、macOS和Linux上均可运行
  • 可定制性:可以根据需求调整PDF参数,如页面大小、图片位置和压缩设置
  • 集成方便:易于与其他Python脚本或系统集成

方法一:使用img2pdf库(推荐)

img2pdf是一个专门用于将图片转换为PDF的Python库,它能直接将图片嵌入PDF而不重新编码,保持原始质量。

安装与基本用法


# 安装img2pdf
pip install img2pdf

# 基本转换代码
import img2pdf
from pathlib import Path

def images_to_pdf(image_list, output_path):
    """将图片列表转换为单个PDF文件"""
    with open(output_path, "wb") as f:
        f.write(img2pdf.convert(image_list))
    print(f"PDF已生成:{output_path}")

# 使用示例
image_files = ["image1.jpg", "image2.png", "image3.jpeg"]
images_to_pdf(image_files, "output.pdf")

处理文件夹中的图片

可以使用pathlib模块处理整个文件夹中的图片:


from pathlib import Path
import img2pdf

def batch_convert(folder_path, output_pdf):
    """转换文件夹中的所有图片为PDF"""
    folder = Path(folder_path)
    image_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.tiff'}
    
    # 收集图片文件并按名称排序
    images = sorted(
        [f for f in folder.iterdir() 
         if f.suffix.lower() in image_extensions],
        key=lambda x: x.name
    )
    
    if not images:
        print("未找到图片文件")
        return
    
    # 转换并保存
    with open(output_pdf, "wb") as f:
        f.write(img2pdf.convert([str(img) for img in images]))
    
    print(f"成功将{len(images)}张图片转换为PDF:{output_pdf}")

# 使用示例
batch_convert("./images_folder", "all_images.pdf")

方法二:使用Pillow(PIL)库

Pillow是Python的图像处理库,也可以用来创建PDF文件。这种方法适合需要额外图像处理的情况。


from PIL import Image
from pathlib import Path

def pillow_images_to_pdf(image_files, output_path):
    """使用Pillow将图片转换为PDF"""
    # 打开第一张图片作为基础
    first_img = Image.open(image_files[0])
    
    # 转换为RGB模式(PDF需要RGB)
    if first_img.mode != "RGB":
        first_img = first_img.convert("RGB")
    
    # 创建其他图片列表
    other_images = []
    for img_path in image_files[1:]:
        img = Image.open(img_path)
        if img.mode != "RGB":
            img = img.convert("RGB")
        other_images.append(img)
    
    # 保存为PDF
    first_img.save(
        output_path, 
        "PDF", 
        resolution=100.0, 
        save_all=True, 
        append_images=other_images
    )
    
    print(f"PDF已生成:{output_path}")

# 使用示例
image_list = ["img1.png", "img2.jpg", "img3.bmp"]
pillow_images_to_pdf(image_list, "pillow_output.pdf")

方法三:使用ReportLab库(高级控制)

ReportLab是专业的PDF生成库,提供最精细的控制,适合需要复杂布局的场景。


from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from PIL import Image
import os

def reportlab_images_to_pdf(image_files, output_path, page_size=letter):
    """使用ReportLab创建带图片的PDF"""
    c = canvas.Canvas(output_path, pagesize=page_size)
    width, height = page_size
    
    for img_path in image_files:
        # 获取图片尺寸
        with Image.open(img_path) as img:
            img_width, img_height = img.size
        
        # 计算缩放比例以适应页面
        ratio = min(width / img_width, height / img_height)
        new_width = img_width * ratio
        new_height = img_height * ratio
        
        # 居中放置
        x = (width - new_width) / 2
        y = (height - new_height) / 2
        
        # 绘制图片
        c.drawImage(img_path, x, y, width=new_width, height=new_height)
        c.showPage()
    
    c.save()
    print(f"PDF已生成:{output_path}")

# 使用示例
images = ["photo1.jpg", "photo2.png"]
reportlab_images_to_pdf(images, "reportlab_output.pdf")

高级功能与优化

1. 图片排序与过滤

在实际应用中,图片可能需要按特定规则排序:


import re
from pathlib import Path

def natural_sort_key(path):
    """自然排序键函数"""
    name = path.stem
    return [
        int(part) if part.isdigit() else part.lower()
        for part in re.split(r'([0-9]+)', name)
    ]

# 使用自然排序
images = sorted(Path("./images").glob("*.jpg"), key=natural_sort_key)

2. PDF压缩优化

转换时可以考虑压缩选项,减小文件体积:


import img2pdf

def compress_images_to_pdf(image_files, output_path, dpi=150):
    """带压缩的转换"""
    # img2pdf默认保持原始分辨率
    # 可以先调整图片大小再转换
    with img2pdf.open("rb", [open(f, "rb").read() for f in image_files]) as doc:
        doc.save(output_path, compress=True)

3. 错误处理与验证

生产环境中需要添加完善的错误处理:


from pathlib import Path
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def safe_images_to_pdf(image_files, output_path):
    """带错误处理的安全转换"""
    valid_images = []
    
    for img_path in image_files:
        try:
            path = Path(img_path)
            if path.exists() and path.is_file():
                # 验证文件是否为有效图片
                with Image.open(path) as img:
                    img.verify()
                valid_images.append(str(path))
            else:
                logger.warning(f"文件不存在或不是有效文件:{img_path}")
        except Exception as e:
            logger.error(f"验证图片失败 {img_path}: {str(e)}")
    
    if not valid_images:
        logger.error("没有有效的图片文件")
        return False
    
    try:
        images_to_pdf(valid_images, output_path)
        return True
    except Exception as e:
        logger.error(f"生成PDF失败:{str(e)}")
        return False

完整示例:图片转PDF命令行工具

以下是一个完整的命令行工具示例,集成了多种功能:


#!/usr/bin/env python3
"""图片转PDF命令行工具"""

import argparse
from pathlib import Path
import img2pdf
from PIL import Image


def main():
    parser = argparse.ArgumentParser(description="将图片转换为PDF文件")
    parser.add_argument("images", nargs="+", help="图片文件路径")
    parser.add_argument("-o", "--output", default="output.pdf", help="输出PDF文件名")
    parser.add_argument("-r", "--recursive", action="store_true", help="递归搜索子文件夹")
    parser.add_argument("-s", "--sort", choices=["name", "date", "size"], 
                       default="name", help="图片排序方式")
    
    args = parser.parse_args()
    
    # 收集图片文件
    image_files = []
    for img in args.images:
        path = Path(img)
        if path.is_dir():
            pattern = "**/*.jpg" if args.recursive else "*.jpg"
            for ext in ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.tiff"]:
                image_files.extend(path.glob(pattern.replace("*.jpg", ext)))
        elif path.is_file():
            image_files.append(path)
    
    # 排序
    if args.sort == "name":
        image_files.sort(key=lambda x: x.name.lower())
    elif args.sort == "date":
        image_files.sort(key=lambda x: x.stat().st_mtime)
    elif args.sort == "size":
        image_files.sort(key=lambda x: x.stat().st_size)
    
    # 转换
    try:
        with open(args.output, "wb") as f:
            f.write(img2pdf.convert([str(img) for img in image_files]))
        print(f"成功生成PDF:{args.output},包含{len(image_files)}张图片")
    except Exception as e:
        print(f"转换失败:{str(e)}")
        return 1
    
    return 0


if __name__ == "__main__":
    exit(main())

总结

使用Python将图片转换为PDF是一个简单而强大的解决方案。根据具体需求选择合适的库:

  • img2pdf:最简单直接,保持原始质量,适合大多数情况
  • Pillow:当需要图像预处理时使用
  • ReportLab:需要复杂PDF布局时的首选

通过掌握这些方法,你可以轻松创建自动化脚本,处理从日常文档扫描到专业图像归档的各种任务。记住在生产环境中添加适当的错误处理和日志记录,以确保脚本的健壮性。