Python实现批量图片转GIF动图(附源代码)

 更新时间:2026年04月15日 08:51:18   作者:躬行见万象  
本文介绍了一个Python实现的批量图片转GIF工具,提供简洁版和专业版两种实现方案,该工具支持从指定目录读取PNG/JPG/BMP等格式图片,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

本文分享如何实现 批量图片转 GIF 动图:

关键内容

  1. 支持 PNG/JPG/BMP 等主流图片格式,自动过滤非图片文件;
  2. 参数灵活配置输入目录、输出路径、GIF 帧率(FPS)、图像名称顺序循环次数
  3. 自动处理图片格式兼容问题,并包含完善的异常提示。
  4. 多维度轻量化压缩,支持 0.1-1.0 缩放因子调整图片大小。

运行效果:

简洁版

首先分享的是简洁版,一个批量图片转GIF动图的Python脚本,基于PIL库实现。

代码的参数配置:

阶段关键操作说明
参数解析argparse支持输入目录、输出路径、FPS、循环次数、排序方式
文件筛选os.listdir + 后缀过滤仅保留支持的5种图片格式
智能排序re.search(r'\d+')提取文件名中的数字进行排序,处理如 frame_001.png
图像处理Image.open → convert('RGB')统一转RGB,解决透明通道兼容问题
GIF生成images[0].save(save_all=True)首帧保存,其余帧append
目录处理os.makedirs(exist_ok=True)自动创建不存在的输出目录

思路流程:

源代码:

import os
import argparse
import re
from PIL import Image

def create_gif(image_folder, output_path, fps=10, loop=0, sort_order='asc'):
    """
    从指定目录的图片创建GIF动图
    参数:
    image_folder (str): 图片目录路径
    output_path (str): GIF输出路径
    fps (int/float): 每秒帧数,默认0.5
    loop (int): 循环次数(0=无限),默认0
    sort_order (str): 排序方式(asc=升序/desc=降序),默认asc
    """
    # 支持的图片格式
    IMAGE_EXTS = ('.png', '.jpg', '.jpeg', '.bmp', '.webp')
    
    # 筛选目录内的图片文件
    image_files = [
        os.path.join(image_folder, f) 
        for f in os.listdir(image_folder) 
        if f.lower().endswith(IMAGE_EXTS)
    ]
    
    if not image_files:
        raise ValueError(f"目录 '{image_folder}' 未找到图片文件")
    
    # 提取文件名中的数字作为排序依据
    def sort_key(filename):
        basename = os.path.basename(filename)
        match = re.search(r'\d+', basename)
        return int(match.group()) if match else basename
    
    # 根据参数切换升/降序排序
    reverse_flag = True if sort_order == 'desc' else False
    image_files.sort(key=sort_key, reverse=reverse_flag)
    
    # 打印排序后的图片列表
    print(f"找到 {len(image_files)} 张图片,排序方式: {sort_order}")
    for i, f in enumerate(image_files):
        print(f"  {i+1}. {os.path.basename(f)}")
    
    # 打开并处理图片(转RGB兼容透明通道)
    images = []
    for img_path in image_files:
        try:
            img = Image.open(img_path)
            img = img.convert('RGB')  # 统一转为RGB模式
            images.append(img)
        except Exception as e:
            print(f"警告: 无法打开图片 {img_path} - {e}")
    
    if not images:
        raise ValueError("无可用图片文件")
    
    # 计算每帧持续时间(毫秒)
    duration = 1000 / fps
    
    # 保存GIF
    images[0].save(
        output_path,
        save_all=True,
        append_images=images[1:],
        duration=duration,
        loop=loop
    )
    
    # 打印生成结果
    print(f"\nGIF已保存至: {output_path}")
    print(f"帧率: {fps} FPS | 图片数量: {len(images)} | 循环次数: {'无限' if loop == 0 else loop}")

def main():
    # 命令行参数解析
    parser = argparse.ArgumentParser(description='批量图片转GIF动图工具')
    parser.add_argument('--input_dir', default='./coco_test/', help='输入图片目录(默认: ./coco_test/)')
    parser.add_argument('--output_file', default='Output_GIF/coco_test-202601.gif', help='输出GIF文件路径')
    parser.add_argument('-f', '--fps', type=float, default=0.5, help='每秒帧数(默认: 0.5)')
    parser.add_argument('-l', '--loop', type=int, default=0, help='循环次数(0=无限,默认: 0)')
    parser.add_argument('-s', '--sort_order', choices=['asc', 'desc'], default='asc', help='排序方式(asc=升序/desc=降序,默认: asc)')
    
    args = parser.parse_args()
    
    # 校验输入目录是否存在
    if not os.path.isdir(args.input_dir):
        print(f"错误: 输入目录 '{args.input_dir}' 不存在")
        return
    
    # 自动补全GIF扩展名
    if not args.output_file.lower().endswith('.gif'):
        args.output_file += '.gif'
    
    # 自动创建输出目录(如果不存在)
    output_dir = os.path.dirname(args.output_file)
    if output_dir and not os.path.exists(output_dir):
        os.makedirs(output_dir, exist_ok=True)
        print(f"提示: 自动创建输出目录 '{output_dir}'")
    
    # 生成GIF
    try:
        create_gif(args.input_dir, args.output_file, args.fps, args.loop, args.sort_order)
    except Exception as e:
        print(f"错误: {e}")

if __name__ == "__main__":
    main()

打印信息:

找到 5 张图片,排序方式: asc
  1. 000000000030.jpg
  2. 000000000034.jpg
  3. 000000000192.jpg
  4. 000000000247.jpg
  5. 000000000307.jpg

GIF已保存至: Output_GIF/coco_test-202601.gif
帧率: 0.5 FPS | 图片数量: 5 | 循环次数: 无限

运行效果:

专业版

这是一个增强版批量图片转GIF工具,相比之前的基础版本,新增了压缩优化、尺寸缩放、颜色量化等专业功能。

核心功能对比:

特性基础版增强版(本代码)
图片转GIF
智能数字排序
透明通道处理❌(直接转RGB)✅(白色背景填充)
尺寸缩放✅(LANCZOS重采样)
颜色量化✅(MedianCut算法,1-256色)
帧差异优化✅(optimize参数)
压缩级别控制✅(0-9级)
调色板质量✅(1-100)
尺寸一致性校验✅(打印警告)

这是一款功能全面、高度可定制的批量图片转 GIF 工具,覆盖从图片预处理到 GIF 优化的全流程,核心能力如下:

  1. 核心生成:灵活可控的 GIF 创建

    • 读取指定目录下 PNG/JPG/BMP/WebP 等主流格式图片,支持通过-s/--sort_order参数一键切换文件名升序 / 降序排序;
    • 自定义帧率(FPS)、循环次数(0 = 无限循环),满足不同播放节奏需求。
  2. 预处理:智能兼容 & 规整图片

    • 自动处理 RGBA 透明图片:将透明背景转为白色,避免 GIF 背景异常;
    • 校验所有图片尺寸一致性,尺寸不符时给出明确警告,保障动图显示效果;
    • 支持 0.1-1.0 缩放因子调整图片大小,平衡 GIF 清晰度与文件体积。
  3. 优化:多维度轻量化压缩

    • 可选颜色数精简:通过中值切割算法限制最大颜色数(1-256),大幅降低 GIF 体积;
    • 帧优化 + 多级压缩:启用帧差异编码、自定义压缩级别(0-9)、调色板质量(1-100),兼顾画质与压缩率;
    • 内置 Floyd-Steinberg 抖动算法,减少颜色精简后的画面失真。

源代码:

import os
import argparse
import re
from PIL import Image
import numpy as np

def create_gif(image_folder, output_path, fps=10, loop=0, 
               reduce_colors=True, max_colors=256, 
               optimize_frames=True, resize_factor=1.0, 
               compress_level=6, quality=85, sort_order='asc'):
    """
    从指定目录图片创建GIF动图(支持压缩/缩放/调色)
    参数:
    image_folder (str): 图片目录路径
    output_path (str): GIF输出路径
    fps (int/float): 每秒帧数,默认10
    loop (int): 循环次数(0=无限),默认0
    reduce_colors (bool): 是否减少颜色数,默认True
    max_colors (int): 最大颜色数(1-256),默认256
    optimize_frames (bool): 是否优化帧(差异编码),默认True
    resize_factor (float): 缩放因子(0.1-1.0),默认1.0(不缩放)
    compress_level (int): 压缩级别(0-9),默认6
    quality (int): 调色板质量(1-100),默认85
    sort_order (str): 排序方式(asc=升序/desc=降序),默认asc
    """
    # 支持的图片格式
    IMAGE_EXTS = ('.png', '.jpg', '.jpeg', '.bmp', '.webp')
    
    # 筛选目录内的图片文件
    image_files = [
        os.path.join(image_folder, f) 
        for f in os.listdir(image_folder) 
        if f.lower().endswith(IMAGE_EXTS)
    ]
    
    if not image_files:
        raise ValueError(f"目录 '{image_folder}' 未找到图片文件")
    
    # 提取文件名中的数字作为排序依据
    def sort_key(filename):
        basename = os.path.basename(filename)
        match = re.search(r'\d+', basename)
        return int(match.group()) if match else basename
    
    # 根据参数切换升/降序排序
    reverse = True if sort_order == 'desc' else False
    image_files.sort(key=sort_key, reverse=reverse)
    
    # 打印排序结果
    print(f"找到 {len(image_files)} 张图片,排序方式: {sort_order}")
    for i, f in enumerate(image_files):
        print(f"  {i+1}. {os.path.basename(f)}")
    
    # 加载并统一图片格式/尺寸
    images = []
    first_size = None
    
    for img_path in image_files:
        try:
            img = Image.open(img_path)
            
            # 校验图片尺寸一致性
            if first_size is None:
                first_size = img.size
                print(f"\n基准尺寸: {first_size[0]}x{first_size[1]}")
            elif img.size != first_size:
                print(f"警告: 图片 {os.path.basename(img_path)} 尺寸 {img.size} 与基准不一致")
            
            # 处理透明通道(转为白色背景)
            if img.mode == 'RGBA':
                background = Image.new('RGB', img.size, (255, 255, 255))
                background.paste(img, mask=img.split()[-1])
                img = background
            else:
                img = img.convert('RGB')
            
            images.append(img)
            
        except Exception as e:
            print(f"警告: 无法打开图片 {img_path} - {e}")
    
    if not images:
        raise ValueError("无可用图片文件")
    
    print(f"\n成功加载 {len(images)} 张图片")
    
    # 图片缩放(按需)
    if resize_factor != 1.0 and 0.1 <= resize_factor <= 1.0:
        new_size = (int(first_size[0] * resize_factor), 
                   int(first_size[1] * resize_factor))
        print(f"缩放图片: {first_size} → {new_size} (缩放因子: {resize_factor})")
        
        for i in range(len(images)):
            images[i] = images[i].resize(new_size, Image.Resampling.LANCZOS)
    
    # 减少颜色数(按需)
    if reduce_colors and max_colors < 256:
        print(f"减少颜色数至 {max_colors} 色")
        
        for i in range(len(images)):
            images[i] = images[i].quantize(colors=max_colors, 
                                           method=Image.Quantize.MEDIANCUT)
            images[i] = images[i].convert('RGB')
    
    # 计算每帧时长(毫秒)
    duration = 1000 / fps
    
    # 自动创建输出目录(不存在时)
    output_dir = os.path.dirname(os.path.abspath(output_path))
    if output_dir:
        os.makedirs(output_dir, exist_ok=True)
        print(f"\n输出目录已确保存在: {output_dir}")
    
    # 生成并保存GIF(带优化参数)
    print("正在生成GIF文件...")
    images[0].save(
        output_path,
        save_all=True,
        append_images=images[1:],
        duration=duration,
        loop=loop,
        optimize=optimize_frames,
        compress_level=compress_level,
        quality=quality,
        disposal=2,
        dither=Image.Dither.FLOYDSTEINBERG
    )
    
    # 输出生成结果
    file_size = os.path.getsize(output_path) / (1024 * 1024)
    print(f"\n✅ GIF已保存至: {output_path}")
    print(f"📦 文件大小: {file_size:.2f} MB | 🎞️ 帧率: {fps} FPS (每帧 {duration:.1f}ms)")
    print(f"🖼️ 图片数量: {len(images)} | 🔁 循环次数: {'无限' if loop == 0 else loop}")
    if resize_factor != 1.0:
        print(f"🔍 缩放因子: {resize_factor}")
    if reduce_colors:
        print(f"🎨 颜色数限制: {max_colors}")
    print(f"🗜️ 压缩级别: {compress_level} | 📊 质量设置: {quality}")

def main():
    # 命令行参数解析
    parser = argparse.ArgumentParser(description='GIF生成工具(支持压缩/缩放/调色/排序)')
    parser.add_argument('--input_dir', default='./THUD_Robot_data/', help='输入图片目录(默认: ./Gif_bev_Global_Graph_Range/)')
    parser.add_argument('--output_file', default='Output_GIF/THUD_Robot_data-test.gif', help='输出GIF文件路径')
    parser.add_argument('-f', '--fps', type=float, default=0.5, help='每秒帧数(默认: 0.5)')
    parser.add_argument('-l', '--loop', type=int, default=0, help='循环次数(0=无限,默认: 0)')
    parser.add_argument('-s', '--sort_order', choices=['asc', 'desc'], default='asc',help='排序方式(asc=升序/desc=降序,默认: asc)')
    
    # 压缩/优化相关参数
    parser.add_argument('--no-reduce-colors', action='store_false', default=True, dest='reduce_colors',help='不减少颜色数')
    parser.add_argument('--max-colors', type=int, default=256,help='最大颜色数(1-256),默认256')
    parser.add_argument('--resize', type=float, default=0.6,help='缩放因子(0.1-1.0),默认0.6')
    parser.add_argument('--compress', type=int, default=3, choices=range(0, 10),help='压缩级别(0-9),默认3')
    parser.add_argument('--quality', type=int, default=95,help='调色板质量(1-100),默认95')
    
    args = parser.parse_args()
    
    # 校验输入目录
    if not os.path.isdir(args.input_dir):
        print(f"❌ 错误: 输入目录 '{args.input_dir}' 不存在")
        return
    
    # 自动补全GIF扩展名
    if not args.output_file.lower().endswith('.gif'):
        args.output_file += '.gif'
    
    # 执行GIF生成
    try:
        create_gif(
            args.input_dir, 
            args.output_file, 
            args.fps, 
            args.loop,
            reduce_colors=args.reduce_colors,
            max_colors=args.max_colors,
            resize_factor=args.resize,
            compress_level=args.compress,
            quality=args.quality,
            sort_order=args.sort_order
        )
    except Exception as e:
        print(f"\n❌ 错误: {e}")
        import traceback
        traceback.print_exc()

if __name__ == "__main__":
    main()
  • 配置:零代码便捷适配

    • 全参数通过命令行配置(输入 / 输出路径、缩放、压缩、排序等),无需修改代码;
    • 自动补全.gif扩展名,避免格式错误;
    • 输出生成后详细信息(文件大小、帧率、颜色数等),直观掌握结果。
  • 鲁棒性:防错 & 易调试

    • 自动创建不存在的输出目录,无需手动建文件夹;
    • 校验输入目录有效性,捕获异常并打印错误堆栈,快速定位问题;
    • 跳过无法打开的异常图片,不中断整体生成流程。

可视化结果:

运行信息:

找到 7 张图片,排序方式: asc
  1. frame-000010.color.png
  2. frame-000019.color.png
  3. frame-000039.color.png
  4. frame-000046.color.png
  5. frame-000066.color.png
  6. frame-000086.color.png
  7. frame-000109.color.png

基准尺寸: 960x540

成功加载 7 张图片
缩放图片: (960, 540) → (768, 432) (缩放因子: 0.8)

输出目录已确保存在: /home/user/lgp_dev/01_Gif_picture/Output_GIF
正在生成GIF文件...

✅ GIF已保存至: Output_GIF/THUD_Robot_data-test.gif
📦 文件大小: 1.14 MB | 🎞️ 帧率: 0.5 FPS (每帧 2000.0ms)
🖼️ 图片数量: 7 | 🔁 循环次数: 无限
🔍 缩放因子: 0.8
🎨 颜色数限制: 256
🗜️ 压缩级别: 3 | 📊 质量设置: 95

分析完成~

到此这篇关于Python实现批量图片转GIF动图(附源代码)的文章就介绍到这了,更多相关Python图片转GIF动图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IntelliJ 中配置 Anaconda的过程图解

    IntelliJ 中配置 Anaconda的过程图解

    这篇文章主要介绍了IntelliJ 中配置 Anaconda过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • Python编程中被忽视的核心技巧总结

    Python编程中被忽视的核心技巧总结

    这篇文章主要介绍了一些在 Python 编程中可能被忽视的核心功能,包括默认参数、海象运算符、*args 和 **kwargs 的使用等,需要的可参考下
    2023-08-08
  • Pandas中MultiIndex选择并提取任何行和列

    Pandas中MultiIndex选择并提取任何行和列

    本文主要介绍了Pandas中MultiIndex选择并提取任何行和列,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • python GUI库图形界面开发之PyQt5窗口背景与不规则窗口实例

    python GUI库图形界面开发之PyQt5窗口背景与不规则窗口实例

    这篇文章主要介绍了python GUI库图形界面开发之PyQt5窗口背景与不规则窗口实例,需要的朋友可以参考下
    2020-02-02
  • python读取csv文件并把文件放入一个list中的实例讲解

    python读取csv文件并把文件放入一个list中的实例讲解

    下面小编就为大家分享一篇python读取csv文件并把文件放入一个list中的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04
  • PHPMyAdmin及权限配置

    PHPMyAdmin及权限配置

    这篇文章主要介绍了PHPMyAdmin及权限配置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2014-08-08
  • python导出requirements.txt的几种方法总结

    python导出requirements.txt的几种方法总结

    这篇文章主要介绍了python导出requirements.txt的几种方法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Python装饰器decorator用法实例

    Python装饰器decorator用法实例

    这篇文章主要介绍了Python装饰器decorator用法,以实例形式详细讲述了Python装饰器及相关概念与用途,需要的朋友可以参考下
    2014-11-11
  • ​python中pandas读取csv文件​时如何省去csv.reader()操作指定列步骤

    ​python中pandas读取csv文件​时如何省去csv.reader()操作指定列步骤

    这篇文章主要介绍了​python中pandas读取csv文件​时如何省去csv.reader()操作指定列步骤,对正在工作的你可能有一定的帮助,需要的朋友可以参考一下
    2022-01-01
  • python 实现人和电脑猜拳的示例代码

    python 实现人和电脑猜拳的示例代码

    这篇文章主要介绍了python 实现人和电脑猜拳的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03

最新评论