Python自动化图片与PDF批量处理:从Pillow到OCR的完整方案
在实际工作中我们经常会遇到需要批量处理图片或PDF文档的场景。无论是产品图片统一尺寸、添加水印还是将多个PDF合并、拆分或转换格式手动操作不仅效率低下还容易出错。虽然Photoshop等专业工具提供了批量处理功能但对于非设计人员来说学习成本较高且需要付费使用。本文将介绍如何使用Python和开源工具构建一套完整的图片批量处理和PDF处理流程实现从图片预处理到PDF生成的全自动化。这套方案特别适合需要定期处理大量图片和文档的运营人员、内容创作者和办公人员无需编程基础也能快速上手。1. 环境准备与工具选择1.1 核心工具介绍图片批量处理主要使用Pillow库这是Python图像处理的标准库支持多种图像格式的读写和基本操作。PDF处理使用PyPDF2和reportlab库前者用于PDF的拆分、合并等操作后者用于将图片转换为PDF。对于更复杂的PDF处理需求还可以考虑pdfplumber库它能够提取PDF中的文本、表格等结构化信息。如果需要进行OCR识别可以集成pytesseract库。1.2 环境配置步骤首先确保系统已安装Python 3.7及以上版本。然后通过pip安装所需依赖pip install Pillow PyPDF2 reportlab pdfplumber pytesseract如果是Windows系统还需要安装Tesseract OCR引擎# 通过chocolatey安装 choco install tesseract # 或手动下载安装包 # 下载地址https://github.com/UB-Mannheim/tesseract/wikiLinux系统可以通过包管理器安装# Ubuntu/Debian sudo apt-get install tesseract-ocr # CentOS/RHEL sudo yum install tesseract1.3 项目目录结构建议按以下结构组织项目文件image-pdf-processor/ ├── src/ │ ├── image_processor.py # 图片处理核心模块 │ ├── pdf_processor.py # PDF处理核心模块 │ └── utils.py # 工具函数 ├── input/ # 输入文件目录 │ ├── images/ # 待处理图片 │ └── pdfs/ # 待处理PDF ├── output/ # 输出文件目录 ├── config/ # 配置文件目录 └── requirements.txt # 依赖列表2. 图片批量处理实现2.1 基本图片操作函数首先实现图片处理的基础功能包括尺寸调整、格式转换、水印添加等from PIL import Image, ImageDraw, ImageFont import os class ImageProcessor: def __init__(self, input_dir, output_dir): self.input_dir input_dir self.output_dir output_dir os.makedirs(output_dir, exist_okTrue) def resize_images(self, target_size(800, 600), keep_aspectTrue): 批量调整图片尺寸 for filename in os.listdir(self.input_dir): if filename.lower().endswith((.png, .jpg, .jpeg)): input_path os.path.join(self.input_dir, filename) output_path os.path.join(self.output_dir, filename) with Image.open(input_path) as img: if keep_aspect: img.thumbnail(target_size, Image.Resampling.LANCZOS) else: img img.resize(target_size, Image.Resampling.LANCZOS) img.save(output_path) print(f已处理: {filename}) def convert_format(self, target_formatJPEG, quality85): 批量转换图片格式 for filename in os.listdir(self.input_dir): if filename.lower().endswith((.png, .jpg, .jpeg, .bmp)): input_path os.path.join(self.input_dir, filename) name_without_ext os.path.splitext(filename)[0] output_filename f{name_without_ext}.{target_format.lower()} output_path os.path.join(self.output_dir, output_filename) with Image.open(input_path) as img: if img.mode in (RGBA, P): img img.convert(RGB) img.save(output_path, formattarget_format, qualityquality) print(f已转换: {filename} - {output_filename})2.2 高级图片处理功能除了基本操作还可以实现更复杂的功能如批量添加水印、图片压缩优化等def add_watermark(self, watermark_text, font_size36, opacity128): 批量添加文字水印 try: font ImageFont.truetype(arial.ttf, font_size) except: font ImageFont.load_default() for filename in os.listdir(self.input_dir): if filename.lower().endswith((.png, .jpg, .jpeg)): input_path os.path.join(self.input_dir, filename) output_path os.path.join(self.output_dir, filename) with Image.open(input_path) as img: # 创建水印层 watermark Image.new(RGBA, img.size, (0, 0, 0, 0)) draw ImageDraw.Draw(watermark) # 计算水印位置右下角 bbox draw.textbbox((0, 0), watermark_text, fontfont) text_width bbox[2] - bbox[0] text_height bbox[3] - bbox[1] position (img.width - text_width - 20, img.height - text_height - 20) # 绘制水印 draw.text(position, watermark_text, fontfont, fill(255, 255, 255, opacity)) # 合并图片和水印 if img.mode ! RGBA: img img.convert(RGBA) result Image.alpha_composite(img, watermark) if output_path.lower().endswith(.jpg) or output_path.lower().endswith(.jpeg): result result.convert(RGB) result.save(output_path) print(f已添加水印: {filename}) def optimize_images(self, quality85, optimizeTrue): 批量优化图片质量 for filename in os.listdir(self.input_dir): if filename.lower().endswith((.png, .jpg, .jpeg)): input_path os.path.join(self.input_dir, filename) output_path os.path.join(self.output_dir, filename) with Image.open(input_path) as img: # 转换为RGB模式JPEG不支持透明度 if img.mode in (RGBA, P): img img.convert(RGB) save_kwargs {quality: quality, optimize: optimize} if filename.lower().endswith(.png): # PNG优化参数 img.save(output_path, optimizeoptimize) else: # JPEG优化参数 img.save(output_path, **save_kwargs) original_size os.path.getsize(input_path) new_size os.path.getsize(output_path) reduction (original_size - new_size) / original_size * 100 print(f优化完成: {filename} - 大小减少: {reduction:.1f}%)3. PDF处理功能实现3.1 PDF基本操作PDF处理主要包括合并、拆分、旋转页面等基础功能import PyPDF2 from reportlab.lib.pagesizes import letter, A4 from reportlab.pdfgen import canvas import io class PDFProcessor: def __init__(self, input_dir, output_dir): self.input_dir input_dir self.output_dir output_dir os.makedirs(output_dir, exist_okTrue) def merge_pdfs(self, output_filenamemerged.pdf): 合并多个PDF文件 merger PyPDF2.PdfMerger() pdf_files [f for f in os.listdir(self.input_dir) if f.lower().endswith(.pdf)] pdf_files.sort() # 按文件名排序 for pdf_file in pdf_files: pdf_path os.path.join(self.input_dir, pdf_file) merger.append(pdf_path) print(f已添加: {pdf_file}) output_path os.path.join(self.output_dir, output_filename) with open(output_path, wb) as output_file: merger.write(output_file) merger.close() print(fPDF合并完成: {output_filename}) def split_pdf(self, filename, pages_per_split1): 按页拆分PDF文件 input_path os.path.join(self.input_dir, filename) with open(input_path, rb) as file: pdf_reader PyPDF2.PdfReader(file) total_pages len(pdf_reader.pages) for start_page in range(0, total_pages, pages_per_split): end_page min(start_page pages_per_split, total_pages) pdf_writer PyPDF2.PdfWriter() for page_num in range(start_page, end_page): pdf_writer.add_page(pdf_reader.pages[page_num]) output_filename f{os.path.splitext(filename)[0]}_pages_{start_page1}-{end_page}.pdf output_path os.path.join(self.output_dir, output_filename) with open(output_path, wb) as output_file: pdf_writer.write(output_file) print(f已生成: {output_filename})3.2 图片转PDF功能将处理好的图片批量转换为PDF文档def images_to_pdf(self, pdf_filenameimages.pdf, page_sizeA4): 将图片批量转换为PDF image_files [f for f in os.listdir(self.input_dir) if f.lower().endswith((.png, .jpg, .jpeg))] image_files.sort() if not image_files: print(未找到图片文件) return output_path os.path.join(self.output_dir, pdf_filename) # 创建PDF c canvas.Canvas(output_path, pagesizepage_size) page_width, page_height page_size for image_file in image_files: image_path os.path.join(self.input_dir, image_file) try: with Image.open(image_path) as img: # 计算图片在页面中的合适尺寸 img_width, img_height img.size scale min((page_width - 100) / img_width, (page_height - 100) / img_height) new_width img_width * scale new_height img_height * scale # 居中显示 x (page_width - new_width) / 2 y (page_height - new_height) / 2 # 添加新页面并绘制图片 c.showPage() c.drawImage(image_path, x, y, new_width, new_height) print(f已添加图片: {image_file}) except Exception as e: print(f处理图片 {image_file} 时出错: {e}) c.save() print(fPDF生成完成: {pdf_filename}) def extract_images_from_pdf(self, pdf_filename): 从PDF中提取图片 import fitz # PyMuPDF input_path os.path.join(self.input_dir, pdf_filename) doc fitz.open(input_path) for page_num in range(len(doc)): page doc.load_page(page_num) image_list page.get_images() for img_index, img in enumerate(image_list): xref img[0] base_image doc.extract_image(xref) image_bytes base_image[image] image_ext base_image[ext] output_filename f{os.path.splitext(pdf_filename)[0]}_page{page_num1}_img{img_index1}.{image_ext} output_path os.path.join(self.output_dir, output_filename) with open(output_path, wb) as image_file: image_file.write(image_bytes) print(f已提取图片: {output_filename}) doc.close()4. 完整工作流整合4.1 配置文件管理使用JSON配置文件来管理处理参数便于重复使用和修改{ image_processing: { input_dir: ./input/images, output_dir: ./output/images, resize: { enabled: true, width: 800, height: 600, keep_aspect: true }, watermark: { enabled: true, text: Confidential, font_size: 36, opacity: 128 }, optimize: { enabled: true, quality: 85 } }, pdf_processing: { input_dir: ./input/pdfs, output_dir: ./output/pdfs, merge_enabled: false, split_enabled: true, pages_per_split: 1 } }4.2 主程序实现创建主程序来协调整个处理流程import json from src.image_processor import ImageProcessor from src.pdf_processor import PDFProcessor class BatchProcessor: def __init__(self, config_fileconfig/settings.json): with open(config_file, r, encodingutf-8) as f: self.config json.load(f) def process_images(self): 执行图片批量处理 img_config self.config[image_processing] processor ImageProcessor(img_config[input_dir], img_config[output_dir]) if img_config[resize][enabled]: size (img_config[resize][width], img_config[resize][height]) processor.resize_images(size, img_config[resize][keep_aspect]) if img_config[watermark][enabled]: watermark_config img_config[watermark] processor.add_watermark( watermark_config[text], watermark_config[font_size], watermark_config[opacity] ) if img_config[optimize][enabled]: processor.optimize_images(img_config[optimize][quality]) def process_pdfs(self): 执行PDF处理 pdf_config self.config[pdf_processing] processor PDFProcessor(pdf_config[input_dir], pdf_config[output_dir]) if pdf_config[merge_enabled]: processor.merge_pdfs() if pdf_config[split_enabled]: pdf_files [f for f in os.listdir(pdf_config[input_dir]) if f.lower().endswith(.pdf)] for pdf_file in pdf_files: processor.split_pdf(pdf_file, pdf_config[pages_per_split]) def run_full_workflow(self): 执行完整工作流 print(开始图片处理...) self.process_images() print(开始PDF处理...) self.process_pdfs() print(所有处理完成) if __name__ __main__: processor BatchProcessor() processor.run_full_workflow()5. 常见问题与解决方案5.1 图片处理常见问题问题1处理大图片时内存不足现象处理高分辨率图片时程序崩溃或报内存错误。解决方案使用流式处理分块读取图片数据from PIL import ImageFile ImageFile.LOAD_TRUNCATED_IMAGES True # 设置最大图像像素限制 Image.MAX_IMAGE_PIXELS None # 或设置一个合理的上限问题2图片格式兼容性问题现象某些特殊格式的图片无法打开或处理。解决方案添加格式验证和异常处理def safe_image_open(image_path): try: with Image.open(image_path) as img: img.verify() # 验证图片完整性 return True except Exception as e: print(f图片 {image_path} 损坏或不支持: {e}) return False5.2 PDF处理常见问题问题1PDF加密无法读取现象处理加密PDF时出现权限错误。解决方案尝试使用空密码或提供密码参数def read_encrypted_pdf(pdf_path, passwordNone): try: with open(pdf_path, rb) as file: pdf_reader PyPDF2.PdfReader(file) if pdf_reader.is_encrypted: if password: pdf_reader.decrypt(password) else: # 尝试空密码 pdf_reader.decrypt() return pdf_reader except Exception as e: print(f读取PDF失败: {e}) return None问题2中文字体显示问题现象生成PDF时中文显示为乱码。解决方案使用支持中文的字体文件from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont # 注册中文字体 pdfmetrics.registerFont(TTFont(SimSun, simsun.ttc)) # 使用中文字体 c.setFont(SimSun, 12)5.3 性能优化建议批量处理优化使用多进程处理大量文件合理设置批处理大小避免内存溢出使用缓存机制减少重复计算内存管理及时关闭文件句柄使用生成器处理大文件定期清理临时文件6. 高级功能扩展6.1 OCR文字识别集成为图片和PDF添加文字识别功能import pytesseract from pdf2image import convert_from_path def extract_text_from_image(image_path, langchi_simeng): 从图片中提取文字 try: text pytesseract.image_to_string(Image.open(image_path), langlang) return text.strip() except Exception as e: print(fOCR识别失败: {e}) return def extract_text_from_pdf(pdf_path, langchi_simeng): 从PDF中提取文字 try: # 将PDF转换为图片 images convert_from_path(pdf_path) all_text for i, image in enumerate(images): text pytesseract.image_to_string(image, langlang) all_text f--- 第 {i1} 页 ---\n{text}\n\n return all_text except Exception as e: print(fPDF文字提取失败: {e}) return 6.2 自动化脚本调度使用计划任务实现定时批量处理Windows任务计划程序# 创建批处理文件 run_processor.bat echo off cd /d C:\path\to\your\project python main.pyLinux crontab# 每天凌晨2点执行 0 2 * * * cd /path/to/your/project python main.py6.3 Web界面集成使用Flask创建简单的Web界面from flask import Flask, request, render_template, send_file import os app Flask(__name__) app.route(/) def index(): return render_template(index.html) app.route(/process, methods[POST]) def process_files(): # 处理上传的文件 uploaded_files request.files.getlist(files) config request.form.to_dict() # 调用处理逻辑 # ... return send_file(output.zip, as_attachmentTrue) if __name__ __main__: app.run(debugTrue)这套图片批量处理和PDF处理方案提供了从基础到高级的完整功能可以根据实际需求灵活配置。对于常规的办公自动化需求使用基础功能即可满足大部分场景。对于更复杂的需求可以通过扩展高级功能来实现定制化处理。在实际项目中建议先从简单的功能开始测试逐步增加复杂度。同时要注意文件备份避免处理过程中造成原始文件损坏。对于生产环境的使用还需要考虑错误日志记录、处理进度监控等运维方面的需求。

相关新闻

黄金定价权机制与全球市场格局分析

黄金定价权机制与全球市场格局分析

1. 黄金定价权的本质与形成机制黄金定价权是指对全球黄金市场价格形成具有决定性影响力的能力。这种权力并非来自某个单一机构或国家的强制规定,而是通过市场交易机制、储备规模和市场参与者结构共同作用形成的复杂体系。现代黄金定价权的核心在于伦敦金银市场协会&…

2026/10/13 20:10:49 阅读更多 →
开尔文四线检测原理与应用:精准测量低电阻的核心技术

开尔文四线检测原理与应用:精准测量低电阻的核心技术

1. 开尔文四线检测:为什么“两根线”测不准电阻?如果你曾经尝试用万用表测量一段导线、一个电阻焊点,或者一块PCB上铜箔的阻值,结果可能会让你困惑:为什么测出来的数值总是飘忽不定,甚至小到几乎为零&#…

2026/10/13 17:21:39 阅读更多 →
Webswing:零代码改造,将Swing桌面应用无缝迁移至浏览器

Webswing:零代码改造,将Swing桌面应用无缝迁移至浏览器

1. 项目概述:当桌面Swing应用“遇见”浏览器如果你是一位Java开发者,尤其是经历过那个桌面应用黄金时代的同行,对Swing一定不会陌生。那些用JFrame、JButton、JTable构建起来的客户端工具,曾经是企业内部系统、数据管理工具的主力…

2026/10/11 7:04:27 阅读更多 →

最新新闻

AI Agent突破屏幕囚笼:开源SDK如何让智能硬件真正动起来

AI Agent突破屏幕囚笼:开源SDK如何让智能硬件真正动起来

这几天应用商店的榜单有点意思:一款叫 Muse 的 AI 应用冲上免费总榜第一。单看登顶这事,在 AI 圈其实并不新鲜——每隔一阵子就有一款对话式应用靠新鲜感冲榜,然后一个月后杳无音信。真正让我这种长期做 AI 应用开发的人留意的,是…

2026/10/13 20:13:09 阅读更多 →
基于人工智能的课堂分析架构:从采集到反馈的分层设计与实现

基于人工智能的课堂分析架构:从采集到反馈的分层设计与实现

简介:本资源为华东师范大学课程与教学研究所杨晓哲副教授撰写的学术论文《基于人工智能的课堂分析架构:一种智能的课堂教学研究》,面向教育研究者、教研员、中小学教师及教育技术方向的学习者,聚焦大规模课堂分析难以落地、传统听…

2026/10/13 20:13:09 阅读更多 →
皮尔森相关系数从原理到工程实践:相似度计算的基石方法详解

皮尔森相关系数从原理到工程实践:相似度计算的基石方法详解

做数据分析或者算法开发的,应该都碰过这样一个问题:两个东西到底像不像。推荐系统里要判断用户口味是否一致,风控里要看两个特征有没有同涨同跌,特征工程时要排查哪些变量互相冗余。这时候第一个冒出来的方法,往往就是…

2026/10/13 20:13:09 阅读更多 →
深入理解计算机系统答案:笔记、习题与复习路线全解析

深入理解计算机系统答案:笔记、习题与复习路线全解析

简介:《深入理解计算机系统》答案与知识点整理文档,面向正在学习计算机系统、操作系统、汇编语言及内存管理等课程的读者,可用于配合原书复习、备考或快速回顾关键概念。文档将书中散落的重难点提炼为数十条简明笔记,覆盖数值截断…

2026/10/13 20:13:09 阅读更多 →
Python外卖配送数据分析系统设计与实现

Python外卖配送数据分析系统设计与实现

1. 项目背景与核心价值外卖配送系统每天产生海量订单数据,这些数据背后隐藏着配送效率、用户偏好、商家运营等关键信息。作为计算机专业的学生,选择这个方向做毕业设计既能体现大数据处理能力,又能展示Python全栈开发技能,更重要的…

2026/10/13 20:13:09 阅读更多 →
jQuery Mobile按钮组件详解:从增强机制到实战踩坑

jQuery Mobile按钮组件详解:从增强机制到实战踩坑

如果你手里还在维护 jQuery Mobile 项目&#xff0c;一定对它的按钮组件印象深刻。这个框架版本不算新了&#xff0c;但按钮这个基础控件的设计思路&#xff0c;放在今天看依然有些“超前”&#xff1a;它把普通的<a>、<input>、<button>标签重新包装&#x…

2026/10/13 20:12:08 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目&#xff0c;我最大的感受是&#xff0c;大部分坑不是出在技术前沿&#xff0c;而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节&#xff0c;最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了&#xff0c;很难不碰到舵机控制这道坎。做智能小车要转方向&#xff0c;做机械臂要抬关节&#xff0c;做云台要偏航俯仰&#xff0c;背后都是同一个东西在干活&#xff1a;舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”&#xff1f;——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台&#xff1f;或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜&#xff1f;又或者&#xff0c;在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →