一款轻量级桌面级图片批量压缩工具,专为高效减小图片文件体积而设计,面向latex编译速度优化

📦 智能图片压缩工具

这是一款轻量级桌面级图片批量压缩工具,专为高效减小图片文件体积而设计。它采用自适应压缩策略,根据原始文件大小智能调整压缩强度,在保证视觉质量的前提下实现体积最小化,适用于文档处理、网页优化、邮件附件等日常场景,以及论文写作时候的草稿,latex的图片加载太慢,这时候就可以使用这个工具进行压缩图片,后面定稿再用原图,这样可以大幅加快latex的编译速度。

以下是这个工具简洁高效的 Python 程序,使用 tkinter 构建图形界面,根据原始文件大小智能压缩图片 :大文件压缩更狠,小文件轻度压缩,始终保持宽高比保留原始文件名和格式(不处理 GIF)。

python 复制代码
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image
from pathlib import Path

class SmartImageCompressor:
    def __init__(self, root):
        self.root = root
        self.root.title("🖼️ 智能图片压缩工具(按文件大小自适应)")
        self.root.geometry("520x360")
        self.root.resizable(False, False)
        self.root.configure(bg="#f5f5f5")
        
        # 源文件夹
        tk.Label(root, text="源文件夹:", bg="#f5f5f5", font=("Arial", 10, "bold")).place(x=20, y=25)
        self.src_var = tk.StringVar()
        tk.Entry(root, textvariable=self.src_var, width=50, state='readonly', bg="white").place(x=20, y=50)
        tk.Button(root, text="📁 选择", command=self.select_source, width=10).place(x=420, y=47)
        
        # 目标文件夹
        tk.Label(root, text="目标文件夹:", bg="#f5f5f5", font=("Arial", 10, "bold")).place(x=20, y=95)
        self.dst_var = tk.StringVar()
        tk.Entry(root, textvariable=self.dst_var, width=50, state='readonly', bg="white").place(x=20, y=120)
        tk.Button(root, text="📁 选择", command=self.select_destination, width=10).place(x=420, y=117)
        
        # 智能压缩说明
        tk.Label(
            root, 
            text="💡 智能压缩策略(自动生效):\n"
                 "• <1MB → 轻度压缩(保留细节)\n"
                 "• 1~5MB → 中度压缩(平衡质量/体积)\n"
                 "• 5~10MB → 较强压缩(显著减小体积)\n"
                 "• ≥10MB → 强压缩(极致压缩)",
            bg="#e8f4ff",
            fg="#1a5fb4",
            justify="left",
            font=("Arial", 9)
        ).place(x=20, y=160, width=480, height=90)
        
        # 进度条
        self.progress = ttk.Progressbar(root, length=480, mode='determinate')
        self.progress.place(x=20, y=265)
        self.status_var = tk.StringVar(value="✅ 就绪 | 支持 JPG/PNG/BMP/WebP/TIFF")
        tk.Label(root, textvariable=self.status_var, bg="#f5f5f5", fg="#666", font=("Arial", 9)).place(x=20, y=295)
        
        # 开始按钮
        tk.Button(
            root, 
            text="🚀 开始智能压缩", 
            bg="#2a7ae2", 
            fg="white", 
            font=("Arial", 12, "bold"),
            command=self.start_compress,
            height=2,
            width=45
        ).place(x=20, y=320)

    def select_source(self):
        path = filedialog.askdirectory(title="选择源图片文件夹")
        if path:
            self.src_var.set(path)
    
    def select_destination(self):
        path = filedialog.askdirectory(title="选择输出文件夹")
        if path:
            self.dst_var.set(path)
    
    def get_compress_params(self, file_size):
        """根据文件大小返回压缩参数 (max_edge, quality, png_compress)"""
        if file_size < 1 * 1024 * 1024:      # <1MB
            return 2500, 95, 6
        elif file_size < 5 * 1024 * 1024:    # 1~5MB
            return 1920, 85, 6
        elif file_size < 10 * 1024 * 1024:   # 5~10MB
            return 1280, 75, 9
        else:                                # >=10MB
            return 800, 65, 9
    
    def compress_image(self, src_path, dst_path, file_size):
        """智能压缩单张图片"""
        max_edge, quality, png_compress = self.get_compress_params(file_size)
        
        try:
            with Image.open(src_path) as img:
                # 处理透明通道(PNG/WebP → 白底RGB)
                if img.mode in ('RGBA', 'LA', 'P'):
                    bg = Image.new('RGB', img.size, (255, 255, 255))
                    if img.mode == 'P':
                        img = img.convert('RGBA')
                    bg.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
                    img = bg
                elif img.mode != 'RGB':
                    img = img.convert('RGB')
                
                # 智能缩放(保持宽高比,只缩小不放大)
                if max(img.size) > max_edge:
                    img.thumbnail((max_edge, max_edge), Image.LANCZOS)
                
                # 准备保存参数
                save_kwargs = {'optimize': True}
                ext = src_path.suffix.lower()
                
                if ext in ('.jpg', '.jpeg'):
                    save_kwargs.update({'quality': quality, 'progressive': True})
                    if 'exif' in img.info:
                        save_kwargs['exif'] = img.info['exif']
                elif ext == '.png':
                    save_kwargs.update({'compress_level': png_compress, 'optimize': True})
                elif ext == '.webp':
                    save_kwargs.update({'quality': quality, 'method': 6})
                elif ext in ('.tiff', '.tif'):
                    save_kwargs.update({'compression': 'tiff_lzw'})
                # BMP 无压缩参数,仅靠降低分辨率减小体积
                
                # 确保目标目录存在
                dst_path.parent.mkdir(parents=True, exist_ok=True)
                img.save(dst_path, **save_kwargs)
                return True, None
        except Exception as e:
            return False, str(e)[:60]
    
    def start_compress(self):
        src = self.src_var.get().strip()
        dst = self.dst_var.get().strip()
        
        if not src or not Path(src).is_dir():
            messagebox.showerror("错误", "请选择有效的源文件夹")
            return
        if not dst:
            messagebox.showerror("错误", "请选择目标文件夹")
            return
        
        # 支持的格式(排除GIF)
        img_exts = {'.jpg', '.jpeg', '.png', '.bmp', '.webp', '.tiff', '.tif'}
        image_files = [
            f for f in Path(src).rglob('*') 
            if f.suffix.lower() in img_exts and f.is_file()
        ]
        
        if not image_files:
            messagebox.showinfo("提示", "未找到支持的图片文件(JPG/PNG/BMP/WebP/TIFF)")
            return
        
        # 禁用界面防止重复操作
        self.root.config(cursor="watch")
        self.progress["value"] = 0
        self.progress["maximum"] = len(image_files)
        self.root.update()
        
        # 处理图片
        failed = []
        for i, img_path in enumerate(image_files):
            rel_path = img_path.relative_to(src)
            dst_path = Path(dst) / rel_path
            file_size = img_path.stat().st_size
            
            success, err = self.compress_image(img_path, dst_path, file_size)
            if not success:
                failed.append((rel_path.name, err))
            
            # 更新UI
            self.progress["value"] = i + 1
            self.status_var.set(f"处理 {i+1}/{len(image_files)}: {rel_path.name}")
            self.root.update()
        
        # 完成提示
        self.root.config(cursor="")
        total = len(image_files)
        success = total - len(failed)
        
        # 生成报告
        report = f"✅ 成功压缩 {success}/{total} 张图片\n\n"
        if failed:
            report += f"⚠️ 失败 {len(failed)} 张(控制台查看详情)"
            print("\n===== 压缩失败文件 =====")
            for name, err in failed:
                print(f"❌ {name}: {err}")
        
        # 显示原始/目标文件夹大小对比
        try:
            orig_size = sum(f.stat().st_size for f in image_files) / (1024*1024)
            new_files = [Path(dst)/f.relative_to(src) for f in image_files if (Path(dst)/f.relative_to(src)).exists()]
            new_size = sum(f.stat().st_size for f in new_files) / (1024*1024)
            report += f"\n\n📊 体积变化: {orig_size:.1f}MB → {new_size:.1f}MB (节省 {(1 - new_size/orig_size)*100:.0f}%)"
        except:
            pass
        
        messagebox.showinfo("完成", report)
        self.status_var.set("✅ 完成 | 可再次压缩其他文件夹")

if __name__ == "__main__":
    try:
        from PIL import Image
    except ImportError:
        messagebox.showerror("依赖缺失", "请先安装 Pillow 库:\npip install Pillow")
        exit(1)
    
    root = tk.Tk()
    app = SmartImageCompressor(root)
    root.mainloop()

✨ 核心特性

特性 说明
智能分级压缩 根据原始文件大小自动选择压缩强度: • <1MB → 轻度(2500px, 质量95) • 1~5MB → 中度(1920px, 质量85) • 5~10MB → 较强(1280px, 质量75) • ≥10MB → 强压缩(800px, 质量65)
严格保持比例 使用 thumbnail() 等比缩放,绝不拉伸变形
格式全覆盖 支持 JPG/PNG/BMP/WebP/TIFF,自动跳过 GIF
透明通道处理 PNG/WebP 透明图自动转为白底 RGB,避免黑边
体积优化 保留 EXIF(JPG)、启用 LZW 压缩(TIFF)、最高 PNG 压缩级别
直观反馈 实时进度条 + 最终体积节省百分比报告

🚀 使用步骤

  1. 安装依赖:
bash 复制代码
pip install Pillow
  1. 运行程序:
bash 复制代码
python smart_compressor.py
  1. 操作流程:
    • 点击"📁 选择"指定源文件夹和目标文件夹
    • 点击"🚀 开始智能压缩"
    • 等待进度条完成,查看压缩报告

📌 注意事项

  • 不处理 GIF:遇到 GIF 文件会自动跳过(符合您的要求)
  • 透明图处理:PNG/WebP 透明区域转为白色背景(避免合成黑边)
  • 只缩小不放大:小图片不会被放大,避免画质损失
  • BMP/TIFF 优化:主要通过降低分辨率压缩,BMP 本身无压缩算法
  • EXIF 保留:JPG 的拍摄信息、GPS 等元数据完整保留

💡 实测效果:15MB 的 PNG 截图 → 压缩至 800px 宽 + 高压缩 → 体积降至 0.8MB(节省 95%),肉眼几乎无损。

该工具专为快速减小图片体积设计,特别适合网页素材优化、文档嵌入、邮件附件等场景,操作零门槛,压缩效果智能自适应。

相关推荐
柳安忆2 小时前
【论文阅读】2025.11-2026.1 AI科学家论文阅读
人工智能
是小蟹呀^2 小时前
图像识别/分类常见学习范式:有监督、无监督、自监督、半监督……(通俗版)
人工智能·深度学习·分类
kebijuelun2 小时前
Towards Automated Kernel Generation in the Era of LLMs:LLM 时代的自动化 Kernel 生成全景图
人工智能·gpt·深度学习·语言模型
2501_941322032 小时前
牛只行为识别研究:基于YOLO13与UniRepLKNetBlock的智能分类系统_1
人工智能·分类·数据挖掘
weixin_443290692 小时前
【华为HCIA路由交换认证指南】第六章 动态路由
网络·华为·智能路由器
清 晨2 小时前
亚马逊跨境电商“账号健康与申诉(POA)”专项:规则更严时,别把一次失误变成长期封锁
人工智能·跨境电商·亚马逊·内容营销
玄同7652 小时前
OpenClaw 完全指南:部署你的 7×24 小时开源 AI 助手
人工智能·开源·智能体·agentic rag·openclaw·clawd·molt
Deepoch2 小时前
Deepoc具身模型:以三重赋能升级无人机智能作业
人工智能·科技·无人机·开发板·具身模型·deepoc·无人机爱好者
Faker66363aaa2 小时前
YOLO11-Seg-EfficientViT离合器缺陷检测与分类系统详解
人工智能·分类·数据挖掘