🙆

[Python] GIFを合成する方法

2023/08/12に公開

複数のGIFを組み合わせて1つのGIFにする方法をメモとしてまとめておきます。

きっかけはNFTで、GIFのジェネラティブ画像を大量に作成する方法を模索していたことでした。

前提

私はPythonは全く書いたことがありませんが、調べたところライブラリも充実しているようだったので、見よう見まねでコードを書きました。
最初はGoで挑戦していましたが、ライブラリも十分になく、コードもかなり複雑になってきた上に完成したGIFのチラつきがすごく、満足したものが出せなかったためPythonを選びました。

※Goの書き方、ライブラリを知っている人は教えてください。

ディレクトリ構成

実装

かなり冗長コードですが、お許しください。
実際に使う場合は配列でループ処理することをお勧めします。

5つのgifを合成して、./output/combined.gifに出力するコードです。

pip install Pillow
main.py
from PIL import Image, ImageSequence

def combine_gifs(gif1_path, gif2_path, gif3_path, gif4_path, gif5_path, output_path):
    # GIFを開く
    gif1 = Image.open(gif1_path)
    gif2 = Image.open(gif2_path)
    gif3 = Image.open(gif3_path)
    gif4 = Image.open(gif4_path)
    gif5 = Image.open(gif5_path)

    # フレームの合成
    frames = []
    for frame1, frame2, frame3, frame4, frame5 in zip(ImageSequence.Iterator(gif1), ImageSequence.Iterator(gif2),
                                                      ImageSequence.Iterator(gif3), ImageSequence.Iterator(gif4),
                                                      ImageSequence.Iterator(gif5)):
        # アルファチャネルを持つ形式にフレームを変換
        frame1_rgba = frame1.convert("RGBA")
        frame2_rgba = frame2.convert("RGBA")
        frame3_rgba = frame3.convert("RGBA")
        frame4_rgba = frame4.convert("RGBA")
        frame5_rgba = frame5.convert("RGBA")

        # 新しいフレームを作成
        combined_frame = Image.new("RGBA", frame1_rgba.size)
	
	# L1以降のフレームをその上に描画
        combined_frame.paste(frame1_rgba, (0, 0), frame1_rgba)
        combined_frame.paste(frame2_rgba, (0, 0), frame2_rgba)
        combined_frame.paste(frame3_rgba, (0, 0), frame3_rgba)
        combined_frame.paste(frame4_rgba, (0, 0), frame4_rgba)
        combined_frame.paste(frame5_rgba, (0, 0), frame5_rgba)

        frames.append(combined_frame)

    # 新しいGIFを保存
    frames[0].save(
        output_path,
        save_all=True,
        append_images=frames[1:],
        duration=gif1.info['duration'],
        loop=0
    )


# パスを指定して関数を実行
combine_gifs(
    './layers/L1/image.gif',
    './layers/L2/image.gif',
    './layers/L3/image.gif',
    './layers/L4/image.gif',
    './layers/L5/image.gif',
    './output/combined.gif',
)

Discussion