在日常的工作和学习过程当中,我相信很多人遇到过这样一个很普通的需求,就是将某一个图片转为PDF或者是将多个图片合并到一个PDF文件。但是,在苦苦搜寻一圈之后发现要么要下载软件,下载了还要注册,注册了还要VIP,甚至SVIP才能实现这样的需求!
今天,我带大家把这个功能打下来!
这个文件夹中的这些图片就是我们今天的主要任务,将这些图片按照顺序合并到一个PDF文件!
实现这个需求最主要的是要用到Python·的两个第三方库,分别是pillow和reportlab,我们先安装这两个库!
pip install pillow reportlab
安装完之后,我们就可以使用了!
这里稍微解释一下,就是多个图片逐个输出位单独的PDF文件,类似于下图中的这个功能,幸亏这个功能还不要钱,否则我是要彪脏话了!
import pathlib
from PIL import Image
def img_to_formart(img:pathlib.Path, _itemdir:pathlib.Path, format="PNG"):
# 转换图片格式
if img.is_file() and img.suffix in [".jpg", ".png", ".jpeg", ".bmp", ".gif"]:
with Image.open(img) as im:
im.save(f"{_itemdir}/{img.name.split('.')[0]}.{format.lower()}", format=format)
if __name__ == "__main__":
imgdir = pathlib.Path("imgs")
itemdir = imgdir / "item"
# 保证转换的文件夹存在
itemdir.mkdir(parents=True, exist_ok=True)
for img in imgdir.iterdir():
# 逐个输入为单独的PDF文件
img_to_formart(img, itemdir, "PDF")
如果我们不用函数封装的话,可能就简简单单的几行代码就能实现,这个函数不仅可以将图片转为PDF,还可以稍加修改就能将图片的格式进行批量转换!
这个需求也是在上一个需求的基础上来实现的,并且需要用到reportlab这个库,由于这个库有一点不好就是合并多个图片到一个PDF文件需要图片的格式必须为PNG格式,所以我们得再合并之前将图片的格式用上个需求的函数img_to_format
全部转换为png!
import re
import shutil
import pathlib
from PIL import Image
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
def img_to_formart(img:pathlib.Path, _itemdir:pathlib.Path, format="PNG"):
# 转换图片格式
if img.is_file() and img.suffix in [".jpg", ".png", ".jpeg", ".bmp", ".gif"]:
with Image.open(img) as im:
im.save(f"{_itemdir}/{img.name.split('.')[0]}.{format.lower()}", format=format)
# 自定义排序键,提取文件名中的数字并转换为整数
def numeric_sort_key(path):
# 使用正则表达式提取文件名中的数字
# 如果找到数字,返回整数形式的数字
# 如果没有找到数字,返回一个大数以确保这些文件排在最后
match = re.search(r'(\d+)', path.name)
return int(match.group(1)) if match else float('inf')
def marge_img_pdf(_imgs_path, _todir_path, name="test", sort_key=numeric_sort_key):
# 将非png格式的图片转换为png,png格式的拷贝
for img in _imgs_path.iterdir():
if img.is_file() and img.suffix == '.png':
shutil.copy2(img, _todir_path)
else:
img_to_formart(img, _todir_path, "PNG")
# 创建一个空白的PDF
c = canvas.Canvas(f"{name}.pdf", pagesize=A4)
# 按文件名称标号排序
ims = sorted(_todir_path.iterdir(), key=sort_key)
# 合并的关键代码
for img in ims:
with Image.open(img) as im:
# width, height = im.size
c.drawImage(img, 0, 0, width=A4[0], height=A4[1])
# 逐页合并进去
c.showPage()
# 保存
c.save()
# 最后删除转换格式的目录
shutil.rmtree(_todir_path)
if __name__ == "__main__":
# 1.获取图片目录
_imgs_path = pathlib.Path("imgs")
# 2.创建目标目录
_todir_path = pathlib.Path("todir")
_todir_path.mkdir(parents=True, exist_ok=True)
# 3.执行合并
marge_img_pdf(_imgs_path, _todir_path, name="ceshi")
怎么样,上图中VIP的合并功能我们就实现了,还是非常简单的,如果你是自学Python,学了很久一直不得章法,其实你就可以去发现这样的功能然后试着自己用代码将它实现,慢慢的等你积累的这样的代码越来越多,你也就拥有了编程思维和分析问题的方法,编程其实不难,难的是如何拥有拆解需求分析问题的能力!
如果,你学到了,请关注我,我会一步步带你实现更多这样的小功能,小需求!
update:
经过验证,最新版的reportlab >=4.1.0版是直接支持jpg格式的图片的,无需全部转换为png,至于其他格式则需要进一步验证,因此,合并函数可以简单的修改如下:
def marge_img_pdf(_imgs_path, name="test", sort_key=numeric_sort_key):
# 创建一个空白的PDF
c = canvas.Canvas(f"{name}.pdf", pagesize=A4)
# 按文件名称标号排序
ims = sorted(_imgs_path.iterdir(), key=sort_key)
# 合并的关键代码
for img in ims:
with Image.open(img) as im:
# width, height = im.size
c.drawImage(img, 0, 0, width=A4[0], height=A4[1])
# 逐页合并进去
c.showPage()
# 保存
c.save()
# 最后删除转换格式的目录
shutil.rmtree(_todir_path)