吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 887|回复: 17
收起左侧

[学习记录] 图片内存太大怎么办 一段Pyhton完美解决(二更)

[复制链接]
ygwbLiu 发表于 2024-5-29 23:44
本帖最后由 ygwbLiu 于 2024-6-4 09:09 编辑

苦命打工人之同事误将图片格式选错导致图片体积过大导致无法使用作为同事我岂能置之不顾,于是我发挥了20000%的努力写出了下列代码
此程序是将文件夹内的所有图片全部缩小体积
本次更新增加了以下功能:增加了UI界面、新手引导、图片预览、添加滑块使得更加灵活的调整需要压缩后的图片大小、可选择多线程同时运行提高了时间效率、取消手动输入地址更改为文件内选择输入与输出地址
[Python] 纯文本查看 复制代码
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("[color=#2c2c36][font=-apple-system, BlinkMacSystemFont, "][size=16px]像素减肥所:逗趣图片紧身衣[/size][/font][/color]")

        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()

免费评分

参与人数 2吾爱币 +2 热心值 +1 收起 理由
jy138290 + 1 + 1 谢谢@Thanks!
lgc81034 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

wkdxz 发表于 2024-5-30 07:14
既然要多次压缩的话 那就在压缩完后 再用代码判断一下图片的大小如果没有满足要求 就再执行一次就好了。

等待用户的界面使用while true写一个死循环就可以不断地输入新的数据 不用再重新打开软件
医生不可以 发表于 2024-5-30 08:25
厉害  我这种情况用的大佬写的PS脚本 运行一次就OK
xinshengdaiorg 发表于 2024-5-30 08:29
搞个界面,做成选择路径,这样都可以随心转
爱飞的猫 发表于 2024-5-30 08:45
其实还可以尝试使用 pngquant、jpegoptim 等工具对原始文件进行优化(前者用于 PNG,后者用于 JPEG)。

如果系统支持,还可以尝试 cwebp 和 cavif 将图片文件转换为压缩率相对更高的 webp (可选无损) 或 avif (av1,有损) 图像格式。
LuckyClover 发表于 2024-5-30 09:22
感谢分享代码
xuming0315 发表于 2024-5-30 09:22
牛人啊,这事也能想到用python,感谢楼主分享
chmod755 发表于 2024-5-30 09:47
外面写个死循环就行,加个判断条件,如果输入了指定参数,那么执行exit 退出 ,就不用你每次跑完一批东西,重新打开了。
zd53011 发表于 2024-5-30 10:07
怎么使用
wdo1106 发表于 2024-5-30 10:50
强啊,之前都是用wps图片处理
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-9-28 21:42

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表