批量图片转 GIF 动图工具 | 提供源代码

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

关键内容

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

运行效果:

1、简洁版

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

代码的参数配置:

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

思路流程:

源代码:

python 复制代码
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 | 循环次数: 无限

运行效果:

2、专业版

这是一个增强版批量图片转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 抖动算法,减少颜色精简后的画面失真。

源代码:

python 复制代码
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

分析完成~

相关推荐
源码宝1 天前
新一代医院信息系统云HIS,多租户共享,java版HIS+EMR+LIS全套源码
java·大数据·源码·云his·his系统·源代码·医院信息系统
糖炒栗子03262 天前
AI辅助开发的完整提问与验证流程
工具
私人珍藏库3 天前
【windows】跨平台 Android 刷机Root工具箱
android·windows·工具·刷机·软件·多功能
私人珍藏库3 天前
[Android] 蓝叠模拟器工具箱v1.1
android·智能手机·app·工具·软件·多功能
fly_over3 天前
Claude Code 从零复刻教程 第 2 篇:REPL 循环实现
ai编程·工具·命令行·claude code
私人珍藏库3 天前
【Android】Shizuku升级版-Stellar-提高软件权限
android·app·工具·软件·多功能
私人珍藏库5 天前
[Windows] 【灵犀Claw生成】酷狗加密音乐批量转换工具 Xy Music Converter
windows·工具·软件·多功能
私人珍藏库5 天前
【Android】一键硬核锁手机
android·智能手机·app·工具·软件
寺中人5 天前
硬盘提示初始化的损坏,手动恢复MBR及EBR分区教程
windows·工具·硬盘修复