💾

【Python】PillowでアニメーションGIFのリサイズ

2021/06/19に公開

最近アニメーションGIFを一括でリサイズすることがあり、その時のプログラムの覚書です。

sample.gif

01.プログラム

from PIL import Image

# アニメーションGIFを読み込む
image = Image.open("sample.gif")

# 幅と高さを取得
width, height = image.size

# アニメーションの各フレームをリサイズしてリストに格納
resize_image_list = []
for index in range(image.n_frames):
    image.seek(index)
    resize_image_list.append(image.resize((width // 2, height // 2)))

# アニメーションGIFとして書き出し
resize_image_list[0].save(
    "resize_sample.gif",
    save_all=True,
    append_images=resize_image_list[1:],
    loop=0,
)

02.解説

02-01.ファイルタイプ

少々、補足説明を書いていきます。
アニメーションGIFをPillowで開くと「PIL.GifImagePlugin.GifImageFile」の形式で読み込まれます。 ※jpgやbmp等は「PIL.Image.Image」

image = Image.open("sample.gif")
print(image)
<PIL.GifImagePlugin.GifImageFile image mode=P size=200x113 at 0x29888A333D0>

「PIL.GifImagePlugin.GifImageFile」は複数の「PIL.Image.Image」を内包する形式で、n_framesを参照することで枚数を確認できます。

print(image.n_frames)
50

tell()を使用することで現在参照しているフレームのインデックスを取得できます。
読み込んだ状態だと最初のフレームを指しているので0です。

print(image.tell())
0

seek()を使用することで参照フレームを変更することが出来ます。

image.seek(20)
print(image.tell())
20

imageにアクセスすると、参照フレームを「PIL.Image.Image」として扱い処理を行います。

resize_image = image.resize((100, 100))
print(resize_image)
<PIL.Image.Image image mode=P size=100x100 at 0x1BD415F7F10>

少々注意が必要なのが、アニメーションGIFを読み込み、
そのまま処理すると最初のフレームのみに処理をしてしまい、アニメーションではなくなってしまうことです。

image = Image.open("sample.gif")
print(image.tell())
print(image)
resize_image = image.resize((100, 100))
print(resize_image)
0
<PIL.GifImagePlugin.GifImageFile image mode=P size=200x113 at 0x29888A333D0>
<PIL.Image.Image image mode=P size=100x100 at 0x1BD415F7F10>

02-02.リサイズ

アニメーションGIFをリサイズする場合には、各フレームに対し処理をします。

# 幅と高さを取得
width, height = image.size

# アニメーションの各フレームをリサイズしてリストに格納
resize_image_list = []
for index in range(image.n_frames):
    image.seek(index)
    resize_image_list.append(image.resize((width // 2, height // 2)))

02-03.保存

アニメーションGIFとして保存し直します。
1枚目のフレームに対しsave()を使用し、append_imagesオプションで残りのフレームを指定します。
save_allで全ての画像を保存、loopでアニメーションのループ回数を指定します(0だと無限ループ)
詳細は公式ドキュメントにて → Image file formats — Pillow (PIL Fork) documentation

# アニメーションGIFとして書き出し
resize_image_list[0].save(
    "resize_sample.gif",
    save_all=True,
    append_images=resize_image_list[1:],
    loop=0,
)

追記:
出来上がったGIFが上手く表示されないときは、最適化オプション(optimize)をFalseにすることで表示できるようになる場合もあります。

# アニメーションGIFとして書き出し
resize_image_list[0].save(
    "resize_sample.gif",
    save_all=True,
    append_images=resize_image_list[1:],
    loop=0,
    optimize=False,
)

以上。

Discussion