基于python实现图片处理与pdf生成小程序
前言把一堆照片、扫描件、截图整理成一个 PDF是日常里特别高频的小需求。手工操作的痛点很清楚图片尺寸不一、方向不一直接丢进 PDF 里有的横有的竖、有的糊有的清图片一多手动一张张处理更是折磨。写一个小命令行工具能一次性解决它一条命令把指定目录或若干文件批量读取、统一尺寸、居中排好最后合成一个 PDF。这个工具虽小却是「命令行程序」的典型骨架——参数解析、输入输出路径处理、错误容忍、依赖声明四件套一件不少。需要提前说明依赖Python 标准库没有图像处理和 PDF 写入的能力。读图、缩放、居中、写出多页 PDF 都依赖第三方库Pillowpip install Pillow导入名仍是PIL。另一条常见路线是用reportlab之类专门的 PDF 生成库但那同样是第三方库且 API 各不相同——本文只用 Pillow 这条线涉及具体参数之处以 Pillow 官方文档为准。一、先定接口一条命令要做什么先把工具的行为说清楚再写代码。设想接口长这样python img2pdf.py a.jpg b.png c.jpg -o 作品集.pdf --width 1240 --height 1754含义是把三个图片文件按给定的每页宽高处理居中放进统一页面输出为作品集.pdf。设计上有几个决定输入用「若干路径」而不是「一个目录」这样既能传单个文件也能配合 shell 通配符批量传如果还想支持目录可以后续再加一个-d/--dir参数页面尺寸用像素给出默认取 A4 在 150 DPI 下的近似值换算关系直观某一页读失败不终止整个程序而是跳过并打印警告——批量处理里一张坏图毁掉整批结果是最恼人的。二、参数解析用 argparse 定义接口标准库的argparse就是为这种场景准备的它负责把命令行字符串变成结构化参数还会自动生成--help。# 适用于 Python 3.8import argparsedef build_parser():parser argparse.ArgumentParser(progimg2pdf,description把若干图片统一尺寸后合成一个 PDF。,)parser.add_argument(inputs, nargs, help输入图片路径可传多个)parser.add_argument(-o, --output, defaultout.pdf, help输出 PDF 路径)parser.add_argument(--width, typeint, default1240, help每页宽度像素)parser.add_argument(--height, typeint, default1754, help每页高度像素)parser.add_argument(--margin, typeint, default0, help页面四周留白像素)return parser几个要点nargs表示这个位置参数至少接收一个值命令行里写几个都收进一个列表typeint让 argparse 自动做类型转换传了非整数会直接报错并给出用法提示default给出可选项的默认值用户不传就是它-o与--output是同一个参数的短名与长名。parse_args()返回一个命名空间对象inputs是列表其余是标量。不要在业务代码里直接读sys.argv——手写解析既难处理--前缀也做不好类型校验和帮助信息。三、批量读取与处理路径、缩略、居中处理单张图片的逻辑要拆成一个纯函数输入一个路径和一个目标尺寸输出一张「已经排好版」的页面。这样它既好测也好复用。# 适用于 Python 3.8需先 pip install Pillowimport sysfrom pathlib import Pathfrom PIL import Imagedef render_page(path, size, margin0, background(255, 255, 255)):把一张图等比缩放后居中放进一个 size 大小的页面。box_w max(1, size[0] - 2 * margin)box_h max(1, size[1] - 2 * margin)with Image.open(path) as src:page_img src.convert(RGB)page_img.thumbnail((box_w, box_h), Image.LANCZOS)offset_x margin (box_w - page_img.width) // 2offset_y margin (box_h - page_img.height) // 2canvas Image.new(RGB, size, background)canvas.paste(page_img, (offset_x, offset_y))return canvas这里刻意用了thumbnail()而不是resize()thumbnail()会原地缩放并保持长宽比、且只缩不放正符合「完整显示、不裁切、不拉伸」的需求。Image.open()用with包住保证文件句柄及时释放。主流程负责遍历输入、报告进度、收集结果# 适用于 Python 3.8需先 pip install Pillowdef collect_pages(inputs, size, margin0):pages []for raw in inputs:path Path(raw)if not path.is_file():print(f跳过不存在的文件{path}, filesys.stderr)continuetry:pages.append(render_page(path, size, margin))except OSError as exc:# Pillow 打不开的文件格式不支持、文件损坏会抛 OSError 及其子类print(f无法读取 {path}{exc}, filesys.stderr)return pages错误处理的两条原则在这里体现得很清楚能预期的错误就地捕获并给出可读提示继续处理后面的文件真正致命的情况一页都没成功留给主流程判断。四、合成 PDF依赖第三方库多页 PDF 的写入同样由 Pillow 完成把第一页当作主对象其余页作为「附加页」一起交出并指明输出格式为 PDF。下面这段的save_all与append_images是 Pillow 常见的多页保存方式参数含义以 Pillow 官方文档为准。# 适用于 Python 3.8需先 pip install Pillowimport sysfrom pathlib import Pathdef main(argvNone):args build_parser().parse_args(argv)size (args.width, args.height)pages collect_pages(args.inputs, size, args.margin)if not pages:print(没有任何可用图片已退出。, filesys.stderr)return 1out_path Path(args.output)out_path.parent.mkdir(parentsTrue, exist_okTrue) # 输出目录不存在就先建first, rest pages[0], pages[1:]# 传给 Pillow 的路径用字符串形式避免不同版本的路径对象支持差异first.save(str(out_path), PDF, save_allTrue, append_imagesrest,resolution150.0)print(f已写出 {out_path}共 {len(pages)} 页)return 0if __name__ __main__:sys.exit(main())几个必须注意的点写之前先确保输出目录存在否则save会因路径不存在而失败PDF 输出会重新编码图片不是把原始文件「打包」进 PDF所以像素质量会受页面尺寸与保存参数影响如果需求更复杂文字排版、矢量元素、水印、书签reportlab这类专门的 PDF 库会合适得多——记得它同样是第三方依赖且 API 与 Pillow 不同具体用法以该库官方文档为准。环节用到的能力来自哪里参数解析argparse.ArgumentParser、add_argument标准库路径处理pathlib.Path、is_file、mkdir标准库错误报告sys.stderr标准库读图 / 缩放 / 居中Image.open、convert、thumbnail、paste、Image.newPillow第三方多页 PDF 写入Image.save(..., save_allTrue, append_images[...])Pillow第三方常见坑点1. 不说清依赖读者一跑就报错。❌ 代码顶部只有from PIL import Image没有任何安装说明。 ✅ 明确写出「需先 pip install Pillow」并说明它是第三方库、不在标准库里。2. 一次性把所有图片读进内存再处理。❌ 先把上百张原图全部Image.open()存成列表内存瞬间吃满。 ✅ 逐张打开、缩到位、贴成页面原图句柄用完即释放with。3. 一张坏图让整批任务崩掉。❌ 循环里不捕获异常遇到损坏文件直接Traceback退出前面处理的全白做。 ✅ 逐张 try / except 捕获OSError跳过并打印警告继续处理。4. 输出目录不存在导致保存失败。❌ 直接save(输出/子目录/a.pdf)路径不存在时抛异常。 ✅ 保存前用Path(...).parent.mkdir(parentsTrue, exist_okTrue)建目录。5. 手写sys.argv解析。❌ 用下标取参数遇到-o缺少值、传了非整数就崩。 ✅ 用argparse它会自动处理短名 / 长名、类型转换与帮助信息。6. 以为 PDF 是「无损打包」。❌ 认为把原图塞进 PDF 后画质一定和原图一样。 ✅ 多页 PDF 保存会重新编码图片页面上是渲染后的位图关心画质就调大页面尺寸或换专门的 PDF 库。7. 打开图片却忘了关闭。❌im Image.open(path)在循环里反复执行文件句柄越积越多。 ✅ 用with Image.open(path) as im:缩略与粘贴都在这个上下文里完成。8. 没有给「一页都没成功」的情况留出口。❌ 全部图片都失败时仍去保存产出一个空文件或抛难以理解的异常。 ✅ 收集完页面后先判断列表是否为空为空则打印明确提示并返回非零状态码。总结步骤做什么关键点定义接口输入若干路径、输出 PDF、可选页宽 / 页高行为先讲清再写代码解析参数argparse定义位置参数与选项类型转换、默认值、自动帮助处理单张thumbnail 居中 白底保持比例、只缩不放批量收集遍历、校验路径、捕获OSError坏图跳过不中断整批写出 PDFsave(..., save_allTrue, append_images[...])Pillow 为第三方依赖写前建目录一句话收尾这个小程序的价值不在于「把图拼成 PDF」这件事本身而在于它把命令行工具的四件事——参数、路径、批处理、错误容忍——串成了一条完整链路把 PDF 写入换成任何第三方库这套骨架都不用改。

相关新闻

基于Python实现新闻爬取系统

基于Python实现新闻爬取系统

前言 「爬一个新闻站」和「做一个新闻爬取系统」的区别在于:前者抓一页就结束,后者要不停地把「列表页发现链接、详情页抽取正文、结果去重入库」这条流水线跑通,而且中途任何一个环节出错都不能让整批任务崩掉。 常见误解是「新闻站结构简单…

2026/10/11 19:24:26 阅读更多 →
Linux 8.5安装Oracle 21C单实例:完整步骤与避坑指南

Linux 8.5安装Oracle 21C单实例:完整步骤与避坑指南

简介:面向需要在Linux 8.5上部署Oracle 21C数据库的运维与DBA人员,这份PDF文档完整记录了单实例环境从零到可用的全过程。内容涵盖软件准备、部署规划、虚拟机创建、操作系统安装及系统参数优化等核心环节,尤其对hosts配置、SELinux调整、防火…

2026/10/11 19:24:26 阅读更多 →
微信聊天记录导出全攻略:解密SQLite数据库并生成HTML/Word/CSV

微信聊天记录导出全攻略:解密SQLite数据库并生成HTML/Word/CSV

简介:这款微信聊天记录提取与分析工具,专门面向有长期备份与复盘需求的个人用户,以及希望研究聊天数据解析和可视化的开发者。它支持将微信聊天导出为HTML、Word、CSV等常用格式,便于永久存档、跨平台查阅与二次编辑;并…

2026/10/11 19:24:26 阅读更多 →

最新新闻

用代码对抗分心:ADHD开发者如何构建低认知负荷的效率工具链

用代码对抗分心:ADHD开发者如何构建低认知负荷的效率工具链

1. 一个看似玩笑的标题,背后藏着多少真实需求第一次看到“i-have-adhd”这个项目标题,我下意识以为是个段子。毕竟在技术社区里,用自嘲式命名来降低预期、拉近距离的做法太常见了。但点进去认真翻了一遍之后,我发现它其实是一个相…

2026/10/11 20:14:02 阅读更多 →
MySQL底层机制深度解析:索引设计、事务隔离与性能调优实战

MySQL底层机制深度解析:索引设计、事务隔离与性能调优实战

MySQL这个名字,一说出来大家都不陌生,做后端、搞数据、写业务的,基本每天都在跟它打交道。但说实话,我见过太多人CRUD写得很溜,一碰上慢查询、死锁、主从延迟就抓瞎。前段时间帮某团队排查一个线上问题,数据…

2026/10/11 20:14:02 阅读更多 →
LuatOS系统消息与消息队列机制:嵌入式Lua异步驱动核心解析

LuatOS系统消息与消息队列机制:嵌入式Lua异步驱动核心解析

搞嵌入式Lua开发,绕不开LuatOS这套东西。当初我第一次打开它的系统消息列表文档时,说实话是有点懵的:一大串消息名、回调、订阅关系,看起来像个迷宫。但等你真正弄懂了sys.subscribe、sys.publish、sys.timer和sys.loop这几根线之…

2026/10/11 20:14:02 阅读更多 →
毕设级双任务系统:协同过滤+票房预测的特征对齐实践

毕设级双任务系统:协同过滤+票房预测的特征对齐实践

简介:这是一份面向计算机专业本科生的高分毕业设计实战资源,聚焦机器学习在影视领域的双任务应用:个性化电影推荐与票房预测。资源适用于毕业设计、课程设计及项目实训,帮助学习者掌握数据清洗、特征工程、协同过滤、内容推荐、集…

2026/10/11 20:14:02 阅读更多 →
时序相关性下的蒙特卡洛场景生成与削减:原理、实现与避坑

时序相关性下的蒙特卡洛场景生成与削减:原理、实现与避坑

1. 场景生成与削减到底在研究什么:先明确技术定位和业务价值前阵子有同行在群里聊到一个课题,名字叫“考虑时序相关性MC的场景生成与削减研究”。乍一看像纯粹的数学题,但做过电力系统、综合能源或者碳交易相关研究的人应该马上能反应过来&am…

2026/10/11 20:14:02 阅读更多 →
地下2米土壤墒情监测:管式监测仪如何改变灌溉决策

地下2米土壤墒情监测:管式监测仪如何改变灌溉决策

这大概是不少果园主、农场主都遇到过的怪事:叶片中午蔫下去,你赶紧浇水,浇了一小时,第二天反而更蔫。挖开土一看,表层10厘米明明是湿的,可往下翻到30厘米,手指甲都掐不进去的干土块,…

2026/10/11 20:13:02 阅读更多 →

日新闻

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

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

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

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

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

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

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

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

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

2026/10/11 0:00:27 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 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/11 10:45:37 阅读更多 →
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/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练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/11 14:36:54 阅读更多 →