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转换器大作战的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简易boundbox碰撞检测
- 下一篇: CTF 大小写字母转换 try lowe