基于Python實(shí)現(xiàn)PDF批量轉(zhuǎn)化工具
一、開(kāi)發(fā)的緣由
最近,有網(wǎng)友想讓我?guī)退鲆粋€(gè)批量把png, docx, doc, pptx, ppt, xls, xlsx文件轉(zhuǎn)化為PDF格式的軟件,完全傻瓜式的操作,把文件拖進(jìn)去就進(jìn)行轉(zhuǎn)化那種,簡(jiǎn)單實(shí)用。之前,有過(guò)一個(gè)vbs的文件,可以轉(zhuǎn)docx, xlsx, pptx,但是對(duì)于圖片無(wú)能為力,為了完成這個(gè)任務(wù)還是要請(qǐng)出Python這個(gè)強(qiáng)大的利器。
二、開(kāi)發(fā)的過(guò)程

1. 為了能夠?qū)崿F(xiàn)拖動(dòng)的功能,我首先想到要設(shè)計(jì)一個(gè)UI界面,然后可以直接接受拖動(dòng)的文件。另外,因?yàn)槭桥坎僮?,需要一定的時(shí)間來(lái)完成操作,最好是可以添加一個(gè)進(jìn)度條,讓用戶知道是否已經(jīng)完成了轉(zhuǎn)化。
2. 軟件的外觀本來(lái)想著簡(jiǎn)化,但是想著得讓用戶看到轉(zhuǎn)化文件名的路徑和文件名,避免轉(zhuǎn)錯(cuò)了,同時(shí)還得可以刪除選中的條目。所以我就設(shè)計(jì)了一個(gè)listbox控件,一個(gè)刪除按鈕、一個(gè)生成文件按鈕,還有一個(gè)導(dǎo)入文件的按鈕,為的是不習(xí)慣進(jìn)行拖動(dòng)的用戶設(shè)計(jì)。
3. 由于tkinter是系統(tǒng)自帶的,所以可以使軟件更小一點(diǎn)。另外,讀取圖片用到PIL這個(gè)模塊,而其它如docx, pptx, xlsx文件的轉(zhuǎn)化則需要依靠win32com.client這個(gè)模塊。
4. 我嘗試了多種方法來(lái)執(zhí)行拖動(dòng)的功能,但是打包以后發(fā)現(xiàn)無(wú)法實(shí)現(xiàn),于時(shí)最終采用了windnd這個(gè)模塊,為了防止拖動(dòng)時(shí)程序假死,我還用了多線程的方法。
三、成品介紹
我們這個(gè)軟件最終起名為PDF批量轉(zhuǎn)化器,它是一款支持多種文件格式批量轉(zhuǎn)換為PDF格式的工具,特別適用于Word、Excel、PowerPoint、圖片文件的轉(zhuǎn)換。它提供了一個(gè)直觀的界面,允許用戶通過(guò)拖拽文件或通過(guò)文件選擇器導(dǎo)入文件,支持多線程處理,提升了文件轉(zhuǎn)換的效率。主要特點(diǎn)有:
- 多文件格式支持:支持轉(zhuǎn)換Word、Excel、PowerPoint和圖片文件到PDF格式。
- 拖拽功能:用戶可以直接將文件拖拽至程序界面,簡(jiǎn)化操作流程。
- 進(jìn)度條顯示:轉(zhuǎn)換過(guò)程中,進(jìn)度條實(shí)時(shí)顯示,用戶可以了解轉(zhuǎn)換的進(jìn)度。
- 批量處理:一次可以處理多個(gè)文件,節(jié)省時(shí)間和操作精力。
- 文件管理:提供文件導(dǎo)入、刪除等操作,幫助用戶管理文件列表。
- 后臺(tái)處理:采用多線程方式處理文件轉(zhuǎn)換,避免界面卡頓。
此外,為了增強(qiáng)用戶體驗(yàn),我們還增加了二個(gè)小功能,一是把生成的PDF文件統(tǒng)一放在一個(gè)PDF文件夾里面,另外就是如果發(fā)現(xiàn)同名PDF文件,就自動(dòng)跳過(guò)這個(gè)文件,從而避免重復(fù)操作。
四、程序源碼
為了幫助大家,特地放上這個(gè)源碼,供大家調(diào)試使用,里面有豐富的知識(shí)點(diǎn),認(rèn)真學(xué)習(xí)或許還會(huì)有意想不到的收獲。
import tkinter as tk
from tkinter import messagebox,ttk,filedialog
from PIL import Image
import os
import windnd
from threading import Thread
import win32com.client # pywin32 for Word, Excel, PPT processing
class WordProcessorApp:
def __init__(self, root):
self.root = root
self.root.title("PDF批量轉(zhuǎn)化器 V1.2 Gordon ")
self.root.attributes("-topmost", True)
windnd.hook_dropfiles(self.root,func=self.drop_files)
self.file_list = []
self.create_widgets()
os.makedirs("PDF文件", exist_ok=True)
self.path = "PDF文件"
def create_widgets(self):
self.frame = tk.Frame()
self.frame.pack()
# 使用Combobox代替Checkbutton
self.label = tk.Label(self.frame, text = "請(qǐng)把文件拖拽到本界面上,然后點(diǎn)生成文件", font=("宋體", 11), width=38)
self.label.pack(side=tk.LEFT)
self.file_listbox = tk.Listbox(self.root,width=48,font = ("宋體",11))
self.file_listbox.pack()
self.import_button = tk.Button(self.frame, text="導(dǎo)入文件",font = ("宋體",11), command=self.import_file)
self.import_button.pack(sid=tk.LEFT)
frame1 = tk.Frame()
frame1.pack()
# Progress bar
self.progress_bar = ttk.Progressbar(frame1, orient="horizontal", length=400, mode="determinate")
self.progress_bar.pack()
self.delete_button = tk.Button(frame1, text="刪除選中", font=("宋體", 11), command=self.delete_selected)
self.delete_button.pack(side=tk.LEFT,padx = 30)
self.generate_button = tk.Button(frame1, text="生成文件",font = ("宋體",11), command=self.generate_files)
self.generate_button.pack(side=tk.LEFT,padx = 30)
self.quit_button = tk.Button(frame1, text="退出程序",font = ("宋體",11), command=self.ui_quit)
self.quit_button.pack(side=tk.LEFT,padx = 30)
def ui_quit(self):
self.root.destroy()
def delete_selected(self):
selected_indices = self.file_listbox.curselection()
if not selected_indices:
messagebox.showwarning("Warning", "請(qǐng)先選擇要?jiǎng)h除的文件!")
return
for index in reversed(selected_indices):
self.file_listbox.delete(index)
del self.file_list[index]
def thread_it(self,func,*args):
self.thread1=Thread(target=func,args=args)
self.thread1.setDaemon(True)
self.thread1.start()
#---------------定義一個(gè)drop_files,然后用thread_it-------------
def drop_files(self,files):
self.thread_it(self.drop_files2,files)
#--------------找開(kāi)文件對(duì)話框的代碼--------------
def drop_files2(self,files=None):
for file_path in files:
file_path=file_path.decode("gbk")
file_path = file_path.replace('\\', '/')
if file_path not in self.file_listbox.get(0, tk.END):
# 將文件路徑添加到Listbox中
self.file_listbox.insert(tk.END, file_path)
self.file_list.append(file_path)
return
def import_file(self):
filename = filedialog.askopenfilename(filetypes=[("Word files", "*.docx")])
if filename:
self.file_list.append(filename)
self.file_listbox.insert(tk.END, filename)
def generate_files(self):
if not self.file_list:
messagebox.showerror("Error", "文件列表為空!")
return
# for filename in self.file_list:
else:
self.convert_files()
def process_file(self, file_path, convert_func, update_progress):
path_without_extension = os.path.splitext(os.path.basename(file_path))[0]
pdf_path = os.path.join(os.path.abspath(self.path), path_without_extension + ".pdf")
# 檢查目標(biāo)文件是否已經(jīng)存在
if os.path.exists(pdf_path):
print(f"文件 {pdf_path} 已經(jīng)存在,跳過(guò)轉(zhuǎn)換。")
return False # 文件已經(jīng)存在,不進(jìn)行轉(zhuǎn)換
# 如果文件不存在,繼續(xù)轉(zhuǎn)換
if convert_func(file_path, pdf_path, update_progress):
return True
return False
def convert_files(self):
files = self.file_listbox.get(0, tk.END) # 獲取列表框中的所有文件
total_files = len(files)
processed_files = 0
# 重置進(jìn)度條
self.progress_bar['maximum'] = total_files # 設(shè)置進(jìn)度條最大值
self.progress_bar['value'] = 0 # 重置進(jìn)度條當(dāng)前值為0
self.label.config(text="正在處理中...") # 更新提示標(biāo)簽
def update_progress():
nonlocal processed_files
processed_files += 1
self.progress_bar['value'] = processed_files
self.root.update_idletasks() # 更新UI
# 處理文件
excel_count = 0
word_count = 0
ppt_count = 0
img_count = 0
for file_path in files:
if file_path.lower().endswith((".xls", ".xlsx")): # Excel file
if self.process_file(file_path, self.excel_to_pdf, update_progress):
excel_count += 1
elif file_path.lower().endswith((".docx", ".doc")): # Word file
if self.process_file(file_path, self.word_to_pdf, update_progress):
word_count += 1
elif file_path.lower().endswith((".pptx", ".ppt")): # PowerPoint file
if self.process_file(file_path, self.ppt_to_pdf, update_progress):
ppt_count += 1
elif file_path.lower().endswith((".jpg", ".png")): # Image file
if self.process_file(file_path, self.img_to_pdf, update_progress):
img_count += 1
# 更新處理結(jié)果
self.label.config(text=f"轉(zhuǎn)化{excel_count}個(gè)Excel,{word_count}個(gè)Word,"
f"{ppt_count}個(gè)PPT,{img_count}個(gè)圖 ")
def excel_to_pdf(self, input_file, output_file, update_progress):
try:
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = False
wb = excel.Workbooks.Open(input_file)
wb.ExportAsFixedFormat(0, output_file)
wb.Close()
excel.Quit()
update_progress() # Update progress after conversion
return True
except Exception as e:
print(f"Error converting Excel to PDF: {e}")
return False
def word_to_pdf(self, input_file, output_file, update_progress):
try:
word = win32com.client.Dispatch("Word.Application")
doc = word.Documents.Open(input_file)
doc.SaveAs(output_file, FileFormat=17) # FileFormat=17 for PDF
doc.Close()
word.Quit()
update_progress() # Update progress after conversion
return True
except Exception as e:
print(f"Error converting Word to PDF: {e}")
return False
def ppt_to_pdf(self, input_file, output_file, update_progress):
try:
ppt = win32com.client.Dispatch("PowerPoint.Application")
ppt.Visible = False
presentation = ppt.Presentations.Open(input_file)
presentation.SaveAs(output_file, 32) # 32 for PDF format
presentation.Close()
ppt.Quit()
update_progress() # Update progress after conversion
return True
except Exception as e:
print(f"Error converting PowerPoint to PDF: {e}")
return False
def img_to_pdf(self, input_file, output_file, update_progress):
try:
img = Image.open(input_file)
img.save(output_file, "PDF", resolution=100.0)
update_progress() # Update progress after conversion
return True
except Exception as e:
print(f"Error converting image to PDF: {e}")
return False
if __name__ == "__main__":
root = tk.Tk()
app = WordProcessorApp(root)
root.mainloop()五、注意事項(xiàng)
1. 文件類型限制:僅支持特定文件類型的轉(zhuǎn)換,如:doc, docx, ppt, pptx, xls, xlsx和常見(jiàn)圖片格式png,jpg格式,其他文件類型暫不適用。
2. 軟件依賴:需要安裝pywin32和Pillow庫(kù),且轉(zhuǎn)換Word、Excel、PowerPoint等文件格式時(shí)依賴安裝Microsoft Office。
3. 路徑問(wèn)題:確保文件路徑不包含特殊字符,否則可能導(dǎo)致路徑無(wú)法識(shí)別。
4. 文件覆蓋:如果轉(zhuǎn)換后的PDF文件已存在,程序會(huì)跳過(guò)該文件以避免覆蓋。
以上就是基于Python實(shí)現(xiàn)PDF批量轉(zhuǎn)化工具的詳細(xì)內(nèi)容,更多關(guān)于Python PDF批量轉(zhuǎn)化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
3種Python 實(shí)現(xiàn)酷炫進(jìn)度條的實(shí)用方法
這篇文章主要介紹了3種Python 實(shí)現(xiàn)酷炫進(jìn)度條的實(shí)用方法,文章圍繞Python的相關(guān)資料展開(kāi)對(duì)實(shí)現(xiàn)進(jìn)度條的介紹,需要的小伙伴可以參考一下2022-04-04
python如何爬取網(wǎng)站數(shù)據(jù)并進(jìn)行數(shù)據(jù)可視化
這篇文章主要介紹了python爬取拉勾網(wǎng)數(shù)據(jù)并進(jìn)行數(shù)據(jù)可視化,爬取拉勾網(wǎng)關(guān)于python職位相關(guān)的數(shù)據(jù)信息,并將爬取的數(shù)據(jù)已csv各式存入文件,然后對(duì)csv文件相關(guān)字段的數(shù)據(jù)進(jìn)行清洗,并對(duì)數(shù)據(jù)可視化展示,包括柱狀圖展示、直方圖展示,需要的朋友可以參考下2019-07-07
python初學(xué)之用戶登錄的實(shí)現(xiàn)過(guò)程(實(shí)例講解)
下面小編就為大家分享一篇python初學(xué)之用戶登錄的實(shí)現(xiàn)過(guò)程(實(shí)例講解),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
卷積神經(jīng)網(wǎng)絡(luò)經(jīng)典模型及其改進(jìn)點(diǎn)學(xué)習(xí)匯總
這篇文章主要為大家介紹了卷積神經(jīng)網(wǎng)絡(luò)經(jīng)典模型及其改進(jìn)點(diǎn)學(xué)習(xí)匯總,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
Python控制windows系統(tǒng)音量實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了Python控制windows系統(tǒng)音量實(shí)現(xiàn)實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-01-01
一文詳解如何實(shí)現(xiàn)PyTorch模型編譯
這篇文章主要為大家介紹了如何實(shí)現(xiàn)PyTorch?模型編譯詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04

