本文主要是介绍pyhon制作word、excel、ppt转pdf转换器大作战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
很久很久没有写博客了。倒不是技术退步了,相反,这些年我从javascript开始,把主流语言基本都摸了个遍。然而编程的很多东西,用进废退,只要很短的一段时间不用就会遗忘很多。所以有些东西忙的时候没有及时记下来,一段时间后就写不出来了。
记得很久很久以前,大概是2011年左右的暑假,我接触到了gamemaker,那时我很想做出属于自己的游戏。于是我就是从那个时候开始学习编程。由于我并不是读计算机类的本科,所以一开始入门对我来说是很困难。甚至于在大四的时候,由于沉迷于学习unity导致参加各种社招都失败,一度有轻生的念头。以前总想着也许我做出一个很好玩的游戏除了自娱自乐之外更重要的是还可以哄自己喜欢的师妹开心,最后换来的不过是那个师妹的一句“不是我说你自作多情,你凭什么觉得我会喜欢你?”而已。
如今我已经早就不再从事编程的工作了,所以也断更了很久很久。倒不是我就不再热爱游戏,也谈不上是生活所迫,只是说编程过度伤身而我的身体受不了不得不放弃而已。我觉得这代人既是幸运的,也是悲哀的。幸运的是我们生活在一个不愁吃喝,科技进步的黄金年代,只要自己愿意努力就可以学有所成、学有所获。悲哀的则是我们的身体跟不上我们的科技发展的步伐。有时候我在想,如果人体不怕熬夜,不会脱发,不怕各种各样因为不良生活习惯导致的身体问题,不会因为身体衰老导致记忆力和理解力下降,拥有数百年的寿命供我们研究学习,那该有多好多好。那才是真正的由人类的必然王国飞跃到自由王国的白金时代。可惜我们不是出生在那样的时代,我们也只能受制于生理的紧箍咒过日子了。
这次写一个word转pdf的转换器,是为了一个姑娘。早就过了三十而立的我,依旧是异性绝缘体。不是什么其他原因,就是外貌问题而已。单位有个姑娘叫我帮她看看电脑问题,她说她需要把word文档和pdf合并成新的pdf文档,也就是要把word转pdf,再把多个pdf合并。网上的一些工具都不太好用,所以叫我能不能帮她解决。这姑娘应该说是我长这么大看过的第二好看的姑娘,属于梦中情人的那种。我之前晚上找她的时候,不管是七点还是十一点她都是固定地回复“我要去洗澡了”,我当然看得出她不过是利用我帮她解决问题而已,是不可能真的喜欢我的。然而我还是愿意这么一做,倒不是说什么没人格,而是对我来说,有个姑娘愿意对我笑笑都早已经是奢望了,更何况还是自己心仪的女孩呢?
如果我能回到以前没有学习编程的时候,我肯定会放弃这些曲折的弯路,转而去研究诸如绘画音乐之类的艺术。因为研究程序多了容易一根筋,这是最不讨女孩子喜欢的。而且,现实是长得丑的人是不适合去学习编程的,长得丑本身就有点难救了,要是又丑又秃又木,那么就注孤生了。以中国的性别比例来看,未来注孤生的男性肯定多如牛毛,这大概是人类历史上为数不多见的大规模社会淘汰了——往大了说,很多丑的都被淘汰了,国人的平均长相是会提高的嘛。
好了,不扯了,开始说正经内容了:
首先自然是安装python了。我这次做了两个版本,一个是xp的,一个是win7的。目前xp上面最高支持3.4.4。先说说在win7上面怎么搞,我用的是win7 64位的电脑。
下载python3.7:https://www.python.org/downloads/release/python-370/
下载里面的Windows x86-64 executable installer,如果是32位就是Windows x86 executable installer,安装的时候注意尽量安装不要有中文路径,我直接安装在C盘。python3会自带pip等工具,注意这些比较重要,现在的安装包都是默认会装上去的,不要自己随便去掉它们。
安装完毕之后是添加环境变量,这个比较简单,右击我的电脑 → 属性 → 高级系统设置 → 高级 → 环境变量,在下方的系统变量那里的path里面添加上python目录就行了,我的是C:\python37。
然后是安装一些依赖。打开C:\python37\Scripts,在这个目录按住shift然后右击就可以“在此处打开命令窗口”
然后就是pip install pywin32,等它安装完毕。
然后是pip install comtypes
然后pip install PyPDF2
然后就是安装tkinter的扩展tkinterDnD了。为什么用tkinter呢,因为够简单啊,如果只是写小东西的话尽量不要搞太复杂的UI,什么PyQt之类的,搞小程序还是算了吧。那这个tkinterDnD又是什么鬼?是这样,因为tkinter太过简单,连拖拽文件这种功能都实现不了,于是就只能使用外部扩展了。其实有一个叫windnd的东西,但是bug多,不好用,还是算了。dnd就是drag and drop的缩写,英文就是“拖和放”的意思。
下面插一张本次程序的实现图,由于给妹子用的肯定是傻瓜式的软件,所以就这样了。肯定有人注意到下面有“上移”和“下移”的按钮,直接通过拖拽在白框里面调整待合并的office或者pdf文件不就可以了吗,何必多此一举?是这样,因为tkinter比较弱鸡,这种上下拖拽移位看似简单的功能并不好实现。类似的功能换到html和javascript上面那就是so easy的事啊。(所以以后如果再有什么其他需要,我肯定用golang和gowalk了,只不过是因为贪图python的便捷,同时又因为版本问题用不了aardio才出此下策而已。)因为给妹子用的东西永远是越直观越简单越好,所以我就不添加设定合并后文件路径的功能了,直接把合并文件放到桌面去就好了。
tkdnd2.8 https://sourceforge.net/projects/tkdnd/
TkinterDnD2 http://sourceforge.net/projects/tkinterdnd/files/
sourceforge上面有这两个东西,有时候需要科学上网,实在不行的话就用我上传的好了。注意,tkdnd2.8有一个是64位的版本,如果系统是64位的请用64位的版本。
下载完毕之后是解压,然后把tkdnd2.8文件夹复制到python安装位置文件夹下面的tcl文件夹里面去,把TkinterDnD2-0.3里面的TkinterDnD文件夹复制到python安装位置文件夹的Lib文件夹里面去。(TkinterDnD2-0.3里面有几个demo可供学习,请读者自己看)
该安装的安装好了,接着就是撸代码了,我这里就直接把代码贴出来了:
# -*- coding: utf-8 -*-import os
import platform
import time
import comtypes.client
import win32com.client
from TkinterDnD2 import *
import tkinter.messagebox as Messagebox
try:from Tkinter import *from ScrolledText import ScrolledText
except ImportError:from tkinter import *from tkinter.scrolledtext import ScrolledTextfrom PyPDF2 import PdfFileReader, PdfFileWriterimport winreg
def get_desktop():key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,r'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders')return winreg.QueryValueEx(key, "Desktop")[0]def moveup():if len(listbox.curselection()) and listbox.curselection()[0]>0:pos = listbox.curselection()[0]text = listbox.get(pos)listbox.delete(pos)listbox.insert(pos-1,text)listbox.selection_clear("end")listbox.selection_set(pos-1)def movedown():if len(listbox.curselection()) and listbox.curselection()[0]<listbox.size()-1:pos = listbox.curselection()[0]text = listbox.get(pos)listbox.delete(pos)listbox.insert(pos+1,text)listbox.selection_clear("end")listbox.selection_set(pos+1)def convert():allpdf = []waitfordelete = []for p in range(listbox.size()):tmp = listbox.get(p)if str.endswith(tmp,".pdf") or str.endswith(tmp, ".PDF"):allpdf.append(tmp)elif str.endswith(tmp,".doc") or str.endswith(tmp, ".docx") or str.endswith(tmp, ".wps") or str.endswith(tmp,".DOC") or str.endswith(tmp, ".DOCX") or str.endswith(tmp, ".WPS"):# word转化为pdfword = win32com.client.DispatchEx("Word.Application")#word = comtypes.client.CreateObject("Word.Application")word.Visible = 0newpdf = word.Documents.Open(tmp)newpdf.SaveAs(tmp+".pdf", FileFormat=17)newpdf.Close()#word.quit()word.Quit()allpdf.append(tmp+".pdf")waitfordelete.append(tmp+".pdf")elif str.endswith(tmp,".ppt") or str.endswith(tmp, ".pptx") or str.endswith(tmp,".PPT") or str.endswith(tmp, ".PPTX"):# ppt转化为pdfppt = win32com.client.DispatchEx("Powerpoint.Application")#ppt = comtypes.client.CreateObject("Powerpoint.Application")ppt.Visible = 1 #ppt在转换的时候必须可视,不然会异常,原因不明newpdf = ppt.Presentations.Open(tmp)newpdf.SaveAs(tmp+".pdf", FileFormat=32)newpdf.Close()#ppt.quit()ppt.Quit()allpdf.append(tmp+".pdf")waitfordelete.append(tmp+".pdf")elif str.endswith(tmp,".xls") or str.endswith(tmp, ".xlsx") or str.endswith(tmp,".XLS") or str.endswith(tmp, ".XLSX"):# excel转化为pdf#excel = comtypes.client.CreateObject("Excel.Application")excel=win32com.client.DispatchEx("Excel.Application")excel.Visible = 0books = excel.Workbooks.Open(tmp)books.ExportAsFixedFormat(0, tmp+".pdf",1,0)books.Close()excel.Quit()allpdf.append(tmp+".pdf")waitfordelete.append(tmp+".pdf")else:pass#获取文本框里面的文件名outfile = en2.get()if not str.endswith(outfile,".pdf") and not str.endswith(outfile,".PDF"):outfile += ".pdf"outdir = get_desktop()output = PdfFileWriter()outputPages = 0fuckinput = []if len(allpdf):for pdf_file in allpdf:#print("路径:%s"%pdf_file)# 读取源PDF文件inputopener = open(pdf_file, "rb")input = PdfFileReader(inputopener)fuckinput.append(inputopener)# 获得源PDF文件中页面总数pageCount = input.getNumPages()outputPages += pageCount#print("页数:%d"%pageCount)# 分别将page添加到输出output中for iPage in range(pageCount):output.addPage(input.getPage(iPage))#print("合并后的总页数:%d."%outputPages)# 写入到目标PDF文件outputStream = open(os.path.join(outdir, outfile), "wb")output.write(outputStream)outputStream.close()for fuck in fuckinput:fuck.close()for k in waitfordelete:#print(k)os.remove(k) #将所有非pdf格式的office文件临时生成的pdf缓存文件删去Messagebox.showinfo('成功通知','合并完成!')else:Messagebox.showinfo('失败通知','没有可以合并的PDF文件!')def deleteline():listbox.delete(ACTIVE)root = TkinterDnD.Tk()
root.withdraw()
root.resizable(width=False, height=False)
root.title('PDF文件转换与合并工具 for xc')
#xc就是我喜欢的妹子的名字拼音首字母缩写root.grid_rowconfigure(1, weight=1, minsize=300,)
root.grid_columnconfigure(0, weight=1, minsize=500)Label(root, text='请把想要合并的word、excel、ppt、pdf文档拖拽到下方:').grid(row=0, column=0, padx=10, pady=5)
buttonbox = Frame(root)
buttonbox.grid(row=3, column=0, columnspan=2, pady=5)
Button(buttonbox, text='上移选中的行', command=moveup).pack(side=LEFT, padx=5)
Button(buttonbox, text='下移选中的行', command=movedown).pack(side=LEFT, padx=5)
Button(buttonbox, text='删除选中的行', command=deleteline).pack(side=LEFT, padx=5)
Button(buttonbox, text='开始转换', command=convert).pack(side=LEFT, padx=5)
Button(buttonbox, text='退出', command=root.quit).pack(side=LEFT, padx=5)listbox = Listbox(root, name='dnd_demo_listbox',selectmode='BROWSE', width=1, height=1)
listbox.grid(row=1, column=0, padx=30, pady=30, sticky='news')
#listbox.insert(END, os.path.abspath(__file__))labelframe = Frame(root)
labelframe.grid(row=2, column=0, columnspan=2, pady=5)
en1 = Entry(labelframe,bd=0,width=12,fg="#ff0000")
en1.pack(side=LEFT, padx=5)
en1.insert(0,"合并后文件名:")
en1.config(state="disabled")
en2 = Entry(labelframe)
en2.pack(side=LEFT, padx=5)
en2.insert(0,"最新合并文件")# make the Label a drop target:def drop_enter(event):event.widget.focus_force()#print('Entering %s' % event.widget)return event.actiondef drop_position(event):#print('Position: x %d, y %d' %(event.x_root, event.y_root))return event.actiondef drop_leave(event):#print('Leaving %s' % event.widget)return event.actiondef drop(event):if event.data:#print('Dropped data:\n', event.data)if event.widget == listbox:files = listbox.tk.splitlist(event.data)for f in files:if os.path.exists(f):dr = Truefor p in range(listbox.size()):if f == listbox.get(p):dr = Falsebreakif dr:#print('Dropped file: "%s"' % f)listbox.insert('end', f)else:print('Not dropping file "%s": file does not exist.' % f)elif event.widget == text:# calculate the mouse pointer's text indexbd = text['bd'] + text['highlightthickness']x = event.x_root - text.winfo_rootx() - bdy = event.y_root - text.winfo_rooty() - bdindex = text.index('@%d,%d' % (x,y))text.insert(index, event.data)else:print('Error: reported event.widget not known')return event.actionlistbox.drop_target_register(DND_FILES, DND_TEXT)
listbox.dnd_bind('<<DropEnter>>', drop_enter)
listbox.dnd_bind('<<DropPosition>>', drop_position)
listbox.dnd_bind('<<DropLeave>>', drop_leave)
listbox.dnd_bind('<<Drop>>', drop)# make the Label a drag source:def drag_init(event):#data = listbox['text']#return (COPY, DND_TEXT, data)passdef drag_end(event):passlistbox.drag_source_register(DND_TEXT)
listbox.dnd_bind('<<DragInitCmd>>', drag_init)
listbox.dnd_bind('<<DragEndCmd>>', drag_end)root.update()
sw = root.winfo_screenwidth() #tkinter自带的获取屏幕宽度
sh = root.winfo_screenheight()#获取屏幕高度
ww = root.winfo_width()#获取程序窗口宽度
wh = root.winfo_height()#获取程序窗口高度,注意,在调用获取程序窗口宽高之前要先刷新,即调用root.update(),否则得到的是初始值,即0,0x = (sw-ww)/2
y = (sh-wh)/2
root.geometry("%dx%d+%d+%d" %(ww,wh,x,y))
root.iconbitmap(os.getcwd()+"\\xc.ico")
root.update_idletasks()
root.deiconify()
root.mainloop()
代码里面最后面的root.iconbitmap(os.getcwd()+"\\xc.ico")是用来添加图标的,我把图标放在了和py文件同目录位置,图标文件可以自己找,也可以用Photoshop处理png格式之后再用网上的在线转换器进行转换。(xc是妹子姓名拼音首字母)
因为妹子很喜欢周杰伦,所以我就准备做个周杰伦的图标,当然,真人肯定是不行的,因为图标毕竟太小了,所以我就在网上找了一张q版图片:
我觉得第二个不错,就用ps把第二个处理成png:
然后就是在线转ico:http://ico.duduxuexi.com/ (这类网站很多,随便找一个就好)
写完了自然是要打包了,我用的是pyinstaller,直接pip install pyintaller安装的pyinstaller版本是有问题的,会导致各种bug,所以这里我要用的是:
pip install https://github.com/pyinstaller/pyinstaller/archive/develop.tar.gz
安装完成之后就是用pyinstaller来打包了。
我用的指令是这个,每个断开的地方都是一个空格的位置,注意是一个。
pyinstaller --add-data C:\python37\tcl\tkdnd2.8;tkdnd -w -F -i C:\Users\Acer\Desktop\xcproject\xc.ico C:\Users\Acer\Desktop\xcproject\xc.py
这里解释一下,如果直接写pyinstaller -F xxx.py就是打包指定路径的.py文件,加上-w就是打包的时候不要出现console,就是你们说的那个黑黑的控制台。在-F和xxx.py中间加上-i xxx.ico就是指定你打包后的图标的位置。因为tkdnd2.8是手工放进去的,有一些电脑的pyinstaller会识别不到这个module,导致打包失败,所以在-w之前要加上 --add-data xxx\tcl\tkdnd2.8;tkdnd 注意这里的单词add前面是两个减号而不是一个,而后面xxx\xxx\tkdnd2.8是一个路径,路径后面用英文的分号隔开,后面即是包名tkdnd,注意不要弄成中文的分号。
打包完毕之后要把刚刚的ico放在exe同个文件夹里面,因为如果不放进去的话,语句root.iconbitmap(os.getcwd()+"\\xc.ico")读取的时候会读取不到。肯定会有人说为什么还要放这个,刚刚不是已经指定路径打包了吗?是这样,刚刚pyinstaller指定路径打包进去的是exe显示在桌面上的图标,而我的代码指定的则是程序UI界面上的图标和任务栏上的图标,我截个图说明一下吧:
直接把一个exe和ico一起发给妹子肯定是不行的,到时候妹子肯定会问为什么多出一个。所以需要在网上找一些文件打包器打包成一个单独的exe,我用的是http://www.pc0359.cn/downinfo/91554.html ,如果以后链接失效了就到我上传的文件里面找吧。
一切就绪,接着就是测试了。win7 64位的程序在同样的win7 64位上面运行正常,未在win8、win10上面测试,不清楚怎样,在xp上面自然是无法运行的。因为这个程序需要调用到系统装的office,所以如果一个电脑同时装了好几个版本的office就容易运行错误。而且office2003也不能用于转换docx、pptx等高版本,即使是安装了07兼容包也一样。而且但凡是安装了任何绿色版office的一般都会运行失败,使用office365也容易出问题。最容易处理的方法就是把所有office卸载干净(网上有office卸载清理工具,可以卸载得比较干净),然后安装wps,安装wps之后一般不会出问题。而且word文档还有一种wps格式,安装之后同样可以将这种格式转换为pdf。
接下来说说在xp上面怎么搞。肯定有人会跳出来说都什么年代了谁还用这些破玩意儿。我只能说兄dei你还是too young啊, sometimes naive,很多公司和企业、机关单位因为种种原因都会保留他们很多落后的系统,所以在天朝,目前xp还是相当普及的。在xp上面只能安装到python3.4.4,https://www.python.org/downloads/release/python-344/
安装完之后以类似的方法设置路径,然后pip安装pywin32 comtypes 和PyPDF2,不过因为高版本的pywin32没办法在低版本的python3.4和xp电脑上用,所以这个时候就不能直接通过pip来安装pywin32了,而是去下载pywin32-219.win32-py3.4.exe,这个文件在CSDN上面就有得下载。
xp上面的pyinstaller也不能用高版本的,所以是:pip install https://github.com/pyinstaller/pyinstaller/releases/download/v3.5/PyInstaller-3.5.tar.gz
如果觉得pip太慢,就用迅雷下载下来手动安装吧,如何手动安装python的包,百度一下就会了。
其他操作和上面win7的类似,就不再重复了。不过需要注意的是,pyinstaller里面的任何路径的名称都不能含有空格隔开,不然会导致识别错误。我一开始在一台xp电脑上把要打包的东西放在桌面,然后发现一直打包失败,原来是因为xp的桌面放在一个叫做Document and Settings的文件夹里面,这个地方有两个空格隔开,别瞎折腾了,肯定打包不过的,换个路径就好了。
在程序里面,调用windows的word或者excel、powerpoint有两种方法,一种是使用pywin32附带的win32com,另一种是使用comtypes,注意如果是用win32com的话,word.Quit()里面的quit首字母是大写的,而如果是用comtypes的话则必须是小写的。其实这两个没有太大的区别,在win7上面都正常,但是到了xp上面comtypes.client.CreatObject语句经常抽风,换成win32com.clinet.DispatchEx就没有这个问题。
word = win32com.client.DispatchEx("Word.Application")
#word = comtypes.client.CreateObject("Word.Application")
最后是处理ppt里面有句 ppt.Visible = 1 ,ppt转换成pdf需要在可见的情况下才可以转,比较麻烦,不能像word和excel一样不需要打开就可以在后台转换,具体原因不明确,我在外网的stackoverflow上面也查不到什么回答,只能作罢。
由于xp的版本也可以在win7 32位系统上面使用,所以我就不再另行装虚拟机去弄一个win7 32位的版本了,有兴趣的朋友可以自行尝试。
到此为止,程序算是搞定了。如果读者参考我的这篇东西写东西出现了一些问题,那么请先自己百度谷歌吧,我写这个也没有问什么人,碰到问题都是自己想自己查搞定,只有自己折腾才能快速提高嘛,而且说实话我现在很忙,很少上csdn了,有时候实在没时间帮其他人解答问题。
最后的最后,我把程序给妹子之后,妹子只是说了一句“好棒呀谢谢你哈”,然后就又说去洗澡了。第二天,我看到她的朋友圈发的是某酒店的图片,一切都明白了。我默默的点开手机,删掉了她的全部联系方式。
再见了xc。相信我这次不需要像大学那样伤心两年,只需要伤心两个月就会好的。我要继续备考我的司法考试了。
这篇关于pyhon制作word、excel、ppt转pdf转换器大作战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!