1. 环境搭建
# python 版本 3.9.7
# 依赖包 reportlab==3.6.9,PyPdf2==1.27.3,pikepdf==3.0.8,pyinstaller==4.10
2.功能实现
2.1 建立合并文件的类
import os
import sys
from PyPDF2 import PdfFileReader,PdfFileWriter
from reportlab.pdfgen import canvas
from reportlab.lib.units import cm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import pikepdf
class pdfmerge:
def __init__(self):
self.pdfspath='' # 存放pdf文件的文件夹路径
#旋转页面
def page_rotation(self,oldpdfpath, newpdfpath,msg):
oldpdf = PdfFileReader(oldpdfpath)
pagenums = oldpdf.getNumPages()
newpdf = PdfFileWriter()
for i in range(pagenums):
page = oldpdf.getPage(i)
size = page.mediaBox
x, y = size.getUpperRight_x(),size.getUpperRight_y()
# print(size)
if x > y:
# 顺时针旋转90度 90的倍数
# page=page.rotateClockwise(90)
msg.set('提示:正在旋转{}文件的第{}页'.format(oldpdfpath,i))
page.rotateCounterClockwise(90)
newpdf.addPage(page)
with open(newpdfpath, 'wb') as f:
newpdf.write(f)
return f
#合并文件
def merge(self,pdfspath):#pdfspath 存放目标pdf的名称,路径,及命名序号
pdf_hb = PdfFileWriter()
for i in range(len(pdfspath)):
obj = PdfFileReader(pdfspath[i][1])
for j in range(obj.numPages):
page = obj.getPage(j)
pdf_hb.addPage(page)
with open('合并的文件.pdf','wb') as f:
pdf_hb.write(f)
return f
#解密pdf文件 用于处理不能编辑的pdf文件
def pdf_Crack(self,startFile):
endFile=startFile[:-4]+' '+'.pdf'
with pikepdf.open(startFile) as pdf:
pdf.save(endFile)
os.remove(startFile)
return endFile
# 插入页码 生成合并后文件的pdf水印,使用reportlab实现
def create_mark(self,pages):
file_name = 'yam.pdf'
c = canvas.Canvas(file_name)
pdfmetrics.registerFont(TTFont('yahei', resource_path('song.ttc')))
for i in range(1, pages + 1):
c.setFont('yahei', 14)
c.drawString(9.5 * cm, 1 * cm, '第{}页'.format(i))
c.showPage()
c.save()
return file_name
# 为合并后的文件每页添加水印,以实现编写页码
def add_watermark1(self,pdf_file_in, pdf_file_out):
pdf_output = PdfFileWriter()
input_stream = open(pdf_file_in, 'rb')
pdf_input = PdfFileReader(input_stream, strict=False)
# 获取PDF文件的页数
pageNum = pdf_input.getNumPages()
pdf_file_mark = self.create_mark(pageNum)
# 读入水印pdf文件
pdf_watermark = PdfFileReader(open(pdf_file_mark, 'rb'), strict=False)
# 给每一页打水印
for i in range(pageNum):
page = pdf_input.getPage(i)
page.mergePage(pdf_watermark.getPage(i))
page.compressContentStreams() # 压缩内容
pdf_output.addPage(page)
pdf_output.write(open(pdf_file_out, 'wb'))
# 获取目标文件夹下的所有pdf,返回列表,元素也为列表([pdf名称,pdf路径,序号+名称])
def getpdffiles(self):
pdfs=[]
calalog=[]
for root,dirs,files in os.walk(self.pdfspath):
calalog.append(dirs)
for f in files:
if f.endswith(('.pdf','.PDF')):
pdfs.append([f.split('.')[1],os.path.join(root,f),f])
return sorted(pdfs,key=lambda x:(x[2][:3])),calalog[0]
#生成pdf文件的目标,返回txt文本
def create_calalog(self,pdfnames):
with open('目录文件.txt', 'w') as f:
zys = 1
for i in range(len(pdfnames)):
pages = PdfFileReader(pdfnames[i][1]).getNumPages()
aa = pdfnames[i][2] + '.......' + str(zys)
f.writelines(aa)
f.write('\n')
zys = zys + pages
f.close()
2.2 界面
import tkinter as tk
import tkinter.filedialog
from pdfutils import pdfmerge
from PyPDF2 import PdfFileReader
import time
import threading
root = tk.Tk()
root.title('文件汇编小程序v2022-04')
root.geometry('600x200+{}+{}'.format(int((root.winfo_screenwidth()-600)/2),
int((root.winfo_screenheight()-200)/2)))
tk.Label(root,text='请选择文件夹:',font=('simhei',14)).place(x=5,y=15)
pEty=tk.Entry(root)
pEty.place(x=150,y=15,width=300)
cBt=tk.Button(root,text='选 择',font=('simhei',14))
cBt.place(x=480,y=10)
tk.Button(root,text='退 出',font=('simhei',14),command=root.quit).place(x=320,y=150)
rBt=tk.Button(root,text='运 行',font=('simhei',14))
rBt.place(x=180,y=150)
def cBtf():
path=tkinter.filedialog.askdirectory()
pEty.delete('0','end')
pEty.insert('0',path)
cBt['command']=cBtf
#提示语句
msg=tk.StringVar()
tk.Label(root,textvariable=msg,font=('simhei',14),fg='red').place(x=10,y=60)
msg.set('提示:')
def runing():
start=time.time()
app=pdfmerge()
path=pEty.get()
try:
app.pdfspath=path
msg.set('提示:正在对加密文件进行解密...')
pdfpaths = app.getpdffiles()[0]
for pdfpath in pdfpaths:
if PdfFileReader(pdfpath[1]).isEncrypted:
msg.set('提示:正在解密{}'.format(pdfpath[0]))
app.pdf_Crack(pdfpath[1])
msg.set('提示:已完成目标文件夹下所有加密文件的解密!')
time.sleep(1)
pdfpaths = app.getpdffiles()[0]
msg.set('提示:正在导出目标...')
app.create_calalog(pdfpaths)
msg.set('提示:目标导出完成!')
time.sleep(1)
msg.set('提示:正在合并文件...')
app.merge(pdfpaths)
msg.set('提示:合并文件完成!')
time.sleep(1)
msg.set('提示:正在调整页面方向...')
app.page_rotation('合并的文件.pdf', '合并的文件(旋转页面).pdf',msg)
msg.set('提示:页面方向调整完成!')
time.sleep(1)
msg.set('提示:正在生成页码...')
app.add_watermark1('合并的文件(旋转页面).pdf', '合并的文件(已编写页面).pdf')
endt=time.time()
msg.set('提示:文件汇编完成!总耗时:{}秒'.format(int(start-endt)))
except:
msg.set('提示:请选择正确的文件夹')
def run2():
threading.Thread(target=runing).start()
rBt['command']=run2
root.mainloop()
预览:
3. 打包
3.1 创建虚拟环境
python -m venv d:\venv
pip install 依赖库
3.2 添加静态文件
#定义函数,并将类中注册字体的相对路径使用此函数
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
3.3 生成并修改spec文件
pyi-makespec D:\202112study\pdf\app\ui.py
#修改spec
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['D:\\202112study\\pdf\\app\\ui.py'],
pathex=[],
binaries=[],
datas=[],#修改此处,改为datas=[('song.ttc','.')]
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='ui',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='ui')
3.4 生成exe
pyinstaller -F D:\202112study\pdf\app\ui.spec