最近老爸在整族谱的事,用PIL等库处理了一下,这里做个笔记 从家谱网上下载下来的图片的格式不太合他的心意,一张一张改吧,图片数量实在多了(几百张),提了这么几个需求:
- 下载下来的图片全是两页合在一起的,但打印的话需要是单页,那么就需要对半切;(图片切片 crop)
- 下载下来的图片中有页码,每个支系的页码都是从1开始,但最终要所有支系合成一册,要改页码;(更改图片中某一块位置的像素值 putpixel)(图片粘贴 paste)
- 图片文件转pdf文件,并将所有图片合并为一个pdf文件 (图片转pdf文件 ImgToPdf)
?
“小爷我凭啥放着懒觉不睡、游戏不打来给您做苦力啊?”
“事成之后村里给两万劳务费”
“咳咳~~为咱村里做点贡献实乃吾辈分内之事”
咳嗯~言归正传,开始码思路
任务背景介绍
????1.待处理图片格式:JPG(因为不了解这个格式的具体情况,然后就捅了挺大一篓子的,下面会说) ????2.待处理文件目录格式:如下图 可以看见,所有图片的名字都是数字,这是按照内容顺序起的,所以咱切了之后也要保证有序,就需要在遍历出来的文件路径中把这些数字提取出来,然后处理一下作为新图片的名称 比如:原来叫1.jpg的图片,对半切之后应该产生1.jpg和2.jpg;原来叫2.jpg的图片,对半切之后应该产生3.jpg和4.jpg;原来叫25.jpg的图片对半切之后就应该产生49.jpg和50.jpg…
问题分析+代码实现
需求1:图片切片(CropPic)
需要实现的功能如下图所示: 那不就是正中间切一刀然后分俩图片存起来嘛~ 开搞! 要用到的库:os,PIL
- 因为要遍历文件夹,所以得import一个os进来,通过os.walk(文件夹路径)来把D:\20x10这个文件夹里存的所有图片的路径全读出来(关于os.walk的用法可以康康这篇文章[os.walk的简要介绍])
- 因为要操作图片,所以要import一个PIL进来
废话不说了,上代码
import os
from PIL import Image
srcDirectory = input("输入待处理图片所在文件夹的路径:")
if not os.path.exists(srcDirectory):
print("不存在的文件夹你也敢读?你很勇♂噢~")
exit(-1)
dstDirectory = input("输入新文件存放的文件夹路径:")
if not os.path.exists(dstDirectory):
os.mkdir(dstDirectory)
for root, dirs, files in os.walk(srcDirectory, topdown=False):
roots = root.split("\\")
dirName = ""
for subRoot in roots:
if "卷之" in subRoot:
dirName = subRoot
break
NewDir = dstDirectory + "\\" + dirName
if not os.path.exists(NewDir):
os.mkdir(NewDir)
Id = 1
totalNum = len(files)
for file in files:
src_path = root + "\\" + file
dst_path_1 = NewDir + "\\" + str(int(file[:-4])*2-1) + ".png"
dst_path_2 = NewDir + "\\" + str(int(file[:-4])*2) + ".png"
src_img = Image.open(src_path)
length = img.size[0]
height = img.size[1]
crop_box_1 = (length//2, 0, length, height)
crop_box_2 = (0, 0, length//2, height)
img1 = src_img.crop(crop_box_1)
img2 = src_img.crop(crop_box_2)
img1.save(dst_path_1)
img2.save(dst_path_2)
src_img.close()
img1.close()
img2.close()
print("\r当前子文件夹处理进度:{:.2f}%".format(Id*100/totalNum), end='')
print("处理完成!")
需求2:擦去原有页码并生成新页码(AddPageNum)
这是其中一张样例图,可以看见图中有页码“三、四”,最大页码达到三位数; 图片内容识别是不可能做的,因为我不会哈哈哈哈哈哈~ 况且每幅图中页码位置均相同,而且每个图大小均相同,所以咱框定某一坐标范围内的内容,将该范围内的pixel值都设置成白色(255,255,255)就能实现页码擦除啦~ 诶~那坐标范围我咋知道?乱猜?那不是,用电脑自带的画图打开图片,就能显示坐标的 然后,产生新页码也不麻烦: 首先咱把0~9这几个数字对应的汉字图片素材造出来(我是用PPT打出〇一二三四五六七八九这几个字,然后截图存起来之后,再裁剪出每个字,命名就用对应阿拉伯数字,下面是我的目录): 然后怎么在程序里通过整型数来将这几个图贴进去呢? 首先,整型数转换成字符串,然后遍历该字符串,每个字符刚好对应一个图片,使用paste函数将对应数字素材图片粘贴进原图限定位置即可
话不多说上代码 简要说明:
- 遍历文件夹的操作与前面基本无异,只需改变“正片”部分即可。
- 本过程处理的图片是前一步生成的单页文件
- 单页文件中,图片名为奇数的,页码在左;为偶数的,页码在右,需要注意控制
import os
from PIL import Image
srcDirectory = input("输入待处理图片所在文件夹的路径:")
if not os.path.exists(srcDirectory):
print("不存在的文件夹你也敢读?你很勇♂噢~")
exit(-1)
dstDirectory = input("输入新文件存放的文件夹路径:")
if not os.path.exists(dstDirectory):
os.mkdir(dstDirectory)
left = 62 - 30
right = 998 - 62
top = 992
bottom = 1082
elem_size = 30
for root, dirs, files in os.walk(srcDirectory, topdown=False):
if "卷之" not in root:
continue
roots = root.split("\\")
dirName = ""
for subRoot in roots:
if "卷之" in subRoot:
dirName = subRoot
break
NewDir = dstDirectory + "\\" + dirName
if not os.path.exists(NewDir):
os.mkdir(NewDir)
Id = 1
totalNum = len(files)
isLeft = True
PageNum = 1
for i in range(0, totalNum):
count = 0
while not os.path.exists(root+"\\"+str(i+count)+".jpg"
count += 1
src_path = root + "\\" + str(i+count) + ".jpg"
dst_path = NewDir + "\\" + files[i].replace("jpg", "png")
src_img = Image.open(src_path)
left_edge = left
if isLeft:
isLeft = False
else:
left_edge = right
isLeft = True
for x in range(left_edge, left_edge+31):
for y in range(top, bottom):
src_img.putpixel((x, y), (255, 255, 255))
elemDirectory = "F:\\数字素材0~9\\"
PageDigit = [PageNum//100, PageNum%100//10, PageNum%10]
DigitNum = 1
if PageNum >= 10:
DigitNum += 1
if PageNum >= 100:
DigitNum += 1
pos = ()
if isLeft:
pos = (left, top + elem_size * (3 - DigitNum) // 2)
isLeft = False
else:
pos = (right, top + elem_size * (3 - DigitNum) // 2)
isLeft = True
for j in range(0, DigitNum):
elemImg = Image.open(elemDirectory+str(PageDigit[j])+".png")
img.paste(elemImg, box=pos)
pos = (pos[0], pos[1]+elem_size)
elemImg.close()
src_img.save(dst_path)
src.img.close()
print("\r当前子文件夹处理进度:{:.2f}%".format(Id*100/totalNum), end='')
print("处理完成!")
需求3:图片转pdf文件(ImgToPdf)
很简单的一个需求,利用canvas(from reportlab.pdfgen import canvas)打开一个pdf文件画布,通过读取图片数据来填充画布即可生成图片对应的单页pdf文件。 这样就可以得到一个文件夹的pdf,但是要合成一整个文件夹中的pdf,就需要合并pdf(merge pdf)。 其实也好说,调用PyPDF2.PdfFileMerger()产生一个merger,然后将待合并的两个pdf文件用PyPDF2.PdfFileReader()打开后,append进merger,再将merger中的内容write进目的文件路径(dst_root),至此,pdf文件就做好了,然后,习惯问题,merger要记得关:merger.close()。 废话多了,上代码:
import os
import PyPDF2
from reportlab.pdfgen import canvas
from PIL import Image
def ImgToPdf(src_path, dst_path):
Max_W, Max_H = Image.open(src_path).size
pdf_w, pdf_h = (480, 702)
c = canvas.Canvas(dst_path, pagesize=(pdf_w, pdf_h))
if pdf_w/pdf_h < Max_W/Max_H:
c.drawImage(src_path, 0, (pdf_h-Max_H*pdf_w/Max_W)/2, pdf_w, Max_H*pdf_w/Max_W)
else:
c.drawImage(src_path, (pdf_w-Max_W*pdf_h/Max_H)/2, 0, Max_W*pdf_h/Max_H, pdf_h)
c.save()
if __name__ == "__main__":
Directory = input('输入待处理文件夹路径:')
if not os.path.exists(Directory):
print("你他喵的巨勇")
exit(-1)
AimDir = input('输入目标文件夹路径:')
if not os.path.exists(AimDir):
os.makedirs(AimDir)
for root, dirs, files in os.walk(Directory, topdown=False):
if "卷之" not in root:
continue
for file in files:
ImgToPdf(root+"\\"+file, AimDir+"\\"+file.replace("png", "pdf"))
length = len(files)
count = 0
AimPath = root+".pdf"
merger = PyPDF2.PdfFileMerger()
for i in range(1, length+1):
while not os.path.exists(root+"\\"+str(i+count)+".pdf"):
count += 1
src_path = root+"\\"+str(i+count)+".pdf"
merger.append(PyPDF2.PdfFileReader(src_path))
merger.write(AimPath)
merger.close()
|