(0) 任务需求描述

接到一个需求,要求完成在线测试题目的拼接,这样就可以背题目了(像极了期末考前的我)不过这次不是我要考试 。所以我就帮助他完成考试题目的裁剪、拼接并转换成 PDF 用来打印。

可以看到原始的数据集是一些很相似的图片,因此裁剪和拼接可以很好的批量完成。并且通过分析需求可以将程序主要划分成以下三块:

  • 完成图片的裁剪(要可以选择裁剪框的大小)。
  • 完成图片的拼接(要可以选择一页要拼接多少张图片)。
  • 完成拼接后图片向PDF的转化。

同时要注意可视化的要求,保证更好的交互性,所以这里使用到了进度条 tqdm。这里考虑的情况相对比较简单,因此只处理 png 以及 jpg格式的文件,同时待处理文件夹下面仅有这两种格式的图片。

(1) 准备工作

1.导入需要的库

  • PyMuPDF:主要用来处理 PDF。
  • pillow:主要用来处理图片。
  • tqdm:主要用来引入进度条来完成可视化。
  • shutil:主要用来进行os的相关操作。
  • math:主要进行相关的数学操作。
    import os
    import fitz # fitz 就是导入 PyMuPDF
    from PIL import Image
    from tqdm import tqdm
    import shutil
    import math
    

2.准备部分的代码

  • 主要有三部分

    • initial(img_dir, output_name):完成初始化,将文件夹下面可能存在的无关文件均删除。
    • set_same(img_dir):完成图片文件的统一,将 png 和 jpg 文件统一成为 jpg 文件。
    • clear(img_dir):结束时的清理函数,最后将中间产生的文件夹均删除。
    # **************************** Part 0 初始化清除函数以及格式统一函数 **************************** #
    def initial(img_dir, output_name):# 初始化,将文件夹下面可能存在的无关文件均删除if os.path.exists(img_dir + r"cut\\"):# 删除目录,包括目录下的所有文件shutil.rmtree(img_dir + r"cut\\")if os.path.exists(img_dir + r"compose\\"):shutil.rmtree(img_dir + r"compose\\")if os.path.exists(img_dir + output_name + ".pdf"):os.remove(img_dir + output_name + ".pdf")time.sleep(0.1)
    # 将文件夹下面的png和jpg文件统一成为jpg文件
    def set_same(img_dir):files = os.listdir(img_dir)for file in files:if file.split('.')[-1] == "png":img = Image.open(img_dir + r"\\" + file)img = img.convert('RGB')img.save(img_dir + r"\\" + file.split('.')[0] + ".jpg", quality=95)os.remove(img_dir + r"\\" + file)print("Updated Successfully!!!")time.sleep(0.1)def clear(img_dir):# 结束时的清理函数,最后将中间产生的文件夹均删除if os.path.exists(img_dir + r"cut\\"):shutil.rmtree(img_dir + r"cut\\")if os.path.exists(img_dir + r"compose\\"):shutil.rmtree(img_dir + r"compose\\")if(os.path.exists(img_dir + r"temp\\")):shutil.rmtree(img_dir + r"temp\\")time.sleep(0.1)
    

(2) 要处理的图片形式

  • 具体要处理的单一图片形式如下图所示,所有的图片都是相似的,分为两部分,上面是题目描述,下面是答案,需要的就是这两部分,因此在图片裁剪部分需要将剩下不需要的地方裁掉。

(3) 图片的裁剪

  • image_clip(img_dir):完成图像的分割。
    有几个注意事项,程序运行中会输出图片的大小(默认所有图片的大小一致),可以选择是否需要对图片进行裁剪,若选择需要对图片进行裁剪则需要输入裁剪框的位置,裁剪框的格式如下 left upper right lower,输入正整数,并且中间需要用空格隔开。

        # ******************************* Part 1 完成图像的分割 ********************************* ## 完成图片的切割def image_clip(img_dir):# 完成格式的统一set_same(img_dir)# 创建一个中间文件夹用来存储裁剪完成的图片cut_dir = img_dir + r"cut\\"cnt = 0files = os.listdir(img_dir)os.mkdir(cut_dir)img = Image.open(img_dir + "\\" + files[0])print("图片大小为:" + str(img.size))judge = input("是否要进行图片的裁剪(y/n):")if judge == 'n':# 直接将图片拷贝到中间文件夹for file in tqdm(files, "拷贝到中间文件夹"):cnt = cnt + 1shutil.copy(img_dir + "\\" + file, cut_dir + str(cnt) + ".jpg")elif judge == 'y':# (30, 200, 690, 900)(left, upper, right, lower) = list(map(eval, input("请输入裁剪框的位置(left, upper, right, lower):").split(" ")))# 完成对图片的裁剪for file in tqdm(files,"图片的裁剪"):cnt = cnt + 1img = Image.open(img_dir + "\\" + file)# 这里防止输入超出边界right = min(right, img.size[0])lower = min(lower, img.size[1])cropped = img.crop((left, upper, right, lower))cropped.save(cut_dir + str(cnt) + ".jpg")
    

(4) 图片的拼接

  • 主要的函数是 merge_images(img_dir, image_size, image_colnum,image_row):重点说一下这几个参数的含义。 img_dir 是图片的位置,image_size 表示图片的大小,这个参数主要来调控拼接后的清晰度,值越大,拼接后的清晰度也越大,image_colnum 表示一行有几张图,image_row 表示一列有几张图。

        # ******************************* Part 2 完成多张图像的拼接 ********************************* ## 按照宽度进行所需的比例缩放def resize_by_width(infile, image_size):"""按照宽度进行所需比例缩放"""im = Image.open(infile)(x, y) = im.sizelv = round(x / image_size, 2) + 0.01x_s = int(x // lv)y_s = int(y // lv)out = im.resize((x_s, y_s), Image.ANTIALIAS)return out# 返回一个图片的宽、高像素def get_new_img_xy(infile, image_size):"""返回一个图片的宽、高像素"""im = Image.open(infile)(x, y) = im.sizelv = round(x / image_size, 2) + 0.01x_s = x // lvy_s = y // lvreturn x_s, y_s# 定义图像拼接函数def image_compose(image_colnum, image_size, image_rownum, image_names, image_save_path, x_new, y_new):to_image = Image.new('RGB', (image_colnum * x_new, image_rownum * y_new),(255,255,255))  # 创建一个新图# 循环遍历,把每张图片按顺序粘贴到对应位置上total_num = 0for y in range(1, image_rownum + 1):for x in range(1, image_colnum + 1):from_image = resize_by_width(image_names[image_colnum * (y - 1) + x - 1], image_size)to_image.paste(from_image, ((x - 1) * x_new, (y - 1) * y_new))total_num += 1if total_num == len(image_names):breakreturn to_image.save(image_save_path)  # 保存新图# 得到 image 的list列表def get_image_list_fullpath(dir_path):file_name_list = os.listdir(dir_path)image_fullpath_list = []for file_name_one in file_name_list:file_one_path = os.path.join(dir_path, file_name_one)if os.path.isfile(file_one_path):image_fullpath_list.append(file_one_path)else:img_path_list = get_image_list_fullpath(file_one_path)image_fullpath_list.extend(img_path_list)return image_fullpath_list# 完成图片的融合def merge_images(img_dir, image_size, image_colnum,image_row):image_src_path = img_dir + r"cut\\"# 新建一个临时目录用来保存一次拼接所需的文件数量temp_dir = img_dir + r"temp\\"if os.path.exists(temp_dir):shutil.rmtree(temp_dir)os.mkdir(temp_dir)# 新建一个临时目录用来保存拼接后图片image_save_path = img_dir + r"compose\\"if os.path.exists(image_save_path):shutil.rmtree(image_save_path)os.mkdir(image_save_path)# 计算一张图片要拼接几张小图n = image_colnum * image_row# 获取图片集地址下的所有图片名称files = os.listdir(image_src_path)for i in tqdm(range(1, len(files)+1),"图片的拼接"):shutil.copy(image_src_path + str(i) + ".jpg", temp_dir)if(i % n == 0 or i == len(files)):image_fullpath_list = get_image_list_fullpath(temp_dir)if(i == len(files)):image_save = temp_dir + "test" + str(math.ceil(i/n)) + ".jpg"else:image_save = temp_dir + "test" + str(int(i / n)) + ".jpg"image_rownum_yu = len(image_fullpath_list) % image_colnumif image_rownum_yu == 0:image_rownum = len(image_fullpath_list) // image_colnumelse:image_rownum = len(image_fullpath_list) // image_colnum + 1x_list = []y_list = []image_fullpath_list.sort(key=lambda x:int(x.split('\\')[-1].split('.')[0]))for img_file in image_fullpath_list:img_x, img_y = get_new_img_xy(img_file, image_size)x_list.append(img_x)y_list.append(img_y)x_new = int(x_list[len(x_list) // 5 * 4])y_new = int(y_list[len(y_list) // 5 * 4])image_compose(image_colnum, image_size, image_rownum, image_fullpath_list, image_save, x_new, y_new)if (i == len(files)):shutil.copy(temp_dir + "test" + str(math.ceil(i / n)) + ".jpg", image_save_path)else:shutil.copy(temp_dir + "test" + str(int(i/n)) + ".jpg", image_save_path)shutil.rmtree(temp_dir)os.mkdir(temp_dir)
    

(5) 图片的合并

  • 将拼接完成的图片合并成为 pdf 格式的文件,最后生成的 pdf 文件存在于与图片文件所处文件夹同一级的文件夹中。

    # ******************************* Part 3 完成多张图像合并成pdf ********************************* #
    def pic2pdf(img_dir,output_path,output_name):doc = fitz.open()imgs = os.listdir(img_dir)imgs.sort(key=lambda x:int(x.split('.')[0][4:-1] + x.split('.')[0][-1]))for img in tqdm(imgs,"图片向PDF的转换"):  # 读取图片,确保按文件名排序imgdoc = fitz.open(img_dir + img)  # 打开图片pdfbytes = imgdoc.convertToPDF()  # 使用图片创建单页的 PDFimgpdf = fitz.open("pdf", pdfbytes)doc.insertPDF(imgpdf)  # 将当前页插入文档doc.save(output_name + ".pdf")  # 保存pdf文件doc.close()

(6) 示例

  • 全部图片文件,可以看到里面有 jpg 和 png 两种格式的文件。

  • 程序输入输出以及进度条显示。

  • 拼接完成的 pdf 文件。

全部的代码可以从这里下载:
Python 代码

Python 实现大量图片裁剪拼接并生成PDF相关推荐

  1. python使用fpdf生成pdf文件章节(chapter),包含:页眉、页脚、章节主题、数据排版等;

    python使用fpdf生成pdf文件章节(chapter),包含:页眉.页脚.章节主题.数据排版等: #仿真数据 The year 1866 was marked by a bizarre deve ...

  2. python使用fpdf生成pdf章节(chapter)文件包含:页眉、页脚、章节主体、章节内容等;

    python使用fpdf生成pdf章节(chapter)文件包含:页眉.页脚.章节主体.章节内容等: 目录

  3. python使用fpdf生成pdf文件:配置多种语言字体写入多种文字

    python使用fpdf生成pdf文件:配置多种语言字体写入多种文字 目录

  4. Python学习之使用Python生成PDF报告

    在有些时候运维同事需要对一些数据收集后形成PDF报告的形式发送出去.利用python的reportlab库可以帮我们很快的实现自定义生成PDF报告. 在CentOS 下通过sudo yum insta ...

  5. python pdf报告_Python实现html转换为pdf报告(生成pdf报告)功能示例

    本文实例讲述了Python实现html转换为pdf报告(生成pdf报告)功能.分享给大家供大家参考,具体如下: 1.先说下html转换为pdf:其实支持直接生成,有三个函数pdfkit.f 安装pyt ...

  6. 将Python字符串生成PDF

    笔者在今天的工作中,遇到了一个需求,那就是如何将Python字符串生成PDF.比如,需要把Python字符串'这是测试文件'生成为PDF, 该PDF中含有文字'这是测试文件'. 经过一番检索,笔者决定 ...

  7. keil生成hex文件找不到_骚操作!用Python把公众号文章打包成pdf文件,再也不怕找不到了...

    背景 做自媒体的人,尤其是做了一年甚至更久的自媒体人,尤其是通过自媒体还有一些小收入的人,他们最怕自己的公众号内容因为各种原因而丢失,那就太可怕了! 在做自媒体内容上花了太多心血,如果突然一下就没了, ...

  8. 生成html_听说你不会用Python将字符串生成PDF?来,我教你!

    这是恋习Python推荐的第118篇好文 来源:Python爬虫与算法 作者:jclian   笔者在今天的工作中,遇到了一个需求,那就是如何将Python字符串生成PDF.比如,需要把Python字 ...

  9. python合并pdf 加书签_Python生成pdf目录书签的实例方法

    有时候我们用的一些pdf资料是没有目录的,这样找寻我们想到的东西比较麻烦.本篇文章就为大家带来python来生成pdf目录书签的方法. 首先,我们需要下载一个软件FreePic2Pdf,利用它我们可以 ...

  10. python生成c语言代码_Python爬取C语言中文网教程生成PDF

    [Python] 纯文本查看 复制代码import requests from lxml import etree import re import os import pdfkit def geth ...

最新文章

  1. 按键精灵 getcursorpos没有用_给你们想要的一键输出II按键精灵脚本开发教程
  2. PL/SQL如何设置 窗口列表默认显示
  3. iOS GoldRaccoon第三方FTP文件夹下载失败原因
  4. MySQL和Mariadb都启动不了了_linux centos7mariadb安装成功启动不了 解决思路
  5. 关于git diff的一个命令
  6. 即将发布的 JDK 11 包含了什么?
  7. 语音情感识别的优选方法与流程
  8. ubuntu20.04安装MySQL、卸载MySQL命令
  9. wps如何将字体竖着排列_WPS文字中怎么竖着打字?wps文字竖排的设置方法介绍
  10. 软件系统的沙盘测试是什么东西,沙盘(一款安全软件)_百度百科
  11. 读取本地文件转化成MultipartFile
  12. matlab绘图学习(绘制图形的辅助操作)
  13. 聊聊kafka consumer offset lag increase异常
  14. 科沃斯擦玻璃机器人使用感受_科沃斯擦玻璃机器人怎么样?有人用过自动擦窗机器人吗?价格是多少...
  15. 石油大学c语言上机答案,中国石油大学C语言上机题答案(2015版)答案_最全最详细.docx...
  16. vc6创建dll文件的步骤_创建真正有用的产品支持页面的6步骤计划
  17. 动环视频监控在配电房智能化改造中应用
  18. php 邀请码算法,php生成五位数邀请码
  19. C#之internal访问修饰符
  20. java_ssm教学质量评价系统(学生评教)

热门文章

  1. 20个值得一看的 JS 代码简写片段
  2. Json转XML后将首字母大写(或者其他自己的需求格式)对象中包含list集合以及日期字段的处理(注解形式)
  3. Windows 技术篇-win10、win7设置电脑自动锁屏(非关闭显示器),设置电脑黑屏并锁屏方法
  4. 2022年java学什么?java怎么学?
  5. this.$message
  6. 读书笔记 摘自:《亲密关系:通往灵魂的桥梁(张德芬译)》的笔记(作者: 【加】克里斯多福·孟)
  7. 关于DEV-c++ 运行窗口闪退的解决办法
  8. 【随笔 || 逐源·极简学习法】
  9. 阿里巴巴平台型产品经理
  10. python使用 difflib 对比 两个文档 差异