Python 使用 Spire.PDF for Python 提取 PDF 图片的完整指南
Spire.PDF for Python 是一个强大的 PDF 处理库,可以用于提取 PDF 中的图片。以下是详细的使用指南:
1. 安装与准备
安装 Spire.PDF
pip install Spire.PDF
2. 基础图片提取示例
示例 1:提取所有图片到指定文件夹
from spire.pdf import *
from spire.pdf.common import *
def extract_all_images(pdf_path, output_folder):
"""
提取PDF中的所有图片
"""
# 创建PDF文档对象
pdf = PdfDocument()
# 加载PDF文件
pdf.LoadFromFile(pdf_path)
# 创建图像提取器
image_extractor = ImageExtractor(pdf)
# 遍历所有页面
for page_index in range(pdf.Pages.Count):
page = pdf.Pages.get_Item(page_index)
# 获取当前页面的图片
images = image_extractor.ExtractImages(page_index)
# 保存图片
for i, image in enumerate(images):
# 构建文件名
filename = f"{output_folder}/page_{page_index + 1}_img_{i + 1}.png"
# 保存为PNG格式
image.Save(filename, ImageFormat.get_Png())
print(f"保存图片: {filename}")
# 关闭文档
pdf.Close()
# 使用示例
if __name__ == "__main__":
extract_all_images("input.pdf", "./extracted_images")
示例 2:提取特定格式的图片
def extract_images_by_format(pdf_path, output_folder, image_format="png"):
"""
按指定格式提取图片
"""
pdf = PdfDocument()
pdf.LoadFromFile(pdf_path)
image_extractor = ImageExtractor(pdf)
# 支持的格式映射
format_mapping = {
"png": ImageFormat.get_Png(),
"jpg": ImageFormat.get_Jpeg(),
"jpeg": ImageFormat.get_Jpeg(),
"bmp": ImageFormat.get_Bmp(),
"tiff": ImageFormat.get_Tiff(),
}
if image_format.lower() not in format_mapping:
raise ValueError(f"不支持的格式: {image_format}")
selected_format = format_mapping[image_format.lower()]
for page_index in range(pdf.Pages.Count):
images = image_extractor.ExtractImages(page_index)
for i, image in enumerate(images):
filename = f"{output_folder}/page_{page_index + 1}_img_{i + 1}.{image_format}"
image.Save(filename, selected_format)
print(f"保存图片: {filename}")
pdf.Close()
3. 高级提取功能
示例 3:提取特定页面范围的图片
def extract_images_by_page_range(pdf_path, output_folder, start_page=1, end_page=None):
"""
提取指定页面范围内的图片
"""
pdf = PdfDocument()
pdf.LoadFromFile(pdf_path)
# 如果未指定结束页,则提取到最后
if end_page is None or end_page > pdf.Pages.Count:
end_page = pdf.Pages.Count
image_extractor = ImageExtractor(pdf)
for page_index in range(start_page - 1, end_page):
images = image_extractor.ExtractImages(page_index)
if len(images) > 0:
print(f"第 {page_index + 1} 页找到 {len(images)} 张图片")
for i, image in enumerate(images):
# 获取图片尺寸信息
width = image.Width
height = image.Height
filename = f"{output_folder}/page_{page_index + 1}_img_{i + 1}_{width}x{height}.png"
image.Save(filename, ImageFormat.get_Png())
pdf.Close()
示例 4:按尺寸筛选图片
def extract_images_by_size(pdf_path, output_folder, min_width=100, min_height=100):
"""
只提取尺寸大于指定最小值的图片
"""
pdf = PdfDocument()
pdf.LoadFromFile(pdf_path)
image_extractor = ImageExtractor(pdf)
saved_count = 0
for page_index in range(pdf.Pages.Count):
images = image_extractor.ExtractImages(page_index)
for i, image in enumerate(images):
# 检查图片尺寸
if image.Width >= min_width and image.Height >= min_height:
saved_count += 1
filename = f"{output_folder}/image_{saved_count:03d}.png"
image.Save(filename, ImageFormat.get_Png())
print(f"保存图片 {saved_count}: {filename} ({image.Width}x{image.Height})")
else:
print(f"跳过小图片: {image.Width}x{image.Height}")
print(f"\n共提取 {saved_count} 张符合条件的图片")
pdf.Close()
4. 提取并处理图片信息
示例 5:提取图片并保存元数据
import json
def extract_images_with_metadata(pdf_path, output_folder):
"""
提取图片并保存元数据
"""
pdf = PdfDocument()
pdf.LoadFromFile(pdf_path)
image_extractor = ImageExtractor(pdf)
metadata = []
for page_index in range(pdf.Pages.Count):
images = image_extractor.ExtractImages(page_index)
for i, image in enumerate(images):
# 创建唯一文件名
import uuid
unique_id = str(uuid.uuid4())[:8]
filename = f"image_{unique_id}.png"
filepath = f"{output_folder}/{filename}"
# 保存图片
image.Save(filepath, ImageFormat.get_Png())
# 收集元数据
img_info = {
"filename": filename,
"page": page_index + 1,
"index": i + 1,
"width": image.Width,
"height": image.Height,
"horizontal_resolution": image.HorizontalResolution,
"vertical_resolution": image.VerticalResolution,
"file_size": image.RawFormat # 可以添加实际文件大小
}
metadata.append(img_info)
# 保存元数据到JSON文件
metadata_file = f"{output_folder}/metadata.json"
with open(metadata_file, 'w', encoding='utf-8') as f:
json.dump(metadata, f, ensure_ascii=False, indent=2)
print(f"元数据已保存到: {metadata_file}")
pdf.Close()
示例 6:批量处理多个PDF文件
import os
def batch_extract_images(pdf_folder, output_base_folder):
"""
批量处理多个PDF文件
"""
# 确保输出文件夹存在
if not os.path.exists(output_base_folder):
os.makedirs(output_base_folder)
# 遍历PDF文件夹
for filename in os.listdir(pdf_folder):
if filename.lower().endswith('.pdf'):
pdf_path = os.path.join(pdf_folder, filename)
# 为每个PDF创建独立的输出文件夹
pdf_name = os.path.splitext(filename)[0]
output_folder = os.path.join(output_base_folder, pdf_name)
if not os.path.exists(output_folder):
os.makedirs(output_folder)
print(f"\n处理文件: {filename}")
print(f"输出到: {output_folder}")
try:
extract_all_images(pdf_path, output_folder)
print(f"完成: {filename}")
except Exception as e:
print(f"处理失败 {filename}: {str(e)}")
5. 错误处理和优化
示例 7:带有错误处理的完整解决方案
def safe_extract_images(pdf_path, output_folder):
"""
带有完整错误处理的图片提取函数
"""
pdf = None
try:
# 检查输入文件
if not os.path.exists(pdf_path):
raise FileNotFoundError(f"PDF文件不存在: {pdf_path}")
# 检查输出文件夹
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# 初始化PDF文档
pdf = PdfDocument()
pdf.LoadFromFile(pdf_path)
# 检查是否成功加载
if pdf.Pages.Count == 0:
print("警告: PDF文件为空或无法读取")
return
image_extractor = ImageExtractor(pdf)
total_images = 0
print(f"开始处理: {os.path.basename(pdf_path)}")
print(f"总页数: {pdf.Pages.Count}")
# 逐页提取
for page_index in range(pdf.Pages.Count):
try:
images = image_extractor.ExtractImages(page_index)
page_images_count = len(images)
total_images += page_images_count
if page_images_count > 0:
print(f" 第 {page_index + 1} 页: 找到 {page_images_count} 张图片")
for i, image in enumerate(images):
try:
# 生成安全的文件名
safe_index = i + 1
filename = f"page_{page_index + 1:03d}_img_{safe_index:03d}.png"
filepath = os.path.join(output_folder, filename)
# 保存图片
image.Save(filepath, ImageFormat.get_Png())
except Exception as img_error:
print(f" 保存图片 {i+1} 失败: {str(img_error)}")
except Exception as page_error:
print(f" 处理第 {page_index + 1} 页时出错: {str(page_error)}")
continue
print(f"\n处理完成!")
print(f"总提取图片数: {total_images}")
except Exception as e:
print(f"发生错误: {str(e)}")
raise
finally:
# 确保文档被关闭
if pdf is not None:
pdf.Close()
6. 使用示例脚本
完整的命令行工具示例
import argparse
import sys
def main():
parser = argparse.ArgumentParser(description='从PDF中提取图片')
parser.add_argument('input', help='输入PDF文件路径')
parser.add_argument('-o', '--output', default='./extracted_images',
help='输出文件夹路径 (默认: ./extracted_images)')
parser.add_argument('-f', '--format', default='png',
choices=['png', 'jpg', 'jpeg', 'bmp', 'tiff'],
help='输出图片格式 (默认: png)')
parser.add_argument('--min-width', type=int, default=50,
help='最小图片宽度 (默认: 50)')
parser.add_argument('--min-height', type=int, default=50,
help='最小图片高度 (默认: 50)')
args = parser.parse_args()
try:
# 创建输出目录
import os
if not os.path.exists(args.output):
os.makedirs(args.output)
# 提取图片
pdf = PdfDocument()
pdf.LoadFromFile(args.input)
image_extractor = ImageExtractor(pdf)
image_count = 0
for page_index in range(pdf.Pages.Count):
images = image_extractor.ExtractImages(page_index)
for i, image in enumerate(images):
if image.Width >= args.min_width and image.Height >= args.min_height:
image_count += 1
# 根据格式保存
if args.format == 'png':
filename = f"{args.output}/image_{image_count:04d}.png"
image.Save(filename, ImageFormat.get_Png())
elif args.format in ['jpg', 'jpeg']:
filename = f"{args.output}/image_{image_count:04d}.jpg"
image.Save(filename, ImageFormat.get_Jpeg())
elif args.format == 'bmp':
filename = f"{args.output}/image_{image_count:04d}.bmp"
image.Save(filename, ImageFormat.get_Bmp())
elif args.format == 'tiff':
filename = f"{args.output}/image_{image_count:04d}.tiff"
image.Save(filename, ImageFormat.get_Tiff())
print(f"保存: {filename} ({image.Width}x{image.Height})")
pdf.Close()
print(f"\n完成! 共提取 {image_count} 张图片到 {args.output}")
except Exception as e:
print(f"错误: {str(e)}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
使用建议和注意事项
许可证要求:Spire.PDF 需要有效的许可证才能使用所有功能
内存管理:处理大文件时注意内存使用,及时关闭文档
图片质量:提取的图片质量取决于PDF中嵌入的原始图片质量
格式支持:支持PNG、JPEG、BMP、TIFF等常见格式
性能优化:批量处理时可以考虑使用多线程
这个指南涵盖了从基础到高级的各种使用场景,你可以根据具体需求选择合适的方法。记得在实际使用前先测试代码,并根据具体需求进行调整。