【python】图片批量压缩(多线程)

效果演示

在这里插入图片描述

项目场景

从某网站爬了很多图片,图片有jpgpng等格式。有些图片很大,出于某种需求,我们需要把图片批量压缩一下。

核心代码

from PIL import Image
im = Image.open('test.png')
im = im.convert('RGB')
im.save('test.jpg', quality=75)

这里的图片压缩我们用到的是pillow库,所有图片都先转换到RGB三个通道,然后全部保存为jpg格式。

quality参数是设置图片保存质量的参数,默认值是75,其取值范围为1~95,你可以根据自己的具体需求设置。

完整代码

import concurrent.futures as cf
from PIL import Image
import time
import os
import re


class ImageConvert(object):
    def __init__(self):
        self.root = input('请输入图片文件夹的绝对路径: ')
        self.count = 0
        self.pret()

    def pret(self):
        self.names = os.listdir(self.root)
        for i in self.names:
            pattern = re.compile('(.png|.jpg)$')
            if not re.search(pattern, i):
                self.names.remove(i)
        self.sum = len(self.names)
        self.size = sum([
            os.path.getsize(os.path.join(self.root, name)) for name in self.names
        ])
        self.size /= (1024*1024)

    def cont(self, name):
        path = os.path.join(self.root, name)
        im = Image.open(path)
        im = im.convert('RGB')
        im.save(os.path.join(self.root, name[:-4]+'.jpg'), quality=95)
        im.close()
        if '.png' in name:
            os.remove(path)
        else:
            pass

    def show(self, num, _sum,  runTime):
        barLen = 20  # 进度条的长度
        perFin = num/_sum
        numFin = round(barLen*perFin)
        numNon = barLen-numFin
        leftTime = (1-perFin)*(runTime/perFin)
        print(
            f"{num:0>{len(str(_sum))}}/{_sum}",
            f"|{'█'*numFin}{' '*numNon}|",
            f"任务进度: {perFin*100:.2f}%",
            f"已用时间: {runTime:.2f}S",
            f"剩余时间: {leftTime:.2f}S",
            end='\r')
        if num == _sum:
            print()
            sizeBefore = self.size
            self.pret()
            sizeAfter = self.size
            rate = sizeAfter/sizeBefore
            print(
                f"压缩前大小: {sizeBefore:.2f}MB",
                f"压缩后大小: {sizeAfter:.2f}MB",
                f"整体压缩率: {rate*100:.2f}%" # 压缩率越小越好
            )

    def main(self):
        tp = cf.ThreadPoolExecutor(32) # 设置线程数32
        futures = []
        startTime = time.time()
        for name in self.names:
            future = tp.submit(self.cont, name)
            futures.append(future)
        for future in cf.as_completed(futures):
            self.count += 1
            endTime = time.time()
            runTime = endTime-startTime
            self.show(self.count, self.sum, runTime)
        tp.shutdown()
        os.system('pause')


if __name__ == "__main__":
    ImageConvert().main()

温馨提示

为什么我们这里用多线程而不是多进程?

多进程适合处理CPU密集型任务(比如纯计算问题),而多线程适合解决IO密集型任务(比如文件读写操作)。

我们这里主要是读取图片,压缩图片,然后保存图片,显然CPU的占用率不高,而主要是硬盘/内存的读写操作。

引用参考

https://blog.csdn.net/youanyyou/article/details/78990156
https://blog.csdn.net/qq_42951560/article/details/109349309
posted @ 2020-11-11 15:43  XavierJ  阅读(381)  评论(0编辑  收藏  举报