You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Python动态水平拼接多张GIF生成单张GIF文件

多GIF水平拼接Python实现方案

方案1:基于ffmpeg的封装实现(推荐,还原hstack原生效果)

该方案直接调用ffmpeg的hstack滤镜,自动处理不同尺寸GIF的高度对齐、帧率统一,无手动帧处理的误差问题。

依赖安装

  • 系统环境需提前安装ffmpeg并添加到环境变量
  • 安装Python依赖包:pip install ffmpeg-python

实现代码

import ffmpeg
from typing import List

def hstack_gifs(input_paths: List[str], output_path: str, fill_color: str = "white"):
    # 读取所有输入GIF的流
    input_streams = [ffmpeg.input(p) for p in input_paths]
    # 统一所有GIF的帧率为最小输入帧率,避免丢帧
    min_fps = min(int(ffmpeg.probe(p)['streams'][0]['r_frame_rate'].split('/')[0]) for p in input_paths)
    # 对齐高度:统一为最大输入高度,不足的部分用指定颜色填充,内容居中
    max_height = max(ffmpeg.probe(p)['streams'][0]['height'] for p in input_paths)
    processed_streams = []
    for stream in input_streams:
        processed = stream.filter('fps', fps=min_fps)\
                          .filter('pad', height=max_height, y='(oh - ih)/2', color=fill_color)
        processed_streams.append(processed)
    # 水平拼接
    joined = ffmpeg.filter(processed_streams, 'hstack', inputs=len(processed_streams))
    # 输出GIF,设置合理的像素格式
    joined.output(output_path, vcodec='gif', pix_fmt='rgb24').run(overwrite_output=True)

# 调用示例
if __name__ == "__main__":
    # 可传入任意数量的GIF路径
    hstack_gifs(["1.gif", "2.gif", "3.gif"], "output.gif")

方案2:基于Pillow的纯Python实现(无外部依赖)

不需要安装ffmpeg,纯Python处理帧序列,适合轻量使用场景。

依赖安装

pip install pillow

实现代码

from PIL import Image, ImageSequence
from typing import List

def hstack_gifs_pillow(input_paths: List[str], output_path: str, fill_color: tuple = (255,255,255)):
    # 读取所有GIF的帧序列和每帧时长
    gifs_data = []
    max_height = 0
    min_duration = float('inf')
    for path in input_paths:
        gif = Image.open(path)
        frames = [frame.copy() for frame in ImageSequence.Iterator(gif)]
        duration = gif.info.get('duration', 100)
        gifs_data.append({"frames": frames, "duration": duration})
        if gif.height > max_height:
            max_height = gif.height
        if duration < min_duration:
            min_duration = duration
    # 统一所有GIF的帧数为最大帧数,不足的循环补帧
    max_frames = max(len(d["frames"]) for d in gifs_data)
    for data in gifs_data:
        frame_count = len(data["frames"])
        if frame_count < max_frames:
            # 循环补帧到最大帧数
            data["frames"] += data["frames"] * ((max_frames - frame_count) // frame_count) + data["frames"][:(max_frames % frame_count)]
    # 逐帧拼接
    output_frames = []
    for frame_idx in range(max_frames):
        # 计算当前拼接后总宽度
        total_width = sum(data["frames"][frame_idx].width for data in gifs_data)
        # 创建新帧
        new_frame = Image.new('RGB', (total_width, max_height), fill_color)
        current_x = 0
        for data in gifs_data:
            frame = data["frames"][frame_idx].convert('RGB')
            # 垂直居中对齐
            y_offset = (max_height - frame.height) // 2
            new_frame.paste(frame, (current_x, y_offset))
            current_x += frame.width
        output_frames.append(new_frame)
    # 保存GIF
    output_frames[0].save(
        output_path,
        save_all=True,
        append_images=output_frames[1:],
        duration=min_duration,
        loop=0
    )

# 调用示例
if __name__ == "__main__":
    hstack_gifs_pillow(["1.gif", "2.gif", "3.gif"], "output_pillow.gif")

注意事项

  • 如果需要保留GIF透明背景,将Image.new的模式改为RGBA,fill_color改为带alpha通道的元组即可
  • 帧率可根据需求自行调整duration参数

内容的提问来源于stack exchange,提问作者Ratintosh1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 10:36:06