如何使用Python对Gif进行压缩

本文转载自微信公众号「arige」,作者arige。转载本文请联系arige公众号。

 一、背景

前天在给微信公众号上传文章的时候,文章里面有一个图片是gif的,在上传的过程中报错了,说是图片超大了。搜索之后发现图片需要小于5m。

那么问题就转化为怎么把当前的gif给缩减到5m以内本着有轮子用轮子,没有轮子造轮子的精神,网上搜索一番。

发现一些现象

1、压缩要不就是需要会员才能下载;

2、要不免费的只能压缩5m以下的。

考虑到能动手不花钱的本性,我觉得要自己搞一下。

知识背景:

众所周知,gif图就是由若干组图片组成的一种文件格式,有多张有一定差异的图片连续播放,间隔时间较小,欺骗了我们的眼睛和大脑,然后我们以为是一个完全连续的。其实就是一个类似快速翻书的操作。

二、方案选型

方案一

因为gif是有多种图片做的,那我们就考虑把图片减少一些,比如说原来是100张是10m,我给缩减到10张,那体积可不就要缩小到1m左右了吗?当然,为了用户看起来不是那么卡顿,我就拍脑袋给缩减到20张吧,即只有原来的1/5。

方案二

如果缩减的图片太多导致gif看起来卡顿的话,我们可以考虑不缩减图片的张数,但是我们可以压缩图片。

方案三

最后的都是重要的,如果前面两个都无法满足的话,那就可以考虑把他们进行叠加。先减张数,再压缩拆分的图片。

三、项目落实

整体流程如下:

 
 
 
  1. if __name__ == "__main__": 
  2.    # 设置源gif的地址 
  3.    sourceGifPath = "/Users/user/test/f79a3e2c2e864863a6b1a66791cb0950_tplv-k3u1fbpfcp-watermark.gif" 
  4.    # 将gif拆分成多个图片,并保存在本地 
  5.    SplitGif(sourceGifPath) 
  6.    # 将指定位置的文件下的图片按照文件名索引排序,做成gif 
  7.    Combine2Gif(sourceGifPath[:-4], sourceGifPath[:-4] + "_result.gif") 
  8.    print("== finished ==") 

1、将源gif读入内存

2、将gif拆分成png,并保存

 
 
 
  1. def SplitGif(gifPath): 
  2.    # 获取png存储的文件夹的地址 
  3.    pngDir = gifPath[:-4] 
  4.    # 要存储的文件夹下清理干净,避免影响当前操作 
  5.    rmPngDir(pngDir) 
  6.    # 创建存储的文件夹 
  7.    os.mkdir(pngDir) 
  8.    # 把指定gif拆分后存储到指定文件夹 
  9.    savePngToDir(gifPath, pngDir) 

2.1、获取要存储的地址

2.2、清空并移除存储png的文件夹

 
 
 
  1. def rmPngDir(pngDir): 
  2.    if os.path.exists(pngDir): 
  3.        files = os.listdir(pngDir) 
  4.        # 如果不一个一个的移除文件夹下的文件的话,无法移除文件夹 
  5.        for file in files: 
  6.            file = pngDir + "/" + file 
  7.            os.remove(file) 
  8.        os.rmdir(pngDir) 

2.3、创建存储png的文件夹

2.4、将gif拆分成png,并保存

 
 
 
  1. def savePngToDir(gifPath, pngDir): 
  2.    # 通过路径传教image对象 
  3.    image = Image.open(gifPath) 
  4.    try: 
  5.        # 循环,通过异常方案退出循环 
  6.        while True: 
  7.            # 获取当前的索引的位置 
  8.            current = image.tell() 
  9.            # 创建文件路径 
  10.            pngPath = pngDir + '/' + str(current) + '.png' 
  11.            image.save(pngPath, quality=100) 
  12.            # 索引后移,越界后异常,退出当前循环 
  13.            image.seek(current + 1) 
  14.    except EOFError as e: 
  15.        print(e) 
  16.        pass 

3、按照一定的间隔读取2中的png,并生成gif

 
 
 
  1. def Combine2Gif(folderPath, gifFilePath): 
  2.    GenerateGif(0.1, gifFilePath, getPngArray(folderPath)) 

3.1、获取所有的png

 
 
 
  1. def getPngArray(folderPath): 
  2.    files = os.listdir(folderPath) 
  3.    pngFiles = [] 
  4.    # 通过设置step,将文件的大小修改为原来的体积的1/step 
  5.    for i in range(0, len(files), 5): 
  6.        pngFiles.append(folderPath + "/" + ('%d.png' % i)) 
  7.    return pngFiles 

3.2、将png合并成gif

 
 
 
  1. def GenerateGif(step, gifPath, filterPngs): 
  2.    images = [] 
  3.    for filePath in filterPngs: 
  4.        images.append(imageio.imread(filePath)) 
  5.    # 生成gif,duration 是播放两个图片之间的间隔时间 
  6.    imageio.mimsave(gifPath, images, duration=step) 

四、全部的代码

 
 
 
  1. #! /usr/local/bin/python3 
  2. # -*- coding: utf-8 -*- 
  3. from PIL import Image 
  4. import os 
  5. import imageio 
  6.  
  7.  
  8. def SplitGif(gifPath): 
  9.    # 获取png存储的文件夹的地址 
  10.    pngDir = gifPath[:-4] 
  11.    # 要存储的文件夹下清理干净,避免影响当前操作 
  12.    rmPngDir(pngDir) 
  13.    # 创建存储的文件夹 
  14.    os.mkdir(pngDir) 
  15.    # 把指定gif拆分后存储到指定文件夹 
  16.    savePngToDir(gifPath, pngDir) 
  17.  
  18.  
  19. def rmPngDir(pngDir): 
  20.    if os.path.exists(pngDir): 
  21.        files = os.listdir(pngDir) 
  22.        # 如果不一个一个的移除文件夹下的文件的话,无法移除文件夹 
  23.        for file in files: 
  24.            file = pngDir + "/" + file 
  25.            os.remove(file) 
  26.        os.rmdir(pngDir) 
  27.  
  28.  
  29. def savePngToDir(gifPath, pngDir): 
  30.    # 通过路径传教image对象 
  31.    image = Image.open(gifPath) 
  32.    try: 
  33.        # 循环,通过异常方案退出循环 
  34.        while True: 
  35.            # 获取当前的索引的位置 
  36.            current = image.tell() 
  37.            # 创建文件路径 
  38.            pngPath = pngDir + '/' + str(current) + '.png' 
  39.            image.save(pngPath, quality=100) 
  40.            # 索引后移,越界后异常,退出当前循环 
  41.            image.seek(current + 1) 
  42.    except EOFError as e: 
  43.        print(e) 
  44.        pass 
  45.  
  46.  
  47. def Combine2Gif(folderPath, gifFilePath): 
  48.    GenerateGif(0.1, gifFilePath, getPngArray(folderPath)) 
  49.  
  50.  
  51. # 获取文件的数组 
  52. def getPngArray(folderPath): 
  53.    files = os.listdir(folderPath) 
  54.    pngFiles = [] 
  55.    # 通过设置step,将文件的大小修改为原来的体积的1/step 
  56.    for i in range(0, len(files), 5): 
  57.        pngFiles.append(folderPath + "/" + ('%d.png' % i)) 
  58.    return pngFiles 
  59.  
  60.  
  61. def GenerateGif(step, gifPath, filterPngs): 
  62.    images = [] 
  63.    for filePath in filterPngs: 
  64.        images.append(imageio.imread(filePath)) 
  65.    # 生成gif,duration 是播放两个图片之间的间隔时间 
  66.    imageio.mimsave(gifPath, images, duration=step) 
  67.  
  68.  
  69. if __name__ == "__main__": 
  70.    # 设置源gif的地址 
  71.    sourceGifPath = "/Users/user/test/f79a3e2c2e864863a6b1a66791cb0950_tplv-k3u1fbpfcp-watermark.gif" 
  72.    # 将gif拆分成多个图片,并保存在本地 
  73.    SplitGif(sourceGifPath) 
  74.    # 将指定位置的文件下的图片按照文件名索引排序,做成gif 
  75.    Combine2Gif(sourceGifPath[:-4], sourceGifPath[:-4] + "_result.gif") 
  76.    print("== finished ==") 

五、结尾

作为一个追求高效的程序员,我就做一个能满足我需求的方案,即方案一。至于方案二和方案三,有兴趣的朋友可以举一反三。

新闻名称:如何使用Python对Gif进行压缩
当前URL:http://www.shufengxianlan.com/qtweb/news34/445884.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联