PancrasL的博客

使用python批量压缩图片

2021-06-04

General 1920x1080 cats blue eyes animals boxes Ben Torode wooden surface mammals carton box indoors looking at viewer

1. 依赖安装

1
$ pip3 install pillow

2. 图片压缩

2.1 PIL库图片插值的四种模式

Nearest (最近相邻插值算法/最近邻法)

  • 特点:缺少的像素通过直接使用与之最接近的原有像素的颜色生成,也就是照搬旁边的像素。
  • 优点:速度快。
  • 缺点:精度低,有明显的锯齿感。
1
2
3
from PIL import Image
img = Image.open(filename)
img.thumbnail((w,h), Image.NEAREST)

Bilinear(两次线性插值算法/双线性内插法)

  • 特点:通过平均周围像素颜色来添加像素的方法。
  • 优点:消除了锯齿现象,效果中等。
  • 缺点:效果中等。
1
2
3
from PIL import Image
img = Image.open(filename)
img.thumbnail((w,h), Image.BILINEAR)

Bicubic(两次立方插值算法/立方卷积法)

  • 特点:Bilinear的改进版,不仅考虑到四个直接邻点灰度值的影响,还考虑到各邻点间灰度值变化率的影响。
  • 优点:计算精度很高,处理后图像像质损失较小。
  • 缺点:速度慢。
1
2
3
from PIL import Image
img = Image.open(filename)
img.thumbnail((w,h), Image.BICUBIC)

Antialias(Lanczos算法)

  • 特点:几个简单过滤器中的最佳折中方案。
  • 优点:AntialiasBicubic的速度要快。
  • 缺点:没有Bicubic清晰。
1
2
3
from PIL import Image
img = Image.open(filename)
img.thumbnail((w,h), Image.LANCZOS)

2.2 Image.resize()Image.thumbnail()

  • resize():将图片尺寸修改为size
  • thumbnail():如果图像原尺寸大于size,则在保留宽高比的前提下缩小为size;如果图像原尺寸大于size,则尺寸不变。

2.3 代码流程图

image-20210604203014721

2.3 压缩代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# -*- coding: utf-8 -*-

import os
from PIL import Image
import glob

dir = 'E:\\Album Test\\test\\'
patterns = ['*.jpg', "*.png"]


def compressImage():
files = collectFiles(dir, patterns)
for f in files:
img = doCompress(f)

# 在同级目录下的compress目录,用于存放压缩后的图片
compress_dir = "%s/compress/" % os.path.dirname(f)
if not os.path.exists(compress_dir):
os.makedirs(compress_dir)
new_fname = os.path.join(compress_dir, os.path.basename(f))

saveImg(img, new_fname)


def collectFiles(dir, patterns):
# 获取图片文件全路径
files = []
for p in patterns:
files += (glob.glob('%s%s%s' % (dir, '**\\', p), recursive=True))

# 替换win路径为linux路径
for i in range(len(files)):
files[i] = files[i].replace('\\', '/')

return files


def doCompress(filename):
sImg = Image.open(filename)
w, h = sImg.size

sImg.thumbnail((w,h), Image.BICUBIC)

return sImg

def saveImg(img, filename):
img.save(filename)


if __name__ == "__main__":
compressImage()

2.4 压缩代码(通过读取图片旋转信息避免图片压缩后被旋转)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# -*- coding: utf-8 -*-

import os
from PIL import Image, ExifTags
import glob

dir = 'E:/Album Test/public/'
patterns = ['*.jpg', "*.png"]


def compressImage():
files = collectFiles(dir, patterns)
for f in files:
img = doCompress(f)

# # 将压缩后的图片存放在同级目录下的compress文件夹下
# compress_dir = "%s/compress/" % os.path.dirname(f)
# if not os.path.exists(compress_dir):
# os.makedirs(compress_dir)
# new_fname = os.path.join(compress_dir, os.path.basename(f))
saveImg(img, f)


def collectFiles(dir, patterns):
# 获取图片文件全路径
files = []
for p in patterns:
files += (glob.glob('%s%s%s' % (dir, '**\\', p), recursive=True))

# 替换win路径为linux路径
for i in range(len(files)):
files[i] = files[i].replace('\\', '/')

return files


def doCompress(filename):
img = Image.open(filename)

# 找到图像旋转信息 exif: Exchangeable image file format
for k in ExifTags.TAGS.keys():
if(ExifTags.TAGS[k] == 'Orientation'):
if hasattr(img, '_getexif') and hasattr(img._getexif(), 'items'):
exif = dict(img._getexif().items())
if exif[k] == 3:
img = img.rotate(180, expand=True)
elif exif[k] == 6:
img = img.rotate(270, expand=True)
elif exif[k] == 8:
img = img.rotate(90, expand=True)

# 旋转
w, h = img.size
#sImg.thumbnail((w,h), Image.BICUBIC)
img.thumbnail((2000, 1500), Image.BICUBIC)
return img


def saveImg(img, filename):
img.save(filename)
print(filename, "压缩成功")


if __name__ == "__main__":
compressImage()