我经常使用ScreenToGif工具生成GIF动图,有的时候GIF生成的比较大,互联网上有很多在线GIF压缩工具,但是有些不能用,有些速度慢。。。有没有本地工具压缩GIF呢?其实是有的,那就是Gifsicle。
一、Gifsicle
Gifsicle是一个命令行工具,能够创建、编辑GIF动图。
官网地址:https://www.lcdf.org/gifsicle/
下载地址:https://eternallybored.org/misc/gifsicle/
完整的使用手册:https://www.lcdf.org/gifsicle/man.html
1、安装
安装比较简单,下载下来之后将命令行工具目录添加到Path就可以了,运行gifsicle --version
命令,出现如下界面就表示安装成功了:

2、使用
使用手册上的内容比较多,我们只关心关于能压缩GIF体积的参数。
--optimize:最重要的优化参数,能有效压缩GIF大小,使用方式为-O{level}
,level为1、2、3其中一种,数字越大,压缩效果越好,但是耗时也更长,一般想要更好的压缩效果,使用-O3
即可。
--colors:减小GIF中使用到的颜色数量到指定数量,通过减小改值,可以有效减小GIF体积。使用方式:--colors={num}
,num必须是2到256之间的值。
--lossy:有损度,默认值大小为20,该值越大,生成的GIF体积越小,使用方式:--lossy={num}
这样,如果我们想压缩一张GIF动图,可以使用如下命令:
gifsicle -O3 --lossy=100 --colors=64 input.gif -o output.gif
二、python脚本
为了更方便的使用gifsicle工具,我写了一个python脚本。
需要先安装依赖:pip install tkinter rich
完整代码如下所示:
import sys
import tkinter as tk
from tkinter import filedialog, messagebox
import os
import subprocess
from pathlib import Path
import time
from rich.progress import Progress
"""
这是一个压缩gif图像的python脚本
"""
#默认存放GIF动图的目录,需要修改成自己的
default_work_dir = "E:\\动图"
run_mode = 1
def choose_gif_files():
# 创建Tkinter根窗口并隐藏
root = tk.Tk()
root.withdraw()
# 配置文件对话框参数
file_path = filedialog.askopenfilename(
title="请选择动图文件", # 对话框标题
initialdir=os.path.expanduser(default_work_dir), # 初始目录为用户主目录
filetypes=[ # 文件类型过滤
("动图文件", "*.gif")
],
# multiple=True
)
# 销毁根窗口
root.destroy()
return file_path
def do_process_file(file):
path = Path(file)
parent_path = path.parent
origin_file_name = path.name
split_parts = origin_file_name.split(".")
new_file_path = parent_path.joinpath(f"{split_parts[0]}_resize.{split_parts[1]}")
lossy = input("--lossy(默认300,越大压缩效果越好):")
colors = input("--colors(默认64,越小压缩效果越好,但是图片可能会失真):")
print(f"正在处理文件{file}的转换......")
result = subprocess.Popen(
[
"gifsicle",
"-O3",
f"--lossy={300 if not lossy else lossy}",
f"--colors={64 if not colors else colors}",
"--no-extensions",
str(file).replace("/", "\\"),
"-o",
new_file_path.absolute()
],
stdout=subprocess.PIPE,
text=True
)
# 逐行读取输出
while True:
output = result.stdout.readline()
if output == "" and result.poll() is not None:
break
if output:
print(output.strip())
# 获取返回码
return_code = result.poll()
if return_code == 0:
return path, new_file_path
else:
return path, None
def open_dir(file_path):
try:
subprocess.Popen(f'explorer /select, "{file_path.absolute()}"', shell=True)
except Exception as e:
messagebox.showerror("错误", f"无法打开资源管理器:{e}")
def format_size(bytes_num):
"""
将字节数转换为自适应单位(KB/MB/GB等)
:param bytes_num: 文件字节数,支持负数
:return: 带单位的格式化字符串
"""
units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
sign = '-' if bytes_num < 0 else ''
size = abs(bytes_num)
index = 0
while size >= 1024 and index < len(units) - 1:
size /= 1024.0
index += 1
return f"{sign}{size:.2f} {units[index]}"
def print_origin_and_new_file_diff_info(origin_file_path: Path, new_file_path: Path):
origin_file_size = origin_file_path.stat().st_size
new_file_size = new_file_path.stat().st_size
print(
f"源文件大小:{format_size(origin_file_size)},新文件大小:{format_size(new_file_size)},"
f"节约{(((origin_file_size - new_file_size) / origin_file_size) * 100):.2f}%的空间"
)
def process():
file_path = choose_gif_files()
# 处理用户选择结果
if not file_path:
print("用户取消选择")
return
origin_file_path, new_file_path = do_process_file(file_path)
if new_file_path:
print_origin_and_new_file_diff_info(origin_file_path, new_file_path)
open_result_dir_flag = input(f"转换后文件:{new_file_path.absolute()},是否打开转换后目标文件夹(y/n)?")
if open_result_dir_flag == 'n' or open_result_dir_flag == 'N':
return
else:
open_dir(new_file_path)
else:
print("转换失败")
def exit_program():
with Progress() as progress:
# 创建一个隐藏进度条的任务(总时间为3秒)
task = progress.add_task(
description="[bold red]即将退出程序... (5)", # 初始描述
total=5,
visible=True,
)
for remaining in range(5, 0, -1):
# 更新描述中的倒计时数字
progress.update(
task,
description=f"[bold red]即将退出程序... ({remaining})",
advance=1,
refresh=True
)
time.sleep(1) # 等待1秒
sys.exit(0)
if __name__ == '__main__':
while True:
process()
if run_mode == 1:
exit_program()
break
continue_flag = input("是否继续转换(y/n)?")
if continue_flag == 'n' or continue_flag == 'N':
exit_program()
continue
运行结果如下:

注意:本文归作者所有,未经作者允许,不得转载