在日常生活中,我們經常需要處理大量圖片,不論是工作報告、專案簡報,還是個人收藏,但高解析度圖片佔用大量硬碟空間,不僅存取不方便,也不利於分享,甚至儲存在檔案裡時佔了過多空間而經常發生傳輸失敗的問題。
為了改善這些問題,我想用 Python 寫一個「智慧圖片壓縮小助手」—— 一個能夠壓縮單張圖片,甚至一次處理整個資料夾的小工具。接下來,就讓我們一步步看看如何動手實作吧!
import os
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image
import ttkbootstrap as tb
from datetime import datetime
import subprocess
app = tb.Window(themename="cosmo")
app.title("圖片壓縮小工具")
app.geometry("600x400")
log_file = "compression_history.txt"
根據圖片格式(PNG / JPG)做不同壓縮,並計算檔案大小差異。
def compress_image(input_path, output_path, quality=50):
img = Image.open(input_path)
original_size = os.path.getsize(input_path)
if img.format == "PNG":
img.save(output_path, "PNG", optimize=True)
else:
img.save(output_path, "JPEG", optimize=True, quality=quality)
new_size = os.path.getsize(output_path)
return original_size, new_size
def select_file():
file_path = filedialog.askopenfilename(filetypes=[("圖片檔案", "*.png;*.jpg;*.jpeg")])
if file_path:
output_path = os.path.splitext(file_path)[0] + "_compressed.jpg"
orig, new = compress_image(file_path, output_path, quality=int(quality_var.get()))
if orig and new:
messagebox.showinfo("完成", f"單張壓縮完成!\n原始: {orig/1024:.2f} KB\n壓縮後: {new/1024:.2f} KB")
open_folder(output_path)
def select_folder():
folder_path = filedialog.askdirectory()
if folder_path:
for filename in os.listdir(folder_path):
if filename.lower().endswith((".png", ".jpg", ".jpeg")):
input_path = os.path.join(folder_path, filename)
output_path = os.path.join(folder_path, "compressed_" + filename)
compress_image(input_path, output_path, quality=int(quality_var.get()))
messagebox.showinfo("完成", f"資料夾壓縮完成!\n歷史紀錄已更新。")
open_folder(folder_path)
def open_folder(path):
if os.name == "nt": # Windows
subprocess.Popen(f'explorer /select,"{path}"')
else: # Mac / Linux
subprocess.Popen(["open", path])
def view_history():
if os.path.exists(log_file):
with open(log_file, "r", encoding="utf-8") as f:
history_text = f.read()
history_window = tb.Toplevel(app)
history_window.title("壓縮紀錄")
text_box = tk.Text(history_window, wrap="word", width=70, height=20)
text_box.insert("1.0", history_text)
text_box.config(state="disabled")
text_box.pack(padx=10, pady=10)
else:
messagebox.showinfo("提示", "目前沒有歷史紀錄。")
title_label = tb.Label(app, text="📷 圖片壓縮小工具", font=("Microsoft JhengHei", 18, "bold"))
title_label.pack(pady=20)
frame = tb.Frame(app)
frame.pack(pady=10)
btn_file = tb.Button(frame, text="選擇單張圖片", bootstyle="primary", command=select_file)
btn_file.grid(row=0, column=0, padx=10)
btn_folder = tb.Button(frame, text="選擇資料夾", bootstyle="success", command=select_folder)
btn_folder.grid(row=0, column=1, padx=10)
btn_history = tb.Button(frame, text="查看歷史紀錄", bootstyle="info", command=view_history)
btn_history.grid(row=0, column=2, padx=10)
quality_label = tb.Label(app, text="壓縮品質 (1-100,數字越小壓縮越狠)", font=("Microsoft JhengHei", 12))
quality_label.pack(pady=10)
quality_var = tk.StringVar(value="50")
quality_entry = tb.Entry(app, textvariable=quality_var, width=10)
quality_entry.pack()
app.mainloop()
這次完成圖片壓縮工具的實作,對我來說是一個把理論轉化為實用工具 的好機會。原本只是在學習 PIL 圖片處理與檔案操作,後來我結合了 ttkbootstrap 美化介面,讓程式不僅能用,還能有點像「小APP」的感覺。
在過程中,我遇到了幾個挑戰,例如如何同時支援單張圖片與整個資料夾 的選擇,還有如何在壓縮的同時保留 PNG 與 JPG 的格式差異。經過不斷嘗試,我更熟悉了 tkinter.filedialog 與檔案副檔名的處理方法。
這次實作最大的收穫是,讓我明白到即使是一個小小的工具,只要加上 友善的介面與多元的應用情境,就能讓程式真正融入日常生活。同時,這將會是我 2025 IT 鐵人賽 所製作的最後一個小程式,但絕對不會是我學習生涯的終點。未來我會繼續往更進階的程式應用邁進,期待能再次展示新的作品,並與大家一起學習、一起進步。