自制Python小工具将HEIC转PNG
CodeKpy的博客-使用 HEIC 转换为 PNG 工具
文末附有全部代码
本文将教你如何使用 Python 和 Tkinter 创建一个 HEIC (High Efficiency Image Coding) 到 PNG 格式的转换器。这个应用不仅支持批量转换 HEIC 文件,还支持通过双击文件来进行单独转换。跟随这个教程,你将学会如何使用 Tkinter 构建一个简单的图形用户界面、选择文件、展示文件列表,并通过后台线程来处理转换任务。
前提条件
1.Python 3.x
2.heic2png Python 库(用于 HEIC 转 PNG 格式转换)
3.Tkinter(用于构建图形用户界面)
安装依赖
首先,需要安装 heic2png 库。运行以下命令来安装:
pip install heic2png
Tkinter 通常会随 Python 一起安装。如果没有安装,可以参考相关文档进行安装。
步骤 1:创建应用界面
4.导入必要的库
import tkinter as tk
from tkinter import filedialog, messagebox
from heic2png import HEIC2PNG
import os
import threading
5.创建应用类
首先,创建一个 HEICConverterApp 类,并设置窗口标题、大小、文件路径和文件列表。
class HEICConverterApp:
def __init__(self, root):
self.root = root
self.root.title("HEIC to PNG 转换器")
self.root.geometry("600x500")
self.filepath = ""
self.files = []
6.设置菜单栏和菜单选项
添加菜单项让用户可以选择文件夹或单个文件。
menubar = tk.Menu(root)
root.config(menu=menubar)
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="文件", menu=file_menu)
file_menu.add_command(label="选择文件夹", command=self.select_folder)
file_menu.add_command(label="选择文件", command=self.select_file)
7.创建文件列表框
在窗口中添加一个列表框,用来显示选中的 HEIC 文件。
self.file_listbox = tk.Listbox(root, selectmode=tk.MULTIPLE, width=80, height=20)
self.file_listbox.pack(pady=20)
8.创建按钮
添加“批量转换”和“转换”按钮来触发转换操作。
button_frame = tk.Frame(root)
button_frame.pack(pady=10)
batch_convert_btn = tk.Button(button_frame, text="批量转换", command=self.batch_convert)
batch_convert_btn.pack(side=tk.LEFT, padx=5)
convert_btn = tk.Button(button_frame, text="转换", command=self.convert)
convert_btn.pack(side=tk.LEFT, padx=5)
步骤 2:实现文件选择和显示功能
9.选择文件夹
用户选择文件夹后,程序会列出所有 HEIC 文件。
def select_folder(self):
self.filepath = filedialog.askdirectory()
if not self.filepath:
return
self.files = [f for f in os.listdir(self.filepath) if f.lower().endswith(".heic")]
self.update_file_listbox()
10.选择单个文件
允许用户选择单个 HEIC 文件,并更新文件列表框。
def select_file(self):
file = filedialog.askopenfilename(filetypes=[("HEIC files", "*.HEIC")])
if file:
self.files = [os.path.basename(file)]
self.update_file_listbox()
11.更新文件列表框
更新列表框,显示当前选中的文件。
def update_file_listbox(self):
self.file_listbox.delete(0, tk.END)
for file in self.files:
self.file_listbox.insert(tk.END, file)
步骤 3:实现转换功能
12.批量转换功能
当用户选择文件夹后,点击“批量转换”按钮会启动一个新线程,处理所有 HEIC 文件的转换。
def batch_convert(self):
if not self.filepath:
messagebox.showerror("错误", "请先选择一个文件夹。")
return
thread = threading.Thread(target=self._batch_convert)
thread.start()
def _batch_convert(self):
for file in self.files:
fullpath = os.path.join(self.filepath, file)
heic_img = HEIC2PNG(fullpath)
png_path = fullpath.lower().replace(".heic", ".png")
heic_img.save(png_path)
self.root.after(0, lambda: messagebox.showinfo("成功", "转换已完成。"))
13.单个文件转换
选中文件后,点击“转换”按钮进行单个文件转换。
def convert(self):
selected_indices = self.file_listbox.curselection()
if not selected_indices:
messagebox.showerror("错误", "请从列表中选择一个文件。")
return
files_to_convert = [self.files[i] for i in selected_indices]
thread = threading.Thread(target=self._convert_files, args=(files_to_convert,))
thread.start()
def _convert_files(self, files_to_convert):
for file in files_to_convert:
fullpath = os.path.join(self.filepath, file)
heic_img = HEIC2PNG(fullpath)
heic_img.save(fullpath.replace(".heic", '.png'))
self.root.after(0, lambda: messagebox.showinfo("成功", "选择的文件已被转换。"))
14.双击文件进行转换
实现双击列表中的文件时自动触发转换。
def on_item_double_click(self, event):
selected_indices = self.file_listbox.curselection()
if not selected_indices:
return
file = self.files[selected_indices[0]]
if messagebox.askyesno("确认", f"是否转换 {file}?"):
self.convert_file(os.path.join(self.filepath, file))
def convert_file(self, fullpath):
try:
heic_img = HEIC2PNG(fullpath)
png_path = fullpath.lower().replace(".heic", ".png")
heic_img.save(png_path)
except Exception as e:
self.root.after(0, lambda: messagebox.showerror("转换错误", f"{fullpath}: {str(e)}"))
步骤 4:运行应用
最后,初始化应用并启动 Tkinter 的主循环:
if __name__ == "__main__":
root = tk.Tk()
app = HEICConverterApp(root)
root.mainloop()
总结
通过本教程,我们已经创建一个简单的 HEIC 到 PNG 转换工具,支持批量转换、单文件转换、以及通过双击文件来触发转换。你可以根据自己的需求扩展更多功能,比如支持其他格式的转换或自定义转换设置等。
全部代码
import tkinter as tk
from tkinter import filedialog, messagebox
from heic2png import HEIC2PNG
import os
import threading
class HEICConverterApp:
def __init__(self, root):
self.root = root
self.root.title("HEIC to PNG 转换器")
self.root.geometry("600x500")
self.filepath = ""
self.files = []
# 创建菜单栏
menubar = tk.Menu(root)
root.config(menu=menubar)
# 创建文件菜单
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="文件", menu=file_menu)
file_menu.add_command(label="选择文件夹", command=self.select_folder)
file_menu.add_command(label="选择文件", command=self.select_file)
# 创建一个列表框来显示 HEIC 文件
self.file_listbox = tk.Listbox(root, selectmode=tk.MULTIPLE, width=80, height=20)
self.file_listbox.pack(pady=20)
# 绑定双击事件
self.file_listbox.bind("<Double-1>", self.on_item_double_click)
# 创建按钮
button_frame = tk.Frame(root)
button_frame.pack(pady=10)
batch_convert_btn = tk.Button(button_frame, text="批量转换", command=self.batch_convert)
batch_convert_btn.pack(side=tk.LEFT, padx=5)
convert_btn = tk.Button(button_frame, text="转换", command=self.convert)
convert_btn.pack(side=tk.LEFT, padx=5)
def select_folder(self):
self.filepath = filedialog.askdirectory()
if not self.filepath:
return
self.files = [f for f in os.listdir(self.filepath) if f.lower().endswith(".heic")]
self.update_file_listbox()
def select_file(self):
file = filedialog.askopenfilename(filetypes=[("HEIC files", "*.HEIC")])
if file:
self.files = [os.path.basename(file)]
self.update_file_listbox()
def update_file_listbox(self):
self.file_listbox.delete(0, tk.END)
for file in self.files:
self.file_listbox.insert(tk.END, file)
def batch_convert(self):
if not self.filepath:
messagebox.showerror("错误", "请先选择一个文件夹。")
return
thread = threading.Thread(target=self._batch_convert)
thread.start()
def _batch_convert(self):
for file in self.files:
fullpath = os.path.join(self.filepath, file)
heic_img = HEIC2PNG(fullpath)
if "heic" in fullpath.lower():
png_path = fullpath.lower().replace(".heic", ".png")
else:
png_path = fullpath.lower().replace(".HEIC", ".png")
heic_img.save(png_path)
self.root.after(0, lambda: messagebox.showinfo("成功", "转换已完成。"))
def convert(self):
selected_indices = self.file_listbox.curselection()
if not selected_indices:
messagebox.showerror("错误", "请从列表中选择一个文件。")
return
files_to_convert = [self.files[i] for i in selected_indices]
thread = threading.Thread(target=self._convert_files, args=(files_to_convert,))
thread.start()
def _convert_files(self, files_to_convert):
for file in files_to_convert:
fullpath = os.path.join(self.filepath, file)
heic_img = HEIC2PNG(fullpath)
heic_img.save(fullpath.replace(".heic", '.png'))
self.root.after(0, lambda: messagebox.showinfo("成功", "选择的文件已被转换。"))
def on_item_double_click(self, event):
selected_indices = self.file_listbox.curselection()
if not selected_indices:
return
file = self.files[selected_indices[0]]
if messagebox.askyesno("确认", f"是否转换 {file}?"):
self.convert_single(file)
def convert_file(self, fullpath):
try:
heic_img = HEIC2PNG(fullpath)
if "heic" in fullpath.lower():
png_path = fullpath.lower().replace(".heic", ".png")
else:
png_path = fullpath.lower().replace(".HEIC", ".png")
heic_img.save(png_path)
except Exception as e:
self.root.after(0, lambda: messagebox.showerror("转换错误", f"{fullpath}: {str(e)}"))
if __name__ == "__main__":
root = tk.Tk()
app = HEICConverterApp(root)
root.mainloop()