写完想着记录点什么,就写下了这篇自己看的博客,记录一下心路历程。
运行效果图
功能实现
1)多页PDF文档给页面标序号
2)单页PDF可以复制多份。第一个复制的页面标1,第二个复制的页面标2,以此类推
实现思路
之前完成过一个图片标序号的小脚本,PDF标序号的话,可以先转成图片,然后图片标序号,最后把图片整合起来,功能实现以后想着做个界面的东西,好看点,最后把代码打包成exe,直接就能使用了,ok想完说干就干
环境准备
python 3.6 64位(安装PythonMagick需要下载对应版本,不然报错) 用到的库:tkinter,PyPDF2,PythonMagick,reportlab
实现过程
开始整python没多久,没做到任何库随手拿来用的地步,所以就是漫长的百度过程,看别人的教程、博客,仿写改写,然后看API用法熟悉一下
用到的库:tkinter,PyPDF2,PIL
PDF标序号主要参考博客:1) #主要功能实现参考这个就行
2) #图片转PDF
tkinter部分主要参考教程:1)https://morvanzhou.github.io/tutorials/python-basic/tkinter/ #tkinter基础
2) #事件绑定
exe打包参考教程:
关键代码
1 import PyPDF2
2 import PythonMagick
3 from PIL import Image,ImageDraw,ImageFont
4 from reportlab.pdfgen import canvas
5 from reportlab.lib.pagesizes import A4
6 import os
7
8 def copy_pdf(fn,num,path): # 拷贝PDF
9 save_names = []
10 for i in range(1, num+1):
11 save_name = str(i)+'.pdf'
12 save_names.append(save_name)
13 with open(fn,'rb') as pdf1File:
14 pdf1_r = PyPDF2.PdfFileReader(pdf1File)
15 for save_name in save_names:
16 pdfWriter = PyPDF2.PdfFileWriter()
17 pdfxFile = open(os.path.join(path,save_name),'wb')
18 pagObj = pdf1_r.getPage(0)
19 pdfWriter.addPage(pagObj)
20 pdfWriter.write(pdfxFile)
21 pdfxFile.close()
22 return save_names, num
23
24 def pdf_2_pic(fn,path): # PDF转换成图片
25 with open(fn,'rb') as pdf1File:
26 pdf_r = PyPDF2.PdfFileReader(pdf1File)
27 npage = pdf_r.getNumPages()
28 if not os.path.exists(path):
29 os.makedirs(path)
30 for p in range(npage):
31 im = PythonMagick.Image(fn+'['+str(p)+']')
32 outfn = '%03d.jpg' % (p)
33 outfn = os.path.join(path, outfn)
34 im.write(outfn)
35
36 def pic_add_num(fn,path): # 图片添加标记
37 for img in [item for item in os.listdir(path) if item.endswith('.jpg')]:
38 im1 = Image.open(os.path.join(path,img))
39 drawimg = ImageDraw.Draw(im1)
40 with open(fn,'rb') as f1:
41 pdf_r = PyPDF2.PdfFileReader(f1)
42 npage = pdf_r.getNumPages()
43 if npage > 1:
44 num = os.path.splitext(img)[0][-3:]
45 else:
46 num = os.path.split(fn)[1].split('.')[0]
47 font = ImageFont.truetype('arial.ttf', 20)
48 drawimg.text((20,20),str(num),font=font,fill='#ff0000')
49 im1.save(os.path.join(path,img))
50
51 def pic_2_pdf(pdfFileName, inPath): # 图片转换成PDF
52 c = canvas.Canvas(pdfFileName)
53 (w, h) = A4
54 jpgs = [item for item in os.listdir(inPath) if item.lower().endswith('jpg')]
55 for infn in jpgs:
56 infn = os.path.join(inPath, infn)
57 c.setFillAlpha(1)
58 c.drawImage(infn, 0, 0, w, h)
59 c.showPage()
60 for file in jpgs:
61 os.remove(os.path.join(inPath, file))
62 c.save()
63
64 def trans_pdf(file_name,save_path,get_num,num=1):
65 if get_num == 0:
66 pns = copy_pdf(file_name, num, save_path)[0]
67 for pn in pns:
68 save_file_path = os.path.join(save_path, pn)
69 pdf_2_pic(save_file_path, save_path)
70 pic_add_num(save_file_path, save_path)
71 pic_2_pdf(save_file_path, save_path)
72 else:
73 pdf_2_pic(file_name, save_path)
74 pic_add_num(file_name, save_path)
75 pic_2_pdf(os.path.join(save_path, os.path.split(file_name)[1]), save_path)
76
77 if __name__ == '__main__':
78 file_name = input('输入文件完整路径,e.g:<F:\pdf\1.pdf>:')
79 save_path = input('输入生成的PDF文档保存路径,e.g:<F:\pdf>:')
80 get_num = int(input('单页PDF拷贝多份输入0,多页PDF标序列号输入1:'))
81 if get_num == 0:
82 num = int(input('输入PDF拷贝数量:'))
83 trans_pdf(file_name,save_path,get_num,num)
84 print('运行成功')
PDF转换部分函数
import tkinter as tk
from tkinter.filedialog import askopenfilename,askdirectory
from tkinter import messagebox
from tk_pdf_demo_copy import trans_pdf
#gui基础信息
window = tk.Tk()
window.title('二狗之友')
window.resizable(width=False,height=False)
window.geometry('600x95')
#frame布局
fm1 = tk.Frame(window)
fm2 = tk.Frame(window)
fm3 = tk.Frame(window)
fm1.pack(side='left',fill='y',padx=5,pady=10)
fm2.pack(side='left',fill='y',padx=5,pady=10)
fm3.pack(side='left',fill='y',padx=5,pady=10)
font = ('Arial',10) # 字体
def e1_double_callback(event):
# 双击弹出文件对话框回调 file_name
file_name = askopenfilename()
a1.set(file_name)
return a1
def e2_double_callback(event):
# 双击弹出文件对话框回调 save_path
save_path = askdirectory()
a2.set(save_path)
return a2
def options_judge():
status = True
file = e1.get()
save = e2.get()
get_num = r12.get()
num = e3.get()
try:
e33 = int(e3.get())
except ValueError:
tk.messagebox.showinfo('二狗提示', '拷贝个数请输入数字(1-1024)')
while status:
if e33 > 1024 or e33 <= 0:
tk.messagebox.showinfo('二狗提示', '拷贝个数请输入数字(1-1024)')
break
elif get_num == 1 and int(num) > 1:
tk.messagebox.showerror('错误', '选择多页PDF时拷贝个数只能为1')
break
else:
status = False
break
return file, save, get_num, int(num),status
def run_command():
file,save,get_num,num,status = options_judge()
if status == False:
trans_pdf(file,save,get_num,num)
tk.messagebox.showinfo('二狗提示', '创建成功')
#fm1
label1 = tk.Label(fm1,text='PDF路径:',height=1).pack(side='top')
label2 = tk.Label(fm1,text='保存路径:',height=1).pack(side='top')
label3 = tk.Label(fm1,text='拷贝个数:',height=1).pack(side='top')
a1 = tk.StringVar()
e1 = tk.Entry(fm2,font=font,width=38,textvariable=a1)
e1.bind('<Double-Button-1>',e1_double_callback)
e1.pack(side='top',pady=1) # file_path
a2 = tk.StringVar()
e2 = tk.Entry(fm2,font=font,width=38,textvariable=a2)
e2.bind('<Double-Button-1>',e2_double_callback)
e2.pack(side='top',pady=1) # save_path
e3 = tk.IntVar()
e3.set(1)
e3 = tk.Entry(fm2,font=font,width=38,textvariable=e3)
e3.pack(side='top',pady=1) # num
#fm3
r12 = tk.IntVar()
r12.set(0)
r1 = tk.Radiobutton(fm3,text='单页PDF',font=font,variable=r12,value=0,command=options_judge)
r1.pack(side='left')
r2 = tk.Radiobutton(fm3,text='多页PDF',font=font,variable=r12,value=1,command=options_judge)
r2.pack(side='right')
btn = tk.Button(fm3,text='提交',font=font,width=10,command=run_command).pack(side='left')
if __name__ =='__main__':
window.mainloop()
tkinter gui部分代码
1 def copy_pdf(fn,num,path): # 拷贝PDF
2 save_names = []
3 for i in range(1, num+1):
4 save_name = str(i)+'.pdf'
5 save_names.append(save_name)
6 pdf1File = open(fn, 'rb')
7 pdf1_r = PyPDF2.PdfFileReader(pdf1File)
8 for save_name in save_names:
9 pdfWriter = PyPDF2.PdfFileWriter()
10 pdfxFile = open(os.path.join(path,save_name),'wb')
11 pagObj = pdf1_r.getPage(0)
12 pdfWriter.addPage(pagObj)
13 pdfWriter.write(pdfxFile)
14 pdf1File.close()
15 return save_names, num
16
17 def pdf_2_pic(fn,path): # PDF转换成图片
18 pdf_r = PyPDF2.PdfFileReader(open(fn, 'rb'))
19 npage = pdf_r.getNumPages()
20 if not os.path.exists(path):
21 os.makedirs(path)
22 for p in range(npage):
23 im = PythonMagick.Image(fn+'['+str(p)+']')
24 outfn = '%03d.jpg' % (p)
25 outfn = os.path.join(path, outfn)
26 im.write(outfn)
27
28 def pic_add_num(fn,path): # 图片添加标记
29 for img in [item for item in os.listdir(path) if item.endswith('.jpg')]:
30 im1 = Image.open(os.path.join(path,img))
31 drawimg = ImageDraw.Draw(im1)
32 pdf_r = PyPDF2.PdfFileReader(open(fn, 'rb'))
33 npage = pdf_r.getNumPages()
34 if npage > 1:
35 num = os.path.splitext(img)[0][-3:]
36 else:
37 num = os.path.split(fn)[1].split('.')[0]
38 font = ImageFont.truetype('arial.ttf', 20)
39 drawimg.text((20,20),str(num),font=font,fill='#ff0000')
40 im1.save(os.path.join(path,img))
41
42 def pic_2_pdf(pdfFileName, inPath): # 图片转换成PDF
43 c = canvas.Canvas(pdfFileName)
44 (w, h) = A4
45 jpgs = [item for item in os.listdir(inPath) if item.lower().endswith('jpg')]
46 for infn in jpgs:
47 infn = os.path.join(inPath, infn)
48 c.setFillAlpha(1)
49 c.drawImage(infn, 0, 0, w, h)
50 c.showPage()
51 asyncio.sleep(1)
52 for file in jpgs:
53 os.remove(os.path.join(inPath, file))
54 c.sav
1 import tkinter as tk
2 from tkinter.filedialog import askopenfilename,askdirectory
3 from tkinter import messagebox
4 from tk_pdf_demo_copy import trans_pdf
5
6 #gui基础信息
7 window = tk.Tk()
8 window.title('二狗之友')
9 window.resizable(width=False,height=False)
10 window.geometry('600x95')
11
12 #frame布局
13 fm1 = tk.Frame(window)
14 fm2 = tk.Frame(window)
15 fm3 = tk.Frame(window)
16 fm1.pack(side='left',fill='y',padx=5,pady=10)
17 fm2.pack(side='left',fill='y',padx=5,pady=10)
18 fm3.pack(side='left',fill='y',padx=5,pady=10)
19
20 font = ('Arial',10) # 字体
21
22 def e1_double_callback(event):
23 # 双击弹出文件对话框回调 file_name
24 file_name = askopenfilename()
25 a1.set(file_name)
26 return a1
27
28 def e2_double_callback(event):
29 # 双击弹出文件对话框回调 save_path
30 save_path = askdirectory()
31 a2.set(save_path)
32 return a2
33
34
35 def options_judge():
36 status = True
37 file = e1.get()
38 save = e2.get()
39 get_num = r12.get()
40 num = e3.get()
41 try:
42 e33 = int(e3.get())
43 except ValueError:
44 tk.messagebox.showinfo('二狗提示', '拷贝个数请输入数字(1-1024)')
45 while status:
46 if e33 > 1024 or e33 <= 0:
47 tk.messagebox.showinfo('二狗提示', '拷贝个数请输入数字(1-1024)')
48 break
49 elif get_num == 1 and int(num) > 1:
50 tk.messagebox.showerror('错误', '选择多页PDF时拷贝个数只能为1')
51 break
52 else:
53 status = False
54 break
55 return file, save, get_num, int(num),status
56
57 def run_command():
58 file,save,get_num,num,status = options_judge()
59 if status == False:
60 trans_pdf(file,save,get_num,num)
61 tk.messagebox.showinfo('二狗提示', '创建成功')
62
63 #fm1
64 label1 = tk.Label(fm1,text='PDF路径:',height=1).pack(side='top')
65 label2 = tk.Label(fm1,text='保存路径:',height=1).pack(side='top')
66 label3 = tk.Label(fm1,text='拷贝个数:',height=1).pack(side='top')
67
68 a1 = tk.StringVar()
69 e1 = tk.Entry(fm2,font=font,width=38,textvariable=a1)
70 e1.bind('<Double-Button-1>',e1_double_callback)
71 e1.pack(side='top',pady=1) # file_path
72
73 a2 = tk.StringVar()
74 e2 = tk.Entry(fm2,font=font,width=38,textvariable=a2)
75 e2.bind('<Double-Button-1>',e2_double_callback)
76 e2.pack(side='top',pady=1) # save_path
77
78 e3 = tk.IntVar()
79 e3.set(1)
80 e3 = tk.Entry(fm2,font=font,width=38,textvariable=e3)
81 e3.pack(side='top',pady=1) # num
82
83 #fm3
84 r12 = tk.IntVar()
85 r12.set(0)
86 r1 = tk.Radiobutton(fm3,text='单页PDF',font=font,variable=r12,value=0,command=options_judge)
87 r1.pack(side='left')
88 r2 = tk.Radiobutton(fm3,text='多页PDF',font=font,variable=r12,value=1,command=options_judge)
89 r2.pack(side='right')
90 btn = tk.Button(fm3,text='提交',font=font,width=10,command=run_command).pack(side='left')
91
92 if __name__ =='__main__':
93 window.mainlo
遇到的问题
1)运行出现RunTimeError,自己PC上可以运行,依赖库装完后笔记本上运行出现的错误,思前想后就ghostscript没有安装。安装以后完美运行
2)进程已结束,退出代码-1073741819 (0xC0000005) 。这时候功能实现了,我想转换600多页的一个PDF文档时报的错,百度没有找到好的解决办法,猜测可能是占内存太大异常退出了(目前已解决,但是效率有点慢,待优化ing)
3)
,遇到这个百度很久也没解决,超出目前能力范围,希望有人以后能告诉我答案,这导致的问题是复制的PDF像素都不高4 )
https://github.com/mstamy2/PyPDF2/issues/438 ---可以参考这个
应该还遇到其他各种各样问题的,想不起来了,如有人看到这可以评论留言遇到的问题,我看看我有没有遇到
立个flag:下次一定边记录问题边写博客!!!