欢迎注册论坛,享受更多奶昔会员权益!
您需要 登录 才可以下载或查看,没有账号?注册
×
直接用这个脚本就行
本地运行,无需网络,上万张图片无损放大几分钟就搞定
这个脚本一键搞定一个目录下所有图片三倍无损放大(递归处理)并覆盖原图
- import os
- import threading
- from tkinter import (
- Tk, Label, Entry, Button, StringVar, IntVar, Checkbutton, Text,
- filedialog, Frame, ttk, DISABLED, NORMAL
- )
- from PIL import Image
-
-
- class ImageResizerApp:
- def __init__(self, root):
- self.root = root
- self.root.title("图片批量无损放大工具")
- self.center_window(858, 600) # 居中窗口
-
- self.stop_flag = False
- self.supported_exts = ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff']
- self.selected_exts = []
- self.processed_count = 0
- self.skipped_count = 0
- self.failed_count = 0
-
- self.build_gui()
-
- def center_window(self, width, height):
- screen_width = self.root.winfo_screenwidth()
- screen_height = self.root.winfo_screenheight()
- x = int((screen_width - width) / 2)
- y = int((screen_height - height) / 2)
- self.root.geometry(f"{width}x{height}+{x}+{y}")
-
- def build_gui(self):
- # 输入路径
- Label(self.root, text="输入文件夹:").grid(row=0, column=0, sticky='e')
- self.input_entry = Entry(self.root, width=60)
- self.input_entry.grid(row=0, column=1, padx=5)
- Button(self.root, text="浏览", command=self.select_input).grid(row=0, column=2)
-
- # 覆盖原图(独立一行)
- self.overwrite_var = IntVar()
- Checkbutton(self.root, text="覆盖原图", variable=self.overwrite_var, command=self.toggle_output).grid(
- row=1, column=0, columnspan=3, sticky='w', padx=20, pady=2)
-
- # 输出路径(带标签)
- Label(self.root, text="输出文件夹:").grid(row=2, column=0, sticky='e')
- self.output_entry = Entry(self.root, width=60)
- self.output_entry.grid(row=2, column=1, padx=5)
- Button(self.root, text="浏览", command=self.select_output).grid(row=2, column=2)
-
- # 放大倍数
- Label(self.root, text="放大倍数:").grid(row=3, column=0, sticky='e')
- self.scale_var = StringVar(value="3")
- Entry(self.root, textvariable=self.scale_var, width=10).grid(row=3, column=1, sticky='w')
-
- # 文件大小限制
- Label(self.root, text="图片体积大于 KB自动跳过:").grid(row=3, column=1, sticky='e')
- self.size_limit_var = StringVar(value="50")
- Entry(self.root, textvariable=self.size_limit_var, width=10).grid(row=3, column=2, sticky='w')
-
- # 图片格式选择
- Label(self.root, text="图片格式:").grid(row=4, column=0, sticky='ne')
- self.ext_vars = {}
- format_frame = Frame(self.root)
- format_frame.grid(row=4, column=1, sticky='w')
- for ext in self.supported_exts:
- var = IntVar(value=1)
- Checkbutton(format_frame, text=ext, variable=var).pack(side='left')
- self.ext_vars[ext] = var
-
- # 自定义扩展名
- Label(self.root, text="追加自定义\n图片类型扩展名 (逗号分隔):").grid(row=5, column=0, sticky='e')
- self.custom_ext_entry = Entry(self.root, width=60)
- self.custom_ext_entry.grid(row=5, column=1, padx=5, pady=2)
-
- # 按钮 + 进度条
- button_frame = Frame(self.root)
- button_frame.grid(row=6, column=0, columnspan=3, pady=10)
- self.start_btn = Button(button_frame, text="开始处理", command=self.start_processing)
- self.start_btn.pack(side='left', padx=5)
- self.stop_btn = Button(button_frame, text="停止", command=self.stop_processing, state=DISABLED)
- self.stop_btn.pack(side='left', padx=5)
-
- self.progress = ttk.Progressbar(self.root, length=500)
- self.progress.grid(row=7, column=0, columnspan=3, pady=10)
-
- # 日志区
- Label(self.root, text="日志:").grid(row=8, column=0, sticky='ne')
- self.log_text = Text(self.root, width=95, height=20)
- self.log_text.grid(row=8, column=1, columnspan=2)
-
- def select_input(self):
- folder = filedialog.askdirectory()
- if folder:
- self.input_entry.delete(0, 'end')
- self.input_entry.insert(0, folder)
-
- def select_output(self):
- folder = filedialog.askdirectory()
- if folder:
- self.output_entry.delete(0, 'end')
- self.output_entry.insert(0, folder)
-
- def toggle_output(self):
- state = DISABLED if self.overwrite_var.get() else NORMAL
- self.output_entry.config(state=state)
-
- def log(self, message):
- self.log_text.insert('end', message + '\n')
- self.log_text.see('end')
-
- def start_processing(self):
- self.stop_flag = False
- self.start_btn.config(state=DISABLED)
- self.stop_btn.config(state=NORMAL)
- self.log_text.delete('1.0', 'end')
- threading.Thread(target=self.process_images).start()
-
- def stop_processing(self):
- self.stop_flag = True
- self.log("正在停止...")
-
- def process_images(self):
- input_dir = self.input_entry.get().strip()
- output_dir = self.output_entry.get().strip()
- scale = int(self.scale_var.get())
- size_limit_kb = int(self.size_limit_var.get())
- self.selected_exts = [ext for ext, var in self.ext_vars.items() if var.get()]
- custom_exts = [e.strip().lower() if e.startswith('.') else f".{e.strip().lower()}"
- for e in self.custom_ext_entry.get().replace(',', ',').split(',') if e.strip()]
- self.selected_exts.extend(custom_exts)
-
- if not os.path.isdir(input_dir):
- self.log("❌ 输入文件夹无效!")
- return
-
- all_files = []
- for foldername, _, filenames in os.walk(input_dir):
- for filename in filenames:
- ext = os.path.splitext(filename)[1].lower()
- if ext in self.selected_exts:
- all_files.append(os.path.join(foldername, filename))
-
- self.progress["maximum"] = len(all_files)
- self.progress["value"] = 0
- self.processed_count = self.skipped_count = self.failed_count = 0
-
- for i, file_path in enumerate(all_files):
- if self.stop_flag:
- self.log("⏹ 已停止处理。")
- break
-
- try:
- if os.path.getsize(file_path) >= size_limit_kb * 1024:
- self.log(f"跳过(文件过大): {file_path}")
- self.skipped_count += 1
- continue
-
- with Image.open(file_path) as img:
- new_size = (img.width * scale, img.height * scale)
- resized_img = img.resize(new_size, Image.Resampling.LANCZOS)
-
- if self.overwrite_var.get():
- save_path = file_path
- else:
- rel_path = os.path.relpath(file_path, input_dir)
- save_path = os.path.join(output_dir, rel_path)
- os.makedirs(os.path.dirname(save_path), exist_ok=True)
-
- file_ext = os.path.splitext(save_path)[1].lower()
- temp_path = save_path + ".tmp"
- save_args = {'format': img.format, 'quality': 95} if file_ext in ('.jpg', '.jpeg') \
- else {'format': img.format, 'optimize': True} if file_ext == '.png' \
- else {'format': img.format}
-
- resized_img.save(temp_path, **save_args)
- os.replace(temp_path, save_path)
- self.log(f"✅ 已处理: {file_path}")
- self.processed_count += 1
-
- except Exception as e:
- self.log(f"❌ 失败: {file_path} - 错误: {str(e)}")
- self.failed_count += 1
-
- self.progress["value"] = i + 1
-
- self.log(f"🎉 完成!成功处理: {self.processed_count} 张,跳过: {self.skipped_count} 张,失败: {self.failed_count} 张")
- self.start_btn.config(state=NORMAL)
- self.stop_btn.config(state=DISABLED)
-
-
- if __name__ == "__main__":
- root = Tk()
- app = ImageResizerApp(root)
- root.mainloop()
复制代码 |