如何使用Python对Gif进行压缩

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

[[426653]]

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

 一、背景

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

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

发现一些现象

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

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

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

知识背景:

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

二、方案选型

方案一

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

方案二

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

方案三

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

三、项目落实

整体流程如下:

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

1、将源gif读入内存

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

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

2.1、获取要存储的地址

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

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

2.3、创建存储png的文件夹

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

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

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

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

3.1、获取所有的png

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

3.2、将png合并成gif

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

四、全部的代码

#! /usr/local/bin/python3 
# -*- coding: utf-8 -*- 
from PIL import Image 
import os 
import imageio 
 
 
def SplitGif(gifPath): 
   # 获取png存储的文件夹的地址 
   pngDir = gifPath[:-4] 
   # 要存储的文件夹下清理干净,避免影响当前操作 
   rmPngDir(pngDir) 
   # 创建存储的文件夹 
   os.mkdir(pngDir) 
   # 把指定gif拆分后存储到指定文件夹 
   savePngToDir(gifPath, pngDir) 
 
 
def rmPngDir(pngDir): 
   if os.path.exists(pngDir): 
       files = os.listdir(pngDir) 
       # 如果不一个一个的移除文件夹下的文件的话,无法移除文件夹 
       for file in files: 
           file = pngDir + "/" + file 
           os.remove(file) 
       os.rmdir(pngDir) 
 
 
def savePngToDir(gifPath, pngDir): 
   # 通过路径传教image对象 
   image = Image.open(gifPath) 
   try: 
       # 循环,通过异常方案退出循环 
       while True
           # 获取当前的索引的位置 
           current = image.tell() 
           # 创建文件路径 
           pngPath = pngDir + '/' + str(current) + '.png' 
           image.save(pngPath, quality=100) 
           # 索引后移,越界后异常,退出当前循环 
           image.seek(current + 1) 
   except EOFError as e: 
       print(e) 
       pass 
 
 
def Combine2Gif(folderPath, gifFilePath): 
   GenerateGif(0.1, gifFilePath, getPngArray(folderPath)) 
 
 
# 获取文件的数组 
def getPngArray(folderPath): 
   files = os.listdir(folderPath) 
   pngFiles = [] 
   # 通过设置step,将文件的大小修改为原来的体积的1/step 
   for i in range(0, len(files), 5): 
       pngFiles.append(folderPath + "/" + ('%d.png' % i)) 
   return pngFiles 
 
 
def GenerateGif(step, gifPath, filterPngs): 
   images = [] 
   for filePath in filterPngs: 
       images.append(imageio.imread(filePath)) 
   # 生成gif,duration 是播放两个图片之间的间隔时间 
   imageio.mimsave(gifPath, images, duration=step) 
 
 
if __name__ == "__main__"
   # 设置源gif的地址 
   sourceGifPath = "/Users/user/test/f79a3e2c2e864863a6b1a66791cb0950_tplv-k3u1fbpfcp-watermark.gif" 
   # 将gif拆分成多个图片,并保存在本地 
   SplitGif(sourceGifPath) 
   # 将指定位置的文件下的图片按照文件名索引排序,做成gif 
   Combine2Gif(sourceGifPath[:-4], sourceGifPath[:-4] + "_result.gif"
   print("== finished =="
  • 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.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.

五、结尾

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

 

责任编辑:武晓燕 来源: arige
相关推荐

2017-09-26 19:02:09

PythonInstagram数据分析

2010-02-02 14:11:14

Python 进行编程

2022-11-07 07:54:05

微服务数据库网关

2023-07-05 07:36:36

SpringJava代码

2010-06-04 13:50:24

MySQL存储过程

2019-10-11 18:27:18

APK资源压缩

2021-11-26 08:45:06

NetworKi网络安全分析安全工具

2014-05-21 09:14:00

VDI审计日志监控监控

2013-03-02 18:00:38

软件加密软件授权WinLicense

2021-05-09 22:48:40

SQL数据库变量

2023-12-12 07:30:54

IstioWasm前端

2020-10-15 12:00:01

Python 开发编程语言

2023-04-12 08:00:00

人工智能ChatGPTPython

2021-02-22 13:44:41

开发Python金融

2014-05-21 14:03:55

日志监控VDI

2021-11-04 05:43:38

GoKartGo代码静态安全分析

2011-01-20 10:33:30

Postfix

2023-01-30 08:30:09

Tomcat性能优化

2022-11-02 14:45:24

Python数据分析工具

2021-06-15 20:59:14

Kubernetes调试容器
点赞
收藏

51CTO技术栈公众号