Python 多图拼接,多图转PDF,一气呵成

对于一些零散的图片,想要把它们给拼接起来,有时候呢,再把它转化为PDF格式可能会更方便一点,那么接下来讲的可能就会派上用场。

没错,如标题所说,就一个库,PIL,就能实现这些功能【完整代码在文章最后】

当然整个过程还得依靠一下其他库来获取下文件,或者实现一些其它小操作
  • 首先,把需要拼接的图片保存到一个文件夹,保证该文件下除了需要的文件外没有其他图片文件。
  • 还有,要保证图片按名称排列的次序和拼接顺序一致(也不一定非这样,不这样的话,就需要写额外代码排序),而一般保存的时候一系列的图片的名称已经是有序的了,所以就先这么来吧。
    • 弄几张表情包来做例子吧:

在这里插入图片描述
在这里插入图片描述

  • 接下来要做的就是利用 os 库获取到这些图片文件的路径,并存入列表等待使用
    • 首先得获得文件夹的路径 path (当然是自己输入啦)
    • 然后再获取到文件夹的文件路径
path = r'c:\users\...\...'
imgs = [op.join(path, name) for name in os.listdir(path)]
不难发现,这获取到的不仅是文件夹下的图片路径,而是该文件下所有的文件路径, 没关系,后面可以通过试错来给它筛喽(当然也可以多写几行代码筛选一下,保留住图片的文件路径[依据后缀],甚至筛选出一些特定的图片文件)
  • 还有一个考虑,就是要拼接的所有图像尺寸是不是一致?

    • 很多情况下,像ppt、漫画,大多数情况每张图的尺寸是一样的,但是也不能排除尺寸不一的情况
    • 那么可以设置一个阀值,判断需不需要考虑尺寸不一样的情况
    • 如果需要考虑的话,就得获取每一张图像的尺寸,然后来计算拼图画布的大小
  • 接下来,就先循环遍历图片路径,把图片打开,并转换为 ‘RGB’ 格式(傻瓜式的统一下格式),然后把打开的图像注意添加到图像列表中
    • 设拼接所用画布高为hight,稍微调整一下,每张图间的间隔来个 5, 然后整体上下留白分别为 10, 那可以先算出所有留白的值
hight = 20 + 5*len(img_list)
  • 然后,遍历的时候,如果需要考虑图拍尺寸不一的情况,就得获取文件尺寸的列表,顺便还可以计算出画布的高度
for im in imgs:
    try:
        img = Image.open(im).convert('RGB')
        img_list.append(img)
        if if_parse:
            size_list.append(list(img.size))
            hight += img.size[1]
    except:
        pass

try 的使用,就不用怕遍历打开路径的时候遇到非图片而报错停止了

  • 获取到图片(或以及尺寸), 接下来就可以开始贴图了

  • 第一种情况,图片的尺寸不一
    • 先按图片宽度把尺寸排序,以获得最大宽
    • 然后再左右两边各留白 5, 计算出画布宽度
    • 得到尺寸后创建画布 canv ,底色默认白色,格式统一为 RGB
size_lt = sorted(size_list, key=lambda x: x[0])
width = size_lt[-1][0] + 10
canv = Image.new('RGB', (width, hight), (255, 255, 255))
然后就可以遍历贴图了
先获取当前要贴的图片的尺寸,然后用画布宽度减去图片宽度最后整除2得到贴图时左上角坐标,使得图片位置居中
y = 10  # 10 为上边的留白值
for i in range(len(img_list)):
    size = size_list[i]
    dx = (width - size[0])//2
    canv.paste(img_list[i], (dx, y))
y 为每次贴图的 ‘纵’ 坐标,每次贴图后要加上所贴图的高度以及留白值 5, 得到下一次贴图的 ‘纵’ 坐标
y = 10
for i in range(len(img_list)):
    size = size_list[i]
    dx = (width - size[0]) // 2
    canv.paste(img_list[i], (dx, y))
    img_list[i].close() # 用完就顺手关闭一下图片
    y += size[1] + 5
  • 另一种情况,图片尺寸一样
    • 先计算画布大小 ,画布宽度即是:随便一张图的宽度+留白值;画布高度即为:图片数x(任一张图的高度+图间留白值)+上下留白值
    • 同样,按尺寸创建画布
canv = Image.new('RGB', \
	(10 + img_list[0].size[0], 20 + len(img_list)*(img_list[0].size[1] + 5)), (255, 255, 255))  
接下来就是没有感情的贴图
for i in range(len(img_list)):
    canv.paste(img_list[i], (5, 10 + i * (5 + img_list[0].size[1])))
    img_list[i].close()
  • 再来点内容,白花花的底色,贴完图后加个框吧

draw = ImageDraw.Draw(canv)
draw.rectangle((0, 0, canv.size[0]-1, canv.size[1]-1), outline='black', width=5)

在这里插入图片描述

第一个元组参数,前两个是框框左上角的坐标,后两个是框框右下角的坐标
outline 是框框的颜色; width 是框框的宽度
弄完这些,保存一下吧
canv.save(out_path, 'PDF', resolution=100.0, save_all=True)

Ps: 要是不需要拼长图,而是需要一张图,一页pdf,那么就改一下保存的代码。

img_list[0].save(out.path, "PDF", resolution=100.0, save_all=True, append_images=img_list[1:])
这里解释一下,img_list 是Image对象的列表。另,这样的话,效果如下在这里插入图片描述

完整代码如下

  • path 参数即为上文的文件夹路径

  • show 用于判断是否展示最终图片

  • if_parse 用于告诉函数是否需要考虑图片尺寸不一的情况

  • out_path 即为输出的文件名(或者是路径,包含文件名)

from PIL import Image, ImageDraw
from random import randint
import os.path as op
import os

def paste_and_pdf(path, show=True, if_parse=None, out_path=r'c:\users\pxo\desktop\document_{}.pdf'.format(randint(0, 999))):
    while op.exists(out_path):
        out_path = r'c:\users\pxo\desktop\document_{}.pdf'.format(randint(0, 999))
    imgs = [op.join(path, name) for name in os.listdir(path)]
    size_list, img_list = [], []
    hight = 20 + 5*len(img_list)
    for im in imgs:
        try:
            img = Image.open(im).convert('RGB')
            img_list.append(img)
            if if_parse:
                size_list.append(list(img.size))
                hight += img.size[1]
        except:
            pass

    if if_parse:
        size_lt = sorted(size_list, key=lambda x: x[0])
        width = size_lt[-1][0] + 10
        canv = Image.new('RGB', (width, hight), (255, 255, 255))
        y = 10
        for i in range(len(img_list)):
            size = size_list[i]
            dx = (width - size[0])//2
            canv.paste(img_list[i], (dx, y))
            img_list[i].close()
            y += size[1]+5
    else:
        canv = Image.new('RGB', (10 + img_list[0].size[0], 20 + len(img_list)*(img_list[0].size[1] + 5)), (255, 255, 255))
        for i in range(len(img_list)):
            canv.paste(img_list[i], (5, 10 + i*(5+img_list[0].size[1])))
            img_list[i].close()
    draw = ImageDraw.Draw(canv)
    draw.rectangle((0, 0, canv.size[0]-1, canv.size[1]-1), outline='black', width=5)
    canv.save(out_path, 'PDF', resolution=100.0, save_all=True)
    if show:
        canv.show()


def old_paste_pic():
    #  im1.save(pdf_name, "PDF", resolution=100.0, save_all=True, append_images=im_list)
    path = r'c:\users\pxo\desktop\tt'
    imgs = [op.join(path, name) for name in os.listdir(path)]
    size = Image.open(imgs[0]).size
    new = Image.new('RGB', (size[0], size[1]*len(imgs)))
    for i in range(len(imgs)):
        im = Image.open(imgs[i])
        new.paste(im, (0, size[1]*i))

    new.show()
    new.save(op.join(path, 'new.jpeg'), quality=90)

def main():
    path = r'c:\users\pxo\desktop\ttt'
    out_path = op.join(path, 'out.pdf')
    paste_and_pdf(path, if_parse=1, out_path=out_path)

main()
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的壳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值