用Python批量压缩图片来给你的手机相册瘦身
编辑时间:2021-05-13 作者:网络 浏览量:2251 来源:网络

我每次换手机都会把旧手机里的照片备份出来拷贝进新手机里,于是现在我的手机里面就有了几十个GB的照片。但是以手机摄像头的成像质量,一张照片动不动就5到10MB的尺寸实在是太浪费手机的存储空间了。

于是我开始在网上寻找能给相册瘦身的APP,终于我找到了一款叫“相册管家”的应用。这是一个腾讯出品的软件,功能非常多,照片压缩只是它附带的一个小功能。

经过几个小时的等待,我手机上30多个G的照片被压缩到了不到5个G。

虽然这个压缩比令我非常满意,但是我却发现了两个问题。

首先,这个软件默认的jpeg输出质量大约是60(根据尺寸推算),而且无法调整,虽然按这个压缩率输出的照片质量勉强能接受,但是仔细看还是能看出来明显的画质损失。

仔细看以上两张照片上天空的色彩,质量60的那张照片出现了明显的条纹。


下面这张图片是质量设置为80之后输出的照片,几乎跟原图没有肉眼可见的质量损失。


再来看看文件尺寸,原图8.69MB,质量80压缩后是2.01MB,质量60压缩之后是1.14MB。

综合考虑,我个人认为质量设置为80更合适一些。

画质问题勉强还能接受,最终让我卸载掉“相册管家”这个APP的原因是这个软件在压缩图片的时候居然把图像的Exif信息丢弃了。没有了Exif信息,手机相册APP就无法对照片按时间来排序,失去了时间排序这个重要功能之后,你就很难从上万张照片里找到你想要找的照片。这是绝对令人无法接受的!

怎么办?突然想到了最近热门的Python,据说入门超级简单,说干就干,马上下载了几本Python的入门教程,现学现用,自己撸了一个批量压缩图片的程序。


首先导入pillow这个模块:

from PIL import Image

然后压缩:

img = Image.open(file)
img.save(file, quality=80)

没错,只需要三行代码!python的图像的压缩就是这么简单!


不过上面的代码还是有一点小问题:跟“相册管家”一样,保存的图片没有exif信息。

别急,pillow的save方法默认是不保留exif信息的,想要保留exif信息,需要先读出图片的exif,然后作为参数传入到save里面。代码修改一下:

img = Image.open(file)
exif = img.info['exif']
img.save(file, exif=exif, quality=80)

大功告成!


不过上万张图片可不能一张图片一张图片的来处理,我们需要做一个批量处理:

先把压缩单张图片的代码写成一个函数(加入了try语句是为了在压缩出现错误的情况下,不中断操作,能继续处理下一个文件),然后使用glob.glob()来遍历目录下所有的jpg图片:

完整代码如下:

from PIL import Image


def zip_jpg(file):
try:
img = Image.open(file)
exif = img.info['exif']
img.save(file, exif=exif, quality=80)
return os.path.getsize(file)
except Exception as err:
print(err)
print(traceback.format_exc())
return 0


WORK_DIR = '/storage/emulated/0/DCIM/Camera'
JPG_FILTER = os.path.join(WORK_DIR, '*.[jJ][pP][gG]')

for file in glob.glob(JPG_FILTER):
filesize = os.path.getsize(file)
new_size = zip_jpg(file)
print('%s %d --> %d' % (os.path.split(file)[1], filesize, new_size))

一共17行代码,搞定!

可以在PC上运行,也可以在安卓手机上安装Pydroid 3来运行。


最后考虑到手机的相机图片相册里会经常新增图片,为了不每次运行程序的时候都把所有的图片文件都压缩一遍,我将代码进一步完善,加入了记录已压缩过的图片的功能,避免每次运行都重复压缩文件,最终代码如下:

from PIL import Image


WORK_DIR = '/storage/emulated/0/DCIM/Camera'
JPG_FILTER = os.path.join(WORK_DIR, '*.[jJ][pP][gG]')


def zip_jpg(file):
try:
img = Image.open(file)
exif = img.info['exif']
img.save(file, exif=exif, quality=80)
return os.path.getsize(file)
except Exception as err:
print(err)
print(traceback.format_exc())
return 0


def zip_jpgs():
filecount = 0
filetotal = len(glob.glob(JPG_FILTER))
zipped = set()
list_file = os.path.join(WORK_DIR, 'zipped.list')
with open(list_file, mode='a+', encoding='utf-8') as f:
f.seek(0)
for line in f.readlines():
line = line.strip()
if not line:
continue
zipped.add(line.split(',')[0])

for file in glob.glob(JPG_FILTER):
filecount += 1
if os.path.split(file)[1] in zipped:
print(os.path.split(file)[1], 'Already Zipped', '(%d/%d)' % (filecount, filetotal))
else:
filesize = os.path.getsize(file)
new_size = zip_jpg(file)
f.write('%s,%d,%d\n' % (os.path.split(file)[1], filesize, new_size))
print('%s %d --> %d (%d/%d)' % (os.path.split(file)[1], filesize, new_size, filecount, filetotal))


if __name__ == '__main__':
zip_jpgs()

最后,为了假装自己是个程序猿,我在GitHub注册了一个账号,把这几十行的代码Push了上去,瞬间感觉高大上了。

https://github.com/laukeng/jpeg


图片压缩的问题算是解决了,但是我又发现了一些新的问题:很多以前的手机拍摄的照片中exif信息不完整,或者exif中的拍摄时间是错误的,导致了相册里排序出现了混乱,还有就是很多照片的命名不统一(现在的智能手机会以“IMG_20191129_182330.jpg”这样的格式来给照片命名),下次我再做一个exif日期修复和文件名批量重命名的程序。

文章转自:https://www.fairysoft.net/post/35.html

来说两句吧