注:本文基于CentOS 7.2系统操作,使用的python版本为:2.7.5
最近在发gif表情的时候发现有些动图太大了,一发就占了一整屏,不太舒服,想着有啥办法能缩小gif的大小,于是乎想起了python。
大概了解了一下,需要使用到PIL的Image和ImageSequence模块,但是这里有一个天坑,让我折腾了一天的时间。。。
那就是:原生PIL不支持gif的保存,需要使用pillow。
因为这,我缩小后的gif只有一帧,还动不了,我还以为是我代码哪里错了,so sad。
pip install pillow
对,就只需要这么一个语句。
废话不多说,上代码。
#!/usr/bin/env python
from PIL import Image, ImageSequence
import sys, os
if len(sys.argv) < 3:
print("input invalid!")
print("you need input ingif and outgif.")
exit(1)
inf = sys.argv[1]
outf = sys.argv[2]
gif = Image.open(inf)
dura = gif.info['duration']
imgs = [f.copy() for f in ImageSequence.Iterator(gif)]
index = 0
imglist = []
os.mkdir("images")
for frame in imgs:
frame.save("./images/%d.png" % index)
im = Image.open("./images/%d.png" % index)
im.thumbnail((128,128), Image.ANTIALIAS)
imglist.append(im)
index += 1
os.system("rm -rf ./images")
imglist[0].save(outf, 'gif', save_all=True, append_images=imglist[1:], loop=0, duration=dura)
gif图片压缩的思路大概就是:获取gif的每一帧,将每一帧图片缩小,然后将缩小的图片重新合成gif图片。
1、获取帧信息
使用ImageSequence模块的迭代器去遍历gif动图的每一帧,然后放到imgs列表里。
imgs = [f.copy() for f in ImageSequence.Iterator(gif)]
上述语句相当于下面的简写:
for f in ImageSequence.Iterator(gif):
imgs.append(f.copy())
2、将帧信息保存为静态图片
frame.save("./images/%d.png" % index)
上一个步骤我们已经获取了动图的帧信息,这里使用save方法,将帧信息保存为png图片。
是否能保存为jpg格式呢?答案是不能,如果需要将其保存为jpg格式,需要先将帧信息转成RGB格式,然后才能保存为jpg格式。
frame = frame.convert('RGB')
frame.save("./images/%d.jpg" % index)
这是什么原因呢?据我考证(不一定正确),帧信息的通道和PNG通道一样,有四个通道,与平常的RGB三通道不同,多了一个A通道,用于表示黑白灰通道。因此如果直接转换为jpg格式,多的一个A通道不知道如何处理。
3、压缩图片
其实就是改变图片尺寸大小。
im.thumbnail((128,128), Image.ANTIALIAS)
thumbnail方法就是生成指定尺寸的缩略图。其中(128,128)表示缩小后的尺寸,Image.ANTIALIAS表示图片的质量。这个方法和resize类似。
4、重新合成gif
处理完所有图片后,就需要将所有帧信息重新合成。
imglist[0].save(outf, 'gif', save_all=True, append_images=imglist[1:], loop=0, duration=dura)
这里使用的还是save方法,不过参数多了几个。通过设定save_all=True参数和 append_images,可以一次性将多帧图像同时存入GIF图片。还有一个duration参数控制的是帧率,我们可以直接从原图片中获取该信息。
dura = gif.info['duration']
除了帧率,gif.info返回的信息还有很多其他信息,
{'background': 0, 'extension': ('NETSCAPE2.0', 803), 'version': 'GIF89a', 'transparency': 23, 'duration': 60, 'loop': 0}
另外,loop参数也很重要,如果没设置这个参数会出现动图动一会儿就不动的情况。
这样,我们就把大的gif图片缩小了,效果如下。