每日签到奶昔超市点数市场奶昔访达
返回列表 发布新帖
查看: 515|回复: 4

图片无损放大,无需AI模型一个脚本搞定

发表于 2025-6-5 18:45:59 | 查看全部 |阅读模式

欢迎注册论坛,享受更多奶昔会员权益!

您需要 登录 才可以下载或查看,没有账号?注册

×
直接用这个脚本就行
本地运行,无需网络,上万张图片无损放大几分钟就搞定
这个脚本一键搞定一个目录下所有图片三倍无损放大(递归处理)并覆盖原图
  1. import os
  2. import threading
  3. from tkinter import (
  4.     Tk, Label, Entry, Button, StringVar, IntVar, Checkbutton, Text,
  5.     filedialog, Frame, ttk, DISABLED, NORMAL
  6. )
  7. from PIL import Image


  8. class ImageResizerApp:
  9.     def __init__(self, root):
  10.         self.root = root
  11.         self.root.title("图片批量无损放大工具")
  12.         self.center_window(858, 600)  # 居中窗口

  13.         self.stop_flag = False
  14.         self.supported_exts = ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff']
  15.         self.selected_exts = []
  16.         self.processed_count = 0
  17.         self.skipped_count = 0
  18.         self.failed_count = 0

  19.         self.build_gui()

  20.     def center_window(self, width, height):
  21.         screen_width = self.root.winfo_screenwidth()
  22.         screen_height = self.root.winfo_screenheight()
  23.         x = int((screen_width - width) / 2)
  24.         y = int((screen_height - height) / 2)
  25.         self.root.geometry(f"{width}x{height}+{x}+{y}")

  26.     def build_gui(self):
  27.         # 输入路径
  28.         Label(self.root, text="输入文件夹:").grid(row=0, column=0, sticky='e')
  29.         self.input_entry = Entry(self.root, width=60)
  30.         self.input_entry.grid(row=0, column=1, padx=5)
  31.         Button(self.root, text="浏览", command=self.select_input).grid(row=0, column=2)

  32.         # 覆盖原图(独立一行)
  33.         self.overwrite_var = IntVar()
  34.         Checkbutton(self.root, text="覆盖原图", variable=self.overwrite_var, command=self.toggle_output).grid(
  35.             row=1, column=0, columnspan=3, sticky='w', padx=20, pady=2)

  36.         # 输出路径(带标签)
  37.         Label(self.root, text="输出文件夹:").grid(row=2, column=0, sticky='e')
  38.         self.output_entry = Entry(self.root, width=60)
  39.         self.output_entry.grid(row=2, column=1, padx=5)
  40.         Button(self.root, text="浏览", command=self.select_output).grid(row=2, column=2)

  41.         # 放大倍数
  42.         Label(self.root, text="放大倍数:").grid(row=3, column=0, sticky='e')
  43.         self.scale_var = StringVar(value="3")
  44.         Entry(self.root, textvariable=self.scale_var, width=10).grid(row=3, column=1, sticky='w')

  45.         # 文件大小限制
  46.         Label(self.root, text="图片体积大于 KB自动跳过:").grid(row=3, column=1, sticky='e')
  47.         self.size_limit_var = StringVar(value="50")
  48.         Entry(self.root, textvariable=self.size_limit_var, width=10).grid(row=3, column=2, sticky='w')

  49.         # 图片格式选择
  50.         Label(self.root, text="图片格式:").grid(row=4, column=0, sticky='ne')
  51.         self.ext_vars = {}
  52.         format_frame = Frame(self.root)
  53.         format_frame.grid(row=4, column=1, sticky='w')
  54.         for ext in self.supported_exts:
  55.             var = IntVar(value=1)
  56.             Checkbutton(format_frame, text=ext, variable=var).pack(side='left')
  57.             self.ext_vars[ext] = var

  58.         # 自定义扩展名
  59.         Label(self.root, text="追加自定义\n图片类型扩展名 (逗号分隔):").grid(row=5, column=0, sticky='e')
  60.         self.custom_ext_entry = Entry(self.root, width=60)
  61.         self.custom_ext_entry.grid(row=5, column=1, padx=5, pady=2)

  62.         # 按钮 + 进度条
  63.         button_frame = Frame(self.root)
  64.         button_frame.grid(row=6, column=0, columnspan=3, pady=10)
  65.         self.start_btn = Button(button_frame, text="开始处理", command=self.start_processing)
  66.         self.start_btn.pack(side='left', padx=5)
  67.         self.stop_btn = Button(button_frame, text="停止", command=self.stop_processing, state=DISABLED)
  68.         self.stop_btn.pack(side='left', padx=5)

  69.         self.progress = ttk.Progressbar(self.root, length=500)
  70.         self.progress.grid(row=7, column=0, columnspan=3, pady=10)

  71.         # 日志区
  72.         Label(self.root, text="日志:").grid(row=8, column=0, sticky='ne')
  73.         self.log_text = Text(self.root, width=95, height=20)
  74.         self.log_text.grid(row=8, column=1, columnspan=2)

  75.     def select_input(self):
  76.         folder = filedialog.askdirectory()
  77.         if folder:
  78.             self.input_entry.delete(0, 'end')
  79.             self.input_entry.insert(0, folder)

  80.     def select_output(self):
  81.         folder = filedialog.askdirectory()
  82.         if folder:
  83.             self.output_entry.delete(0, 'end')
  84.             self.output_entry.insert(0, folder)

  85.     def toggle_output(self):
  86.         state = DISABLED if self.overwrite_var.get() else NORMAL
  87.         self.output_entry.config(state=state)

  88.     def log(self, message):
  89.         self.log_text.insert('end', message + '\n')
  90.         self.log_text.see('end')

  91.     def start_processing(self):
  92.         self.stop_flag = False
  93.         self.start_btn.config(state=DISABLED)
  94.         self.stop_btn.config(state=NORMAL)
  95.         self.log_text.delete('1.0', 'end')
  96.         threading.Thread(target=self.process_images).start()

  97.     def stop_processing(self):
  98.         self.stop_flag = True
  99.         self.log("正在停止...")

  100.     def process_images(self):
  101.         input_dir = self.input_entry.get().strip()
  102.         output_dir = self.output_entry.get().strip()
  103.         scale = int(self.scale_var.get())
  104.         size_limit_kb = int(self.size_limit_var.get())
  105.         self.selected_exts = [ext for ext, var in self.ext_vars.items() if var.get()]
  106.         custom_exts = [e.strip().lower() if e.startswith('.') else f".{e.strip().lower()}"
  107.                        for e in self.custom_ext_entry.get().replace(',', ',').split(',') if e.strip()]
  108.         self.selected_exts.extend(custom_exts)

  109.         if not os.path.isdir(input_dir):
  110.             self.log("❌ 输入文件夹无效!")
  111.             return

  112.         all_files = []
  113.         for foldername, _, filenames in os.walk(input_dir):
  114.             for filename in filenames:
  115.                 ext = os.path.splitext(filename)[1].lower()
  116.                 if ext in self.selected_exts:
  117.                     all_files.append(os.path.join(foldername, filename))

  118.         self.progress["maximum"] = len(all_files)
  119.         self.progress["value"] = 0
  120.         self.processed_count = self.skipped_count = self.failed_count = 0

  121.         for i, file_path in enumerate(all_files):
  122.             if self.stop_flag:
  123.                 self.log("⏹ 已停止处理。")
  124.                 break

  125.             try:
  126.                 if os.path.getsize(file_path) >= size_limit_kb * 1024:
  127.                     self.log(f"跳过(文件过大): {file_path}")
  128.                     self.skipped_count += 1
  129.                     continue

  130.                 with Image.open(file_path) as img:
  131.                     new_size = (img.width * scale, img.height * scale)
  132.                     resized_img = img.resize(new_size, Image.Resampling.LANCZOS)

  133.                     if self.overwrite_var.get():
  134.                         save_path = file_path
  135.                     else:
  136.                         rel_path = os.path.relpath(file_path, input_dir)
  137.                         save_path = os.path.join(output_dir, rel_path)
  138.                         os.makedirs(os.path.dirname(save_path), exist_ok=True)

  139.                     file_ext = os.path.splitext(save_path)[1].lower()
  140.                     temp_path = save_path + ".tmp"
  141.                     save_args = {'format': img.format, 'quality': 95} if file_ext in ('.jpg', '.jpeg') \
  142.                         else {'format': img.format, 'optimize': True} if file_ext == '.png' \
  143.                         else {'format': img.format}

  144.                     resized_img.save(temp_path, **save_args)
  145.                     os.replace(temp_path, save_path)
  146.                     self.log(f"✅ 已处理: {file_path}")
  147.                     self.processed_count += 1

  148.             except Exception as e:
  149.                 self.log(f"❌ 失败: {file_path} - 错误: {str(e)}")
  150.                 self.failed_count += 1

  151.             self.progress["value"] = i + 1

  152.         self.log(f"🎉 完成!成功处理: {self.processed_count} 张,跳过: {self.skipped_count} 张,失败: {self.failed_count} 张")
  153.         self.start_btn.config(state=NORMAL)
  154.         self.stop_btn.config(state=DISABLED)


  155. if __name__ == "__main__":
  156.     root = Tk()
  157.     app = ImageResizerApp(root)
  158.     root.mainloop()
复制代码
爱生活,爱奶昔~
回复

使用道具 举报

发表于 2025-6-5 20:09:34 来自手机 | 查看全部
感谢大佬
爱生活,爱奶昔~
发表于 2025-6-6 00:40:48 来自手机 | 查看全部
看不懂
爱生活,爱奶昔~
发表于 2025-6-8 01:51:13 | 查看全部
不是py吗?
  1. ~/Desktop$ python3 ai.py
  2. Traceback (most recent call last):
  3.   File "/home/m/Desktop/ai.py", line 3, in <module>
  4.     from tkinter import (
  5. ModuleNotFoundError: No module named 'tkinter'
复制代码
爱生活,爱奶昔~
发表于 2025-6-11 09:59:53 | 查看全部
感谢大佬
爱生活,爱奶昔~
您需要登录后才可以回帖 登录 | 注册

本版积分规则

© 2025 Nyarime 沪ICP备13020230号-1|沪公网安备 31010702007642号手机版小黑屋RSS
返回顶部 关灯 在本版发帖
快速回复 返回顶部 返回列表