python
复制代码
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image, ImageFilter, ImageEnhance
import os
class BatchImageProcessor:
def __init__(self, root):
self.root = root
self.root.title("图片批量处理器")
self.root.geometry("800x600")
self.center_window()
# 初始化变量
self.input_folder = ""
self.output_folder = ""
self.processing_options = {
"resize": False,
"resize_width": 800,
"resize_height": 600,
"grayscale": False,
"blur": False,
"blur_radius": 2,
"contrast": False,
"contrast_factor": 1.2,
}
# 创建界面
self.create_widgets()
def center_window(self):
# 强制更新窗口尺寸信息
self.root.update_idletasks()
# 获取窗口尺寸
window_width = self.root.winfo_width()
window_height = self.root.winfo_height()
# 计算居中坐标
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
x = (screen_width - window_width) // 2
y = (screen_height - window_height) // 2
# 设置窗口位置
self.root.geometry(f"+{x}+{y}")
def create_widgets(self):
# 顶部框架 - 文件夹选择
folder_frame = tk.LabelFrame(self.root, text="文件夹设置", padx=10, pady=10)
folder_frame.pack(fill="x", padx=10, pady=5)
# 输入文件夹
tk.Label(folder_frame, text="输入文件夹:").grid(row=0, column=0, sticky="w")
self.input_entry = tk.Entry(folder_frame, width=50)
self.input_entry.grid(row=0, column=1, padx=5)
tk.Button(
folder_frame,
text="浏览...",
command=self.select_input_folder
).grid(row=0, column=2)
# 输出文件夹
tk.Label(folder_frame, text="输出文件夹:").grid(row=1, column=0, sticky="w")
self.output_entry = tk.Entry(folder_frame, width=50)
self.output_entry.grid(row=1, column=1, padx=5)
tk.Button(
folder_frame,
text="浏览...",
command=self.select_output_folder
).grid(row=1, column=2)
# 中间框架 - 处理选项
option_frame = tk.LabelFrame(self.root, text="处理选项", padx=10, pady=10)
option_frame.pack(fill="both", expand=True, padx=10, pady=5)
# 调整大小选项
self.resize_var = tk.BooleanVar()
tk.Checkbutton(
option_frame,
text="调整大小",
variable=self.resize_var,
command=self.toggle_resize
).grid(row=0, column=0, sticky="w")
self.resize_width_label = tk.Label(option_frame, text="宽度:")
self.resize_width_label.grid(row=0, column=1, sticky="e")
self.resize_width_entry = tk.Entry(option_frame, width=5)
self.resize_width_entry.grid(row=0, column=2)
self.resize_width_entry.insert(0, "800")
tk.Label(option_frame, text="高度:").grid(row=0, column=3, sticky="e")
self.resize_height_entry = tk.Entry(option_frame, width=5)
self.resize_height_entry.grid(row=0, column=4)
self.resize_height_entry.insert(0, "600")
# 其他选项
self.grayscale_var = tk.BooleanVar()
tk.Checkbutton(
option_frame,
text="转为灰度图",
variable=self.grayscale_var
).grid(row=1, column=0, sticky="w")
self.blur_var = tk.BooleanVar()
tk.Checkbutton(
option_frame,
text="模糊效果",
variable=self.blur_var,
command=self.toggle_blur
).grid(row=1, column=1, sticky="w")
self.blur_radius_label = tk.Label(option_frame, text="模糊半径:")
self.blur_radius_label.grid(row=1, column=2, sticky="e")
self.blur_radius_entry = tk.Entry(option_frame, width=5)
self.blur_radius_entry.grid(row=1, column=3)
self.blur_radius_entry.insert(0, "2")
self.contrast_var = tk.BooleanVar()
tk.Checkbutton(
option_frame,
text="调整对比度",
variable=self.contrast_var,
command=self.toggle_contrast
).grid(row=2, column=0, sticky="w")
self.contrast_label = tk.Label(option_frame, text="对比度系数:")
self.contrast_label.grid(row=2, column=1, sticky="e")
self.contrast_entry = tk.Entry(option_frame, width=5)
self.contrast_entry.grid(row=2, column=2)
self.contrast_entry.insert(0, "1.2")
# 底部框架 - 操作按钮和进度条
control_frame = tk.Frame(self.root)
control_frame.pack(fill="x", padx=10, pady=5)
tk.Button(
control_frame,
text="开始处理",
command=self.start_processing,
width=15
).pack(side="left", padx=5)
tk.Button(
control_frame,
text="退出",
command=self.root.quit,
width=15
).pack(side="right", padx=5)
# 进度条
self.progress = ttk.Progressbar(
self.root,
orient="horizontal",
length=500,
mode="determinate"
)
self.progress.pack(pady=10)
self.status_label = tk.Label(self.root, text="准备就绪", bd=1, relief="sunken", anchor="w")
self.status_label.pack(fill="x", padx=10, pady=5)
# 初始化选项状态
self.toggle_resize()
self.toggle_blur()
self.toggle_contrast()
def toggle_resize(self):
state = "normal" if self.resize_var.get() else "disabled"
self.resize_width_entry.config(state=state)
self.resize_height_entry.config(state=state)
self.resize_width_label.config(state=state)
def toggle_blur(self):
state = "normal" if self.blur_var.get() else "disabled"
self.blur_radius_entry.config(state=state)
self.blur_radius_label.config(state=state)
def toggle_contrast(self):
state = "normal" if self.contrast_var.get() else "disabled"
self.contrast_entry.config(state=state)
self.contrast_label.config(state=state)
def select_input_folder(self):
folder = filedialog.askdirectory(title="选择输入文件夹")
if folder:
self.input_folder = folder
self.input_entry.delete(0, tk.END)
self.input_entry.insert(0, folder)
def select_output_folder(self):
folder = filedialog.askdirectory(title="选择输出文件夹")
if folder:
self.output_folder = folder
self.output_entry.delete(0, tk.END)
self.output_entry.insert(0, folder)
def update_status(self, message):
self.status_label.config(text=message)
self.root.update_idletasks()
def process_image(self, img_path, output_path):
try:
with Image.open(img_path) as img:
# 调整大小
if self.resize_var.get():
width = int(self.resize_width_entry.get())
height = int(self.resize_height_entry.get())
img = img.resize((width, height), Image.Resampling.LANCZOS)
# 转为灰度图
if self.grayscale_var.get():
img = img.convert("L")
# 模糊效果
if self.blur_var.get():
radius = float(self.blur_radius_entry.get())
img = img.filter(ImageFilter.GaussianBlur(radius))
# 调整对比度
if self.contrast_var.get():
factor = float(self.contrast_entry.get())
enhancer = ImageEnhance.Contrast(img)
img = enhancer.enhance(factor)
# 保存图片
img.save(output_path)
return True
except Exception as e:
print(f"处理图片 {img_path} 时出错: {e}")
return False
def start_processing(self):
# 验证输入
if not self.input_folder or not os.path.isdir(self.input_folder):
messagebox.showerror("错误", "请选择有效的输入文件夹")
return
if not self.output_folder:
messagebox.showerror("错误", "请选择输出文件夹")
return
if not os.path.exists(self.output_folder):
os.makedirs(self.output_folder)
# 获取图片文件列表
image_files = [
f for f in os.listdir(self.input_folder)
if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif'))
]
if not image_files:
messagebox.showwarning("警告", "输入文件夹中没有找到图片文件")
return
# 设置进度条
self.progress["maximum"] = len(image_files)
self.progress["value"] = 0
# 开始处理
processed = 0
for i, filename in enumerate(image_files, 1):
input_path = os.path.join(self.input_folder, filename)
output_path = os.path.join(self.output_folder, filename)
self.update_status(f"正在处理: {filename} ({i}/{len(image_files)})")
if self.process_image(input_path, output_path):
processed += 1
self.progress["value"] = i
self.root.update_idletasks()
# 处理完成
self.update_status(f"处理完成! 成功处理 {processed}/{len(image_files)} 张图片")
messagebox.showinfo("完成", f"批量处理完成!\n成功处理 {processed} 张图片")
if __name__ == "__main__":
root = tk.Tk()
app = BatchImageProcessor(root)
root.mainloop()