Python图片体积压缩工具源码

Python图片体积压缩工具源码

图片体积压缩工具源码

在工作中,我们经常遇到需要上传图片到各种系统的情况,而很多平台对图片大小都有严格限制,通常要求不超过 100KB。虽然市面上有不少图片压缩工具,但它们往往功能复杂、界面繁琐,而我需要的仅仅是一个能快速把图片体积压到指定大小以下的小工具。于是,动手写了一个简洁实用的图片压缩工具。

图片[1]-Python图片体积压缩工具源码-QQ沐编程
图片[2]-Python图片体积压缩工具源码-QQ沐编程

一、为什么自己写?

  1. 功能专注:市面上很多工具附带滤镜、裁剪、格式转换等功能,但我只需要压缩体积。
  2. 批量处理:工作中常常需要一次性压缩多张图片。
  3. 可控性强:可以自由设置目标文件大小,虽然不一定完全精确,但能控制在合理范围内。
  4. 离线使用:不需要上传到云端,保护隐私,也避免网络依赖。

二、工具主要功能

  • ✅ 自定义目标压缩大小(单位:KB)
  • ✅ 支持批量选择图片(JPG、PNG、BMP、TIFF、WebP 等常见格式)
  • ✅ 自动转换为 JPG 格式并调整质量参数
  • ✅ 实时显示压缩进度和结果
  • ✅ 输出文件自动重命名,避免覆盖原图

三、工具界面与使用截图

从上传的图片中可以看到,工具界面分为几个部分:

  1. 目标大小设置:可输入并设置期望的图片大小。
  2. 文件选择区:显示已选图片路径。
  3. 压缩执行按钮:点击后开始批量处理。
  4. 结果输出框:显示每张图片的原始大小、压缩后大小、保存路径等。

例如,将三张 1MB 以上的 PNG 图片压缩至 50KB 以内,最终输出的 JPG 文件大小分别为 44KB、69KB、44KB,均满足要求。

四、源代码解析

以下是完整的 Python 源代码,基于 tkinter 实现界面,PIL(Pillow)处理图片:

import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image
import os

class ImageCompressor:
    def __init__(self, root):
        self.root = root
        self.root.title("图片压缩工具 - 目标大小: 100KB以内")
        self.root.geometry("500x400")

        self.target_size = tk.IntVar(value=100)
        self.create_widgets()

    def create_widgets(self):
        target_frame = tk.Frame(self.root)
        target_frame.pack(pady=5)

        tk.Label(target_frame, text="目标大小 (KB):").pack(side=tk.LEFT)
        self.target_size_entry = tk.Entry(target_frame, width=10, textvariable=self.target_size)
        self.target_size_entry.pack(side=tk.LEFT, padx=5)

        tk.Button(target_frame, text="设置", command=self.set_target_size).pack(side=tk.LEFT)

        self.select_btn = tk.Button(self.root, text="选择图片", command=self.select_images)
        self.select_btn.pack(pady=10)
        self.file_label = tk.Label(self.root, text="未选择图片", wraplength=400)
        self.file_label.pack(pady=5)

        self.compress_btn = tk.Button(self.root, text="开始压缩", command=self.compress_images, state=tk.DISABLED)
        self.compress_btn.pack(pady=10)

        self.progress_label = tk.Label(self.root, text="")
        self.progress_label.pack(pady=5)

        self.result_text = tk.Text(self.root, height=10, width=60)
        self.result_text.pack(pady=10)

        self.clear_btn = tk.Button(self.root, text="清空结果", command=self.clear_results)
        self.clear_btn.pack(pady=5)

        self.image_paths = []

    def set_target_size(self):
        """设置目标压缩大小"""
        try:
            size = int(self.target_size.get())
            if size <= 0:
                messagebox.showerror("错误", "目标大小必须大于0KB")
                return
            if size > 10000:  
                messagebox.showwarning("警告", "目标大小过大,建议设置一个小于10MB的值")

            self.root.title(f"图片压缩工具 - 目标大小: {size}KB以内")
            messagebox.showinfo("成功", f"目标大小已设置为: {size}KB")
        except ValueError:
            messagebox.showerror("错误", "请输入有效的数字")

    def select_images(self):
        file_paths = filedialog.askopenfilenames(
            title="选择要压缩的图片",
            filetypes=[
                ("Image files", "*.jpg *.jpeg *.png *.bmp *.tiff *.webp"),
                ("All files", "*.*")
            ]
        )

        if file_paths:
            self.image_paths = list(file_paths)
            self.file_label.config(text=f"已选择 {len(self.image_paths)} 张图片")
            self.compress_btn.config(state=tk.NORMAL)
            self.result_text.insert(tk.END, f"已选择 {len(self.image_paths)} 张图片\n")
            for path in self.image_paths:
                self.result_text.insert(tk.END, f"- {path}\n")

    def compress_images(self):
        if not self.image_paths:
            messagebox.showerror("错误", "请选择至少一张图片")
            return

        total_images = len(self.image_paths)
        success_count = 0

        for i, image_path in enumerate(self.image_paths):
            try:
                self.progress_label.config(text=f"正在处理第 {i+1}/{total_images} 张图片...")
                self.root.update()

                original_size = os.path.getsize(image_path) / 1024 
                self.result_text.insert(tk.END, f"\n处理图片: {os.path.basename(image_path)}\n")
                self.result_text.insert(tk.END, f"原始大小: {original_size:.2f} KB\n")

                img = Image.open(image_path)

                if img.mode in ('RGBA', 'LA', 'P'):
                    img = img.convert('RGB')

                output_path = self.generate_output_path_batch(image_path)

                quality = 95

                while True:
                    img.save(output_path, "JPEG", optimize=True, quality=quality)

                    compressed_size = os.path.getsize(output_path) / 1024 

                    self.progress_label.config(text=f"正在处理: {os.path.basename(image_path)}, 当前质量: {quality}, 大小: {compressed_size:.2f}KB")
                    self.root.update()

                    if compressed_size <= self.target_size.get() or quality <= 10:
                        break

                    if compressed_size > self.target_size.get() * 1.5: 
                        quality -= 15
                    elif compressed_size > self.target_size.get() * 1.2:
                        quality -= 8
                    else:
                        quality -= 5

                    quality = max(quality, 10)

                final_size = os.path.getsize(output_path) / 1024
                self.result_text.insert(tk.END, f"最终质量: {quality}, 最终大小: {final_size:.2f} KB\n")

                if final_size <= self.target_size.get():
                    self.result_text.insert(tk.END, f"✅ 压缩成功! 文件已保存至: {output_path}\n")
                    success_count += 1
                else:
                    self.result_text.insert(tk.END, f"⚠️ 无法压缩到{self.target_size.get()}KB以下,最低压缩到: {final_size:.2f} KB\n")

                self.root.update()

            except Exception as e:
                self.result_text.insert(tk.END, f"❌ 压缩失败: {str(e)}\n")
                messagebox.showerror("错误", f"压缩过程中出现错误: {str(e)}")

        self.progress_label.config(text="完成!")
        messagebox.showinfo("完成", f"批量压缩完成!\n总共处理: {total_images} 张图片\n成功压缩: {success_count} 张图片\n无法压缩到{self.target_size.get()}KB以下: {total_images - success_count} 张图片")

    def generate_output_path_batch(self, input_path):
        """为批量处理生成输出文件路径"""
        base_name, ext = os.path.splitext(input_path)
        counter = 1
        while True:
            output_path = f"{base_name}_compressed_{counter}.jpg"
            if not os.path.exists(output_path):
                return output_path
            counter += 1

    def clear_results(self):
        self.result_text.delete(1.0, tk.END)

    def compress_image(self):
        pass

if __name__ == "__main__":
    root = tk.Tk()
    app = ImageCompressor(root)
    root.mainloop()

五、如何使用

  1. 安装依赖:
pip install Pillow
  1. 运行代码,启动图形界面。
  2. 设置目标大小(默认为 100KB)。
  3. 点击“选择图片”按钮,可多选。
  4. 点击“开始压缩”,等待处理完成。
  5. 压缩后的图片将保存在原图同一目录下,文件名带有 _compressed_序号.jpg 后缀。

六、总结

这个工具虽然简单,但完全满足日常工作中对图片体积的压缩需求。代码结构清晰,容易扩展,例如未来可以加入图片尺寸缩放、保留 EXIF 信息、支持更多输出格式等功能。

如果你也经常需要压缩图片,不妨试试这个工具,或基于此代码进行二次开发,打造属于自己的高效图片处理助手。

© 版权声明
THE END
喜欢就支持一下吧
点赞8赞赏 分享