Python中图片压缩小工具的开发与异常解决详解

 更新时间:2025年09月15日 08:45:40   作者:晨曦之光Wing  
这篇文章主要为大家详细介绍了如何通过Deep Seek编写Python代码,制作一个图片压缩小工具,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

一、问题描述

通过Deep Seek写Python代码,制作一个图片压缩小工具,结果发现竖图压缩失败,然后一直让它优化,修复这个问题,结果还是一直失败。后面一步步调试才发现,根本不是横图、竖图的问题,而是某些特定场景(图片大小、压缩质量)下会导致死循环,进而导致压缩失败。

二、问题代码及修复

下方while循环的>=会导致某些特定场景下出现死循环,将等号去掉即可。

    def compress_image(self, input_path, output_path, target_size_kb):
        """压缩单张图片到目标大小"""
        # 打开图片
        img = Image.open(input_path)

        # 如果是PNG格式,转换为JPG以获得更好的压缩效果
        if img.format == 'PNG':
            img = img.convert('RGB')
            output_path = output_path.rsplit('.', 1)[0] + '.jpg'

        # 设置初始质量
        quality = 95
        min_quality = 10

        # 转换为字节并检查大小
        while quality >= min_quality:
            # 保存为字节数据以检查大小
            img.save(output_path, quality=quality, optimize=True)

            # 检查文件大小
            file_size_kb = os.path.getsize(output_path) / 1024

            if file_size_kb <= target_size_kb:
                break

            # 质量降低步长根据差距动态调整
            size_ratio = file_size_kb / target_size_kb
            quality_reduction = max(5, int(quality * (1 - 1 / size_ratio) / 2))
            quality = max(min_quality, quality - quality_reduction)

三、修复历程

经过上述几个来回,发现问题依然没有解决,于是我就一步步调试代码去了,此时我以为这个问题是一步步“优化”出来的。

【第一个版本】

后面看了一下发现,前面七个版本基本都是类似的处理,估计我是在第四个版本的时候使用了那张竖图,导致压缩失败了,然后以“失败的结论”去修复失败的问题,结果就一直失败。开了深度思考之后,又优化了两个版本,下面是最后一个版本。

【最后一个版本】

给我整笑了

成功了?我图呢 ?_?

此时我已经不想去纠结了……反正第一个版本修改之后能正常使用了

四、正确代码

第一个版本修改之后的代码:

import os
import sys
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image
import threading


class ImageCompressorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("图片压缩工具")
        self.root.geometry("500x300")
        self.root.resizable(False, False)

        # 变量初始化
        self.input_folder = tk.StringVar()
        self.output_folder = tk.StringVar()
        self.target_size = tk.IntVar(value=100)  # 默认100KB

        self.create_widgets()

    def create_widgets(self):
        # 输入文件夹选择
        tk.Label(self.root, text="输入文件夹:").grid(row=0, column=0, padx=10, pady=10, sticky="w")
        tk.Entry(self.root, textvariable=self.input_folder, width=40).grid(row=0, column=1, padx=10, pady=10)
        tk.Button(self.root, text="浏览", command=self.browse_input).grid(row=0, column=2, padx=10, pady=10)

        # 输出文件夹选择
        tk.Label(self.root, text="输出文件夹:").grid(row=1, column=0, padx=10, pady=10, sticky="w")
        tk.Entry(self.root, textvariable=self.output_folder, width=40).grid(row=1, column=1, padx=10, pady=10)
        tk.Button(self.root, text="浏览", command=self.browse_output).grid(row=1, column=2, padx=10, pady=10)

        # 目标大小设置
        tk.Label(self.root, text="目标大小(KB):").grid(row=2, column=0, padx=10, pady=10, sticky="w")
        tk.Scale(self.root, from_=10, to=1000, orient=tk.HORIZONTAL, variable=self.target_size).grid(row=2, column=1,
                                                                                                     padx=10, pady=10,
                                                                                                     sticky="ew")

        # 压缩按钮
        self.compress_btn = tk.Button(self.root, text="开始压缩", command=self.start_compression, bg="lightblue")
        self.compress_btn.grid(row=3, column=1, padx=10, pady=20)

        # 进度条
        self.progress = ttk.Progressbar(self.root, orient=tk.HORIZONTAL, length=400, mode='indeterminate')
        self.progress.grid(row=4, column=0, columnspan=3, padx=10, pady=10)

        # 状态标签
        self.status_label = tk.Label(self.root, text="准备就绪", relief=tk.SUNKEN, anchor=tk.W)
        self.status_label.grid(row=5, column=0, columnspan=3, sticky="ew", padx=10, pady=10)

    def browse_input(self):
        folder = filedialog.askdirectory()
        if folder:
            self.input_folder.set(folder)

    def browse_output(self):
        folder = filedialog.askdirectory()
        if folder:
            self.output_folder.set(folder)

    def start_compression(self):
        if not self.input_folder.get() or not self.output_folder.get():
            messagebox.showerror("错误", "请选择输入和输出文件夹")
            return

        # 在后台线程中执行压缩,避免界面冻结
        thread = threading.Thread(target=self.compress_images)
        thread.daemon = True
        thread.start()

    def compress_images(self):
        self.compress_btn.config(state=tk.DISABLED)
        self.progress.start()
        self.status_label.config(text="正在压缩图片...")

        input_dir = self.input_folder.get()
        output_dir = self.output_folder.get()
        target_size_kb = self.target_size.get()

        # 支持的图片格式
        supported_formats = ('.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp')

        try:
            # 获取所有图片文件
            image_files = [f for f in os.listdir(input_dir)
                           if f.lower().endswith(supported_formats)]

            if not image_files:
                messagebox.showinfo("信息", "未找到支持的图片文件")
                return

            # 创建输出目录(如果不存在)
            if not os.path.exists(output_dir):
                os.makedirs(output_dir)

            # 处理每张图片
            for i, filename in enumerate(image_files):
                self.status_label.config(text=f"正在处理 {i + 1}/{len(image_files)}: {filename}")
                self.root.update()

                input_path = os.path.join(input_dir, filename)
                output_path = os.path.join(output_dir, filename)

                # 压缩图片
                self.compress_image(input_path, output_path, target_size_kb)

            self.status_label.config(text=f"完成! 已压缩 {len(image_files)} 张图片")
            messagebox.showinfo("完成", f"图片压缩完成! 共处理 {len(image_files)} 张图片")

        except Exception as e:
            messagebox.showerror("错误", f"压缩过程中发生错误: {str(e)}")
        finally:
            self.progress.stop()
            self.compress_btn.config(state=tk.NORMAL)

    def compress_image(self, input_path, output_path, target_size_kb):
        """压缩单张图片到目标大小"""
        # 打开图片
        img = Image.open(input_path)

        # 如果是PNG格式,转换为JPG以获得更好的压缩效果
        if img.format == 'PNG':
            img = img.convert('RGB')
            output_path = output_path.rsplit('.', 1)[0] + '.jpg'

        # 设置初始质量
        quality = 95
        min_quality = 10

        # 转换为字节并检查大小
        while quality > min_quality:
            # 保存为字节数据以检查大小
            img.save(output_path, quality=quality, optimize=True)

            # 检查文件大小
            file_size_kb = os.path.getsize(output_path) / 1024

            if file_size_kb <= target_size_kb:
                break

            # 质量降低步长根据差距动态调整
            size_ratio = file_size_kb / target_size_kb
            quality_reduction = max(5, int(quality * (1 - 1 / size_ratio) / 2))
            quality = max(min_quality, quality - quality_reduction)


def main():
    root = tk.Tk()
    app = ImageCompressorApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()

原图998KB,压缩后140KB,压缩格式为jpg,支持批量压缩(压缩所选文件夹下的所有图片)

(P.S. 后续将发布进一步优化的版本)

到此这篇关于Python中图片压缩小工具的开发与异常解决详解的文章就介绍到这了,更多相关Python图片压缩内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • pytorch 数据处理:定义自己的数据集合实例

    pytorch 数据处理:定义自己的数据集合实例

    今天小编就为大家分享一篇pytorch 数据处理:定义自己的数据集合实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-12-12
  • 基于Python轻松实现PDF转图片

    基于Python轻松实现PDF转图片

    PDF文件是我们在日常工作和学习中常用的文档格式之一,但你知道吗,你可以将PDF文件转换为图像,让文档变得更加生动有趣,下面我们就来看看具体的实现方法吧
    2023-08-08
  • Python中Matplotlib的简单使用

    Python中Matplotlib的简单使用

    这篇文章主要介绍了Python中Matplotlib的简单使用,Matplotlib是一个用于绘制数据可视化图形的Python库,支持绘制各种静态,动态,交互式的图表,它是数据科学和机器学习领域最流行的可视化库之一,需要的朋友可以参考下
    2023-07-07
  • Python自动化办公之编写PDF拆分工具

    Python自动化办公之编写PDF拆分工具

    这篇文章主要为大家分享一个Python自动化办公的小工具——PDF拆分工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试
    2022-03-03
  • 解决python replace函数替换无效问题

    解决python replace函数替换无效问题

    在本篇文章里小编给大家整理的是一篇关于python replace函数替换无效问题的解决方法,需要的朋友们可以参考下。
    2020-01-01
  • python安装并使用virtualenv管理包的详细过程

    python安装并使用virtualenv管理包的详细过程

    本文主要介绍了Python的安装过程和如何使用virtualenv管理包,首先,用户需要访问Python官网下载安装包,并运行安装程序,安装完成后,在命令行输入Python,显示安装的Python版本号,即表示安装成功,感兴趣的朋友一起看看吧
    2024-10-10
  • Python Opencv轮廓常用操作代码实例解析

    Python Opencv轮廓常用操作代码实例解析

    这篇文章主要介绍了Python Opencv轮廓常用操作代码实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • Python matplotlib绘制散点图的实例代码

    Python matplotlib绘制散点图的实例代码

    这篇文章主要给大家介绍了关于Python matplotlib绘制散点图的相关资料,所谓散点图就是反映两组变量每个数据点的值,并且从散点图可以看出它们之间的相关性,需要的朋友可以参考下
    2021-06-06
  • python和bash统计CPU利用率的方法

    python和bash统计CPU利用率的方法

    这篇文章主要介绍了python和bash统计CPU利用率的方法,涉及Python针对系统硬件信息的读取技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • Flask接收上传图片方法实现

    Flask接收上传图片方法实现

    本文主要介绍了Flask接收上传图片方法实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07

最新评论