00 写在前面
又到了新的一期文章更新之时,各位大大久等了!初次看到这期文章标题的朋友可能现在正在疑惑,上一期小编不是说这一期会介绍Python中的字典和集合对象吗,怎么突然间就跳到了PDF裁剪方面呢?正如上一期所说的,本来小编这一期准备着重介绍一下字典和集合对象方面的一些知识,但是今天在办公室突然间听到了同事的求助问题:“有没有PDF文件裁剪软件,可以对一份PDF文件进行裁剪,进而只保留其中的某几页”?在这一问题抛出之后立马就有同事回应存在相关的软件可以做到这个,听到这这个回答后,小编脑海中不由得就闪现出一个想法,就是是否可以采用Python程序去实现这一裁剪功能呢?要知道小编的性格就是能用正版绝不使用盗版或者破解版(这里纯属扯淡,至少小编目前正在用于写文章的电脑的操作程序就不是正版的),所以小编就抑制不住这种想法开始去查找一些资料,看能不能实现这些功能。在参考了一些资料之后,小编发现只有通过几个Python库以及少量的代码便可以完美地实现这一功能,因此小编在激动过后,准备把这一程序展示给各位朋友,希望这一功能能够在工作中帮到你,毕竟大家平时接触最多的一类文件可能就是PDF文件呢。
本来小编准备直接通过python程序+命令行的方式去实现PDF裁剪,但是在考虑到很多朋友对于命令行操作与Python程序的相对不熟悉,以及众看官对于图形操作界面的情有独钟,因此,小编最终决定将分割程序包含在创建的App中,以便于大家直接通过鼠标进行操作,这就是本期文章最终定名为此的原因。好了,让我们闲话少叙,下面正式进入主题。
01 准备工作
既然本文的目的是为了创建一个用于PDF分割的App,那么很明显,实现的步骤至少要包含两个环节:其一,实现PDF文件的裁剪分割;其二,将这种功能嵌入进App之中。所以,小编的工作就是完成两大任务,创建Python程序实现PDF裁剪以及使用Python创建一个图形交互界面(GUI)。在参考了一些资料之后,小编发现Python的第三方库PyPDF2是一个能够被用来裁剪PDF的很好的辅助库,因此本文也将使用PyPDF2来进行PDF文件的裁剪。而对于Python中的GUI库,目前存在相当多的相关库,像Qt,Tkinter,wxWindows,Gooey等,这些库都能够实现制作App的目的,但是在考虑到安装的简便以及操作的简便之后,小编最终决定选择一个最近被新开发出来的第三方库appJar。
这里有必要着重地介绍一下appJar这个第三方的App开发库,是由一位老师为了方便学生进行程序书写以及程序功能展示而特意开发的,每次看到这里,都觉得为什麼都是别人家的老师呀,如果小编当年有一位这样的老师,小编现在说不定就成为了利纳斯·特沃斯了(科普一下,利纳斯·特沃斯是Linux操作系统之父,著名的Git分布式文件管理系统之父,虽然其至今尚未有孩子,是小编最崇拜的神人)。
既然现在已经了解到了准备进行开发的工具,那么接下来自然需要将这些工具安装在你的Python中,还是那句话,实现这些安装仅仅需要两条语句:
pip install PyPDDF2 pip install appJar
现在你已经具备了所有的工具了,下面让我们开始大显身手吧!
02 使用PyPDF2裁剪PDF文件
首先导入PyPDF库中的PdfFileWriter和PdfFileReader两个函数,从而使得下面可以方便进行PDF文件的读些操作:
from PyPDF2 import PdfFileWriter,PdfFileReaderinfile = "Input.pdf"outfile = "Output.pdf"page_range = "1-2,6"
第一句语句导入了需要的函数,第二句语句定义了需要读取的文件,第三句语句定义了输出文件名,第四局语句定义了需要读取的PDF文件页码范围,除了第一句,其余各句大家可以自行进行定义,只要确保上下变量一直即可,为了方便,笔者这里就简单地这样定义了。接下来,便可以采用上面导入的两个函数进行PDF文件的读写:
input_pdf = PdfFileReader(open(infile, "rb"))output_file = open(outfile, "wb")
第一句语句读取了了上文定义的infile文件,并对其赋予了可读权限,同时将其命名为input_pdf,第二条语句是打开了输出文件,并予以可写权限。这里所读取的都是整个文件,然而很多时候我们仅仅需要读取部分页码的文件,这就是是为什麼上文需要定义页码,切记Python中的所以顺序是从0开始的,所以需要对原页码变量进行一下微调:
page_ranges = (x.split("-") for x in page_range.split(","))range_list = [i for r in page_ranges for i in range(int(r[0]), int(r[-1]) + 1)]
第一条语句将原页码变量拆分成了列表,毕竟电脑可不是人,它只能介绍确定的东西,你和它说我要1-2页的话,它只会骂你你神经病;第二条语句将是将列表中的列表进一步拆分,进而形成非嵌套列表,以便Python读取。下面就是很简单的逻辑了,就是美读取一页,就将其写入到输出文件中,具体操作如下:
for p in range_list: PdfFileWriter.addPage(input_pdf.getPage(p - 1))PdfFileWriter.write(output_file)
就是这么简单,你现在已经完成了PDF文件的拆分,是不是很简单,整个过程最多也就是8条语句。然而对于图形操作爱好的你们,是不会喜欢这种使用命令行操作的方式的,所以接下来小编就开始完成GUI的创建。首先一睹为快,让大家先看一下笔者最后所创建的PDF裁剪App的面貌。
03 appJar下GUI的创建
使用appJar创建一个GUI App那可以说是相当简单的,最少两条语句就可以完成GUI的创建,但是,谁让小编是一个美学爱好者呢,还是要让GUI界面看起来不至于太糟糕了嘛,代码如下:
from appJar import gui app = gui("PDF Split",useTtk=True)app.setTtkTheme("default")app.setSize(500, 200)
这样就生成了一个GUI界面,其中第一条语句是导入相关的函数;第二条语句是创建了一个GUI界面并且定义了它的名字和使用风格;第三条语句是将界面的主题设置为Ttk的默认主题,更多主题可以使用app.getTtkThemes()获得;第四句是设置了界面的大小。当然这里所生成了界面仅仅是一个静态的死界面,下面就是要通过向其中填充内容从而使得界面完善和交互起来。
app.addLabel("请选择你要裁剪的PDF文件")app.addFileEntry("Input_File")app.addLabel("文件保存路径")app.addDirectoryEntry("Output_Directory")app.addLabel("输出文件名")app.addEntry("Output_name")app.addLabel("页码范围: 1,3,4-10")app.addEntry("Page_Ranges")app.addButtons(["Start", "Exit"],press)
第1-2句创建了一个文件输入控件,3-4句定义了一个文件输出路径选择控件;5-6句定义了一个输出文件名定义控件;7-8两句定义了一个页码选择控件,其中页码选择控件的1,3,4-10是说明了一种选取规则,你可以按照这种方式进行单页以及多页的选择;最后一句是定义了两个开始和退出两个命令控件,对于任何习惯图形操作的朋友来说这点应该不会有任何疑问。同时注意到最后一条语句中有一个press,这是一个自定义的函数,用来确保命令控件的行为,定义为:
def press(button): if button == "Process": src_file = app.getEntry("Input_File") dest_dir = app.getEntry("Output_Directory") page_range = app.getEntry("Page_Ranges") out_file = app.getEntry("Output_name") errors, error_msg = date_inputs(src_file, dest_dir, page_range, out_file) if errors: app.errorBox("Error", "".join(error_msg), parent=None) else: split_pages(src_file, page_range, Path(dest_dir, out_file)) else: app.stop()
这个函数的定义中,很多语句笔者在前面已经介绍过,这里重点强调一下函数定义中的data_inputs()函数与split_pages()函数,前者是用来响应你对于输入输出文件框的操作,后者是用来分割PDF文件的,正如在第三部分中讲到的那样。两个函数的具体定义为:
def date_inputs(input_file, output_dir, range, file_name): errors = False error_msgs = [] if Path(input_file).suffix.upper() != ".PDF": errors = True error_msgs.append("Please select a PDF input file") if len(range)
def split_pages(input_file, page_range, out_file): output = PdfFileWriter() input_pdf = PdfFileReader(open(input_file, "rb")) output_file = open(out_file, "wb") # https://stackoverflow.com/questions/5704931/parse-string-of-integer-sets-with-intervals-to-list page_ranges = (x.split("-") for x in page_range.split(",")) range_list = [i for r in page_ranges for i in range(int(r[0]), int(r[-1]) + 1)] for p in range_list: # Need to subtract 1 because pages are 0 indexed try: output.addPage(input_pdf.getPage(p - 1)) except IndexError: # Alert the user and stop adding pages app.infoBox("Info", "Range exceeded number of pages in input.File will still be saved.") break output.write(output_file) if(app.questionBox("File Save", "Output PDF saved. Do you want to quit?")): app.stop()
一旦这些都准备好,那么你的GUI界面已经构建后了,不同于初始的静态界面,这些函数的加入以及控件的加入,使得现在的界面已经完全成了一个交互式的可行性界面,通过运行app.go()便会弹出GUI界面,你现在可以通过这个界面完成PDF文件的裁剪了。最后,笔者将完整的代码书写如下:
from appJar import guifrom PyPDF2 import PdfFileWriter, PdfFileReaderfrom pathlib import Pathdef split_pages(input_file, page_range, out_file): input_pdf = PdfFileReader(open(input_file, "rb")) output_file = open(out_file, "wb") page_ranges = (x.split("-") for x in page_range.split(",")) range_list = [i for r in page_ranges for i in range(int(r[0]), int(r[-1]) + 1)] for p in range_list: try: PdfFileWriter.addPage(input_pdf.getPage(p - 1)) except IndexError: app.infoBox("Info", "Range exceeded number of pages in input.File will still be saved.") break PdfFileWriter.write(output_file) if(app.questionBox("File Save", "Output PDF saved. Do you want to quit?")): app.stop() def date_inputs(input_file, output_dir, range, file_name): errors = False error_msgs = [] if Path(input_file).suffix.upper() != ".PDF": errors = True error_msgs.append("Please select a PDF input file") if len(range)
至此,笔者已经完成了对于PDF裁剪App的创建工作,诸位可以参照相应的代码慢慢熟悉然后更加个性化地创建你自己的App。这一期文章就写到这里吧,下一期文章中,笔者将完成这一期本该完成的承诺,继续讲解Python的基础知识——字典和集合,敬请期待!
PS:本文更加适合在电脑上阅读,手机上阅读会存在代码阅读不便现象。
end
领取专属 10元无门槛券
私享最新 技术干货