Python实现图片(合并)转PDF

在日常的工作和学习过程当中,我相信很多人遇到过这样一个很普通的需求,就是将某一个图片转为PDF或者是将多个图片合并到一个PDF文件。但是,在苦苦搜寻一圈之后发现要么要下载软件,下载了还要注册,注册了还要VIP,甚至SVIP才能实现这样的需求!

今天,我带大家把这个功能打下来!

image.png

这个文件夹中的这些图片就是我们今天的主要任务,将这些图片按照顺序合并到一个PDF文件!

安装库

实现这个需求最主要的是要用到Python·的两个第三方库,分别是pillow和reportlab,我们先安装这两个库!

pip install pillow reportlab

安装完之后,我们就可以使用了!

实现需求

1. 将图片分别转换为PDF

这里稍微解释一下,就是多个图片逐个输出位单独的PDF文件,类似于下图中的这个功能,幸亏这个功能还不要钱,否则我是要彪脏话了!

image.png

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,还可以稍加修改就能将图片的格式进行批量转换!

2. 将多个图片合并到一个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)