图片内存太大怎么办 一段Pyhton完美解决(二更)
本帖最后由 ygwbLiu 于 2024-6-4 09:09 编辑苦命打工人之同事误将图片格式选错导致图片体积过大导致无法使用作为同事我岂能置之不顾,于是我发挥了20000%的努力写出了下列代码
此程序是将文件夹内的所有图片全部缩小体积
本次更新增加了以下功能:增加了UI界面、新手引导、图片预览、添加滑块使得更加灵活的调整需要压缩后的图片大小、可选择多线程同时运行提高了时间效率、取消手动输入地址更改为文件内选择输入与输出地址
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
from PIL import Image, ImageTk
import os
import threading
import time
import json
class FirstTimeGuide:
def __init__(self, parent):
self.parent = parent
self.dialog = tk.Toplevel(parent)
self.dialog.title("新手引导")
self.dialog.protocol("WM_DELETE_WINDOW", self.on_close)
intro_text = (
"欢迎使用图片压缩工具!\n\n"
"1. 选择输入文件夹:点击‘浏览’选择图片目录。\n"
"2. 选择输出文件夹:设置压缩后图片存放位置。\n"
"3. 调整压缩质量:滑块控制压缩程度。\n"
"4. 高级设置:更多自定义选项。\n"
"5. 开始压缩:点击按钮开始任务。\n\n"
"了解后,点击‘开始使用’开始体验。"
)
ttk.Label(self.dialog, text=intro_text, justify="left", wraplength=400).pack(pady=20)
ttk.Button(self.dialog, text="开始使用", command=self.on_start).pack(pady=10)
def on_close(self):
with open("first_launch.json", "w") as file:
json.dump({"shown": True}, file)
self.dialog.destroy()
def on_start(self):
self.dialog.destroy()
class AdvancedOptionsDialog:
def __init__(self, parent, compressor):
self.parent = parent
self.compressor = compressor
self.dialog = tk.Toplevel(parent)
self.dialog.title("高级设置")
ttk.Label(self.dialog, text="压缩质量 (1-100):").pack(pady=10)
self.quality_var = tk.IntVar()
self.quality_var.set(self.compressor.quality_var.get())
ttk.Scale(self.dialog, variable=self.quality_var, from_=1, to=100, orient=tk.HORIZONTAL).pack()
ttk.Label(self.dialog, text="线程数:").pack(pady=10)
self.threads_var = tk.IntVar()
self.threads_var.set(4)
ttk.Spinbox(self.dialog, from_=1, to=10, textvariable=self.threads_var).pack()
ttk.Button(self.dialog, text="保存设置", command=self.save_and_close).pack(pady=10)
def save_and_close(self):
self.compressor.quality_var.set(self.quality_var.get())
self.dialog.destroy()
class ImageCompressorGUI:
def __init__(self, master):
self.master = master
master.title("像素减肥所:逗趣图片紧身衣")
self.quality_var = tk.IntVar(value=75)
self.setup_ui()
self.progress_var = tk.DoubleVar()
self.progress_bar = ttk.Progressbar(self.master, orient="horizontal", length=300, mode="determinate", variable=self.progress_var)
self.progress_bar.grid(row=7, column=0, columnspan=3, padx=5, pady=5)
self.status_label = ttk.Label(master, text="准备就绪", foreground="green")
self.status_label.grid(row=8, column=0, columnspan=3, padx=5, pady=5)
self.compress_thread = None
self.load_history()
def setup_ui(self):
self.input_label = ttk.Label(self.master, text="选择输入文件夹:")
self.input_label.grid(row=0, column=0, padx=5, pady=5)
self.input_var = tk.StringVar()
self.input_entry = ttk.Entry(self.master, textvariable=self.input_var, width=50)
self.input_entry.grid(row=0, column=1, padx=5, pady=5)
self.browse_input_button = ttk.Button(self.master, text="浏览", command=self.browse_input_folder)
self.browse_input_button.grid(row=0, column=2, padx=5, pady=5)
self.output_label = ttk.Label(self.master, text="选择输出文件夹:")
self.output_label.grid(row=1, column=0, padx=5, pady=5)
self.output_var = tk.StringVar()
self.output_entry = ttk.Entry(self.master, textvariable=self.output_var, width=50)
self.output_entry.grid(row=1, column=1, padx=5, pady=5)
self.browse_output_button = ttk.Button(self.master, text="浏览", command=self.browse_output_folder)
self.browse_output_button.grid(row=1, column=2, padx=5, pady=5)
self.quality_label = ttk.Label(self.master, text="压缩质量:")
self.quality_label.grid(row=2, column=0, padx=5, pady=5)
ttk.Scale(self.master, variable=self.quality_var, from_=1, to=100, orient=tk.HORIZONTAL).grid(row=2, column=1, columnspan=2, padx=5, pady=5)
self.compress_button = ttk.Button(self.master, text="开始压缩", command=self.start_compression)
self.compress_button.grid(row=4, column=0, columnspan=3, padx=5, pady=10)
self.advanced_button = ttk.Button(self.master, text="高级设置", command=self.show_advanced_options)
self.advanced_button.grid(row=6, column=0, columnspan=3, padx=5, pady=5)
def browse_input_folder(self):
folder_path = filedialog.askdirectory()
self.input_var.set(folder_path)
def browse_output_folder(self):
folder_path = filedialog.askdirectory()
self.output_var.set(folder_path)
def start_compression(self):
input_folder = self.input_var.get()
output_folder = self.output_var.get()
if not os.path.isdir(input_folder) or not os.path.isdir(output_folder):
self.status_label.config(text="输入或输出路径无效,请检查", foreground="red")
return
self.status_label.config(text="压缩进行中...", foreground="black")
self.progress_var.set(0)
self.compress_thread = threading.Thread(target=self.compress_images, args=(input_folder, output_folder))
self.compress_thread.start()
def compress_images(self, input_folder, output_folder):
total_files = sum(len(files) for _, _, files in os.walk(input_folder))
processed_files = 0
for root, dirs, files in os.walk(input_folder):
for file in files:
img_path = os.path.join(root, file)
output_path = os.path.join(output_folder, file)
try:
with Image.open(img_path) as im:
# 根据文件类型调整压缩参数
if file.lower().endswith(('.jpg', '.jpeg')):
im.save(output_path, optimize=True, quality=self.quality_var.get())
elif file.lower().endswith('.png'):
# 尝试使用更高的压缩级别来压缩PNG图像
im.save(output_path, format='PNG', optimize=True, compress_level=9)
else:
messagebox.showinfo("提示", f"{file} 不是支持的图片格式,已跳过。")
continue
processed_files += 1
self.progress_var.set(processed_files / total_files * 100)
self.master.update_idletasks()
except Exception as e:
messagebox.showerror("错误", f"处理{file}时出错: {e}")
self.status_label.config(text="压缩出错,请查看错误信息", foreground="red")
break
if processed_files == total_files:
self.status_label.config(text="压缩完成", foreground="green")
else:
self.status_label.config(text="压缩中断", foreground="orange")
def show_advanced_options(self):
AdvancedOptionsDialog(self.master, self)
def load_history(self):
try:
with open("history.json", "r") as file:
history = json.load(file)
self.input_var.set(history.get("last_input", ""))
self.output_var.set(history.get("last_output", ""))
except FileNotFoundError:
pass
def save_history(self):
history = {"last_input": self.input_var.get(), "last_output": self.output_var.get()}
with open("history.json", "w") as file:
json.dump(history, file)
def check_first_time(self):
try:
with open("first_launch.json", "r") as file:
return json.load(file).get("shown", False)
except FileNotFoundError:
return False
def on_closing(self):
self.save_history()
self.master.destroy()
if __name__ == "__main__":
root = tk.Tk()
app = ImageCompressorGUI(root)
# 新手引导
if not app.check_first_time():
FirstTimeGuide(root)
root.protocol("WM_DELETE_WINDOW", app.on_closing)
root.mainloop() :lol 既然要多次压缩的话 那就在压缩完后 再用代码判断一下图片的大小如果没有满足要求 就再执行一次就好了。
等待用户的界面使用while true写一个死循环就可以不断地输入新的数据 不用再重新打开软件 厉害我这种情况用的大佬写的PS脚本 运行一次就OK 搞个界面,做成选择路径,这样都可以随心转{:301_993:} 其实还可以尝试使用 pngquant、jpegoptim 等工具对原始文件进行优化(前者用于 PNG,后者用于 JPEG)。
如果系统支持,还可以尝试 cwebp 和 cavif 将图片文件转换为压缩率相对更高的 webp (可选无损) 或 avif (av1,有损) 图像格式。 感谢分享代码 牛人啊,这事也能想到用python,感谢楼主分享 外面写个死循环就行,加个判断条件,如果输入了指定参数,那么执行exit 退出 ,就不用你每次跑完一批东西,重新打开了。 怎么使用
强啊,之前都是用wps图片处理
页:
[1]
2