Python 图片压缩

我做了一个处理Markdown图片的小工具markdown-img,在之前给这个工具添加了主流图床支持后功能基本完备了。昨天写了一篇影评的博客扎导版正义联盟观影吐槽,图片都是从电影中截取的,每张都是1Mb以上,颇占云存储空间,所以决定加上图片压缩功能。

bing了一番以后,决定使用Pillow库实现压缩功能,虽然使用 python 压缩 png 图片,高达 80% 压缩率,肉眼无差异(一):为什么不用 pillow库这篇文章说了为什么Pillow库用于压缩的缺陷,但该作者给出的另一个压缩方案是windows软件,只能通过命令行调取,并不能直接通过pip库集成,综合考虑下来还是使用Pillow库,至少作为一个可选项是不错的,后期可以加入其它的压缩服务支持,比如在线无损压缩服务tinypng

先通过pip安装包:

python3 -m pip install --upgrade pip
python3 -m pip install --upgrade Pillow

因为暂时只有这一个压缩服务,就简单地用单个文件进行组织:

from PIL import Image
from ..config import Config
import os
from ..tools.debug import Debug


class Compress:
    def __init__(self, imageFile: str, compressLimit: int = 500) -> None:
        """初始化压缩上下文管理器
        imageFile: 用于压缩的原图片路径
        compressLimit: 压缩门槛(高于该值的图片才会被压缩,单位kb)
        """
        self.__imageFile = imageFile
        self.__compressLimit: int = compressLimit

    def __enter__(self):
        # 对png图片使用quantize压缩
        basename = os.path.basename(self.__imageFile)
        _, _, ext = basename.rpartition(".")
        imageSize = self.__class__.getSize(self.__imageFile)
        # 没有达到压缩门槛,不压缩
        if imageSize < self.__compressLimit:
            return self.__imageFile
        Debug.print("开始对{}进行压缩,压缩前大小{}kb".format(
            self.__imageFile, int(imageSize)))
        if ext == "png":
            self.__compressPng(self.__imageFile)
        else:
            self.__compressImage(self.__imageFile)
        outPutFile = self.__getOutPutFile(self.__imageFile)
        if os.path.exists(outPutFile):
            return outPutFile
        else:
            # 没有产生压缩图片,返回原图
            return self.__imageFile

    def __exit__(self, expType, expVal, expTrace):
        # 如果存在压缩后的临时文件,删除
        outPutFile = self.__getOutPutFile(self.__imageFile)
        if os.path.exists(outPutFile):
            os.remove(outPutFile)

    @classmethod
    def getSize(cls, file):
        # 获取文件大小:KB
        size = os.path.getsize(file)
        return size / 1024

    def __getOutPutFile(self, infile: str) -> str:
        """获取输出文件路径
        infile: 待处理文件路径
        return: 输出文件路径
        """
        fileName: str = os.path.basename(infile)
        sysConfig = Config.getInstance()
        return sysConfig.getTmpDir()+sysConfig.getPathSplit()+fileName

    def __compressPng(self, infile: str) -> None:
        """压缩png图片到输出目录
        infile: 待压缩图片
        """
        im: Image.Image = Image.open(infile)
        new_im = im.quantize(colors=256)
        new_im.save(self.__getOutPutFile(infile))
        pressedSize = self.__class__.getSize(self.__getOutPutFile(infile))
        Debug.print("{}压缩后的大小{}kb".format(infile, int(pressedSize)))

    def __compressImage(self, infile, step=10, quality=80) -> None:
        """对图片进行多轮压缩以达到压缩门槛(仅限JPG图片)
        infile: 压缩源文件
        step: 每一轮压缩增加的压缩率差值
        quality: 起始压缩率
        """
        maxSize = self.__compressLimit
        o_size = self.__class__.getSize(infile)
        if o_size <= maxSize:
            return
        outfile = self.__getOutPutFile(infile)
        im = Image.open(infile)
        while o_size > maxSize:
            im.save(outfile, quality=quality)
            if quality - step < 0:
                break
            quality -= step
            o_size = self.__class__.getSize(outfile)
        Debug.print("{}压缩后的大小{}kb".format(infile, int(o_size)))
        return

ConfigDebug等项目中地其它组件在这里只起到配置和调试相关功能,并不影响压缩功能。

这里的主要关键在于Pillow库压缩图片需要对png格式和jpg格式单独对待,处理方式不同,im.save(outfile, quality=quality)这种方式并不能压缩png格式的图片。

此外之所以我将这个模块写成上下文管理器,是因为在我的程序中是需要压缩后上传到网络图库,本地不需要压缩后的图片,所以最好自动删除,故此上下文管理器的方式应该是最佳的。

使用:

            with Compress(localImg, compressLimit) as compressedImg:
                imgService = ImgServiceManager.getImgService()
                return imgService.upload(compressedImg)

测试:

开始对7526c60df75a574cd2b42da1239308df.png进行压缩,压缩前大小929kb
开始对c105b51e21824730b09f68bbc8352c63.jpeg进行压缩,压缩前大小2002kb
开始对i6q1uk.png进行压缩,压缩前大小1084kb
c105b51e21824730b09f68bbc8352c63.jpeg压缩后的大小340kb
7526c60df75a574cd2b42da1239308df.png压缩后的大小292kb

参考资料:

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐