見出し画像

noteに動画を貼るのが面倒なので、MP4をGIFに変換するツールを作った

はじめに

こんばんは。ほったりたです。Micro:bitの投稿を最近していますが、動作の動画をアップしたくなります。
(これはMicro:bitに限ったことではなく、他のものづくりでもそうですが・・)

でも…noteに動画貼るのめんどくないですか?

僕が知らないだけかもしれませんが、多分YoutubeかVimeoのリンク埋め込みですよね?
noteに貼るためだけにアップするのって結構手間だなと思ったので、別に難しくもないですが、note投稿用に動画をgifに変換するプログラムを書きました。(Web上にサービスあるじゃんっていうのもわかります。でも、僕ああいうサイトあんまり使いたくないので、自分で作ったのです。)

今回は自分しか使わないつもりだったので、息子と一緒にmicro:bitいじってる時に、Claude-Codeに作らせました。Pythonのプログラムです。

基本Python触っている人はコード載せなくても自分で書けるレベルかと思いますが、コードも載せておきます。
Google Colabでも使えるようにプログラムも置いておきます。誰かのお役に立てると幸いです
(Google Colabの使い方はググれば出てくるはずですが、この記事が読まれるようならニーズがあるかもしれないのでマニュアル記事書きます)

※ただし、音声が必要な場合はGIFだと厳しいので、結局音声アリはYoutubeにアップする必要があることに作ってから気づきましたw。note用の動画アップ自動化したいですね。

作ったもの

MP4動画をGIFに変換するPythonスクリプトです。以下の機能を実装しました

フレームレート調整: GIFのfpsを指定可能(デフォルト10fps)
サイズ調整: 幅を指定してリサイズ(アスペクト比維持)
時間範囲指定: 開始位置と長さを指定して部分的に変換
ファイルサイズ表示: 変換後のファイルサイズをMB単位で表示

コード

#!/usr/bin/env python3
"""
MP4動画をGIFに変換するスクリプト

使い方:
    python mp4_to_gif.py input.mp4 output.gif

オプション:
    --fps: GIFのフレームレート (デフォルト: 10)
    --width: GIFの幅 (デフォルト: 元のサイズ)
    --start: 開始時間(秒) (デフォルト: 0)
    --duration: 長さ(秒) (デフォルト: 全体)
"""

import sys
import argparse
from pathlib import Path

try:
    from moviepy.editor import VideoFileClip
except ImportError:
    try:
        from moviepy import VideoFileClip
    except ImportError:
        print("Error: moviepy がインストールされていません")
        print("以下のコマンドでインストールしてください:")
        print("  pip install moviepy")
        sys.exit(1)


def convert_mp4_to_gif(
    input_file: str,
    output_file: str,
    fps: int = 10,
    width: int = None,
    start_time: float = 0,
    duration: float = None
):
    """
    MP4動画をGIFに変換する

    Args:
        input_file: 入力MP4ファイルのパス
        output_file: 出力GIFファイルのパス
        fps: GIFのフレームレート
        width: GIFの幅(Noneの場合は元のサイズ)
        start_time: 開始時間(秒)
        duration: 長さ(秒、Noneの場合は全体)
    """
    print(f"変換開始: {input_file} -> {output_file}")

    # 動画を読み込む
    clip = VideoFileClip(input_file)

    # 時間範囲を指定
    if start_time > 0 or duration is not None:
        end_time = start_time + duration if duration else clip.duration
        clip = clip.subclip(start_time, end_time)

    # サイズを調整
    if width:
        # 幅を指定して、アスペクト比を維持してリサイズ
        height = int(clip.h * width / clip.w)
        # moviepyのバージョンによってメソッド名が異なる
        if hasattr(clip, 'resize'):
            clip = clip.resize((width, height))
        else:
            clip = clip.resized((width, height))

    print(f"元の動画: {clip.duration:.2f}秒, {clip.w}x{clip.h}")
    print(f"GIF設定: fps={fps}, width={clip.w}")

    # GIFに変換
    clip.write_gif(output_file, fps=fps)

    clip.close()

    # ファイルサイズを表示
    output_path = Path(output_file)
    file_size = output_path.stat().st_size / (1024 * 1024)  # MB
    print(f"変換完了: {output_file} ({file_size:.2f} MB)")


def main():
    parser = argparse.ArgumentParser(
        description="MP4動画をGIFに変換",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
例:
  # 基本的な変換
  python mp4_to_gif.py video.mp4 output.gif

  # フレームレートと幅を指定
  python mp4_to_gif.py video.mp4 output.gif --fps 15 --width 800

  # 10秒目から5秒間を変換
  python mp4_to_gif.py video.mp4 output.gif --start 10 --duration 5
        """
    )

    parser.add_argument("input", help="入力MP4ファイル")
    parser.add_argument("output", help="出力GIFファイル")
    parser.add_argument("--fps", type=int, default=10, help="フレームレート (デフォルト: 10)")
    parser.add_argument("--width", type=int, help="GIFの幅(省略時は元のサイズ)")
    parser.add_argument("--start", type=float, default=0, help="開始時間(秒)")
    parser.add_argument("--duration", type=float, help="長さ(秒)")

    args = parser.parse_args()

    # 入力ファイルの存在確認
    if not Path(args.input).exists():
        print(f"Error: 入力ファイルが見つかりません: {args.input}")
        sys.exit(1)

    try:
        convert_mp4_to_gif(
            args.input,
            args.output,
            fps=args.fps,
            width=args.width,
            start_time=args.start,
            duration=args.duration
        )
    except Exception as e:
        print(f"Error: 変換中にエラーが発生しました: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()

使い方

1. 必要なライブラリをインストール

pip install moviepy

2. 基本的な変換

python mp4_to_gif.py video.mp4 output.gif

これだけで変換できます。デフォルトではfps=10、元のサイズで変換されます。

3. オプションを指定した変換

幅を800pxに縮小してfps=15で変換

python mp4_to_gif.py video.mp4 output.gif --fps 15 --width 800

10秒目から5秒間だけを変換

python mp4_to_gif.py video.mp4 output.gif --start 10 --duration 5

組み合わせ例

python mp4_to_gif.py video.mp4 output.gif --fps 12 --width 600 --start 5 --duration 10

実際に使ってみた

micro:bitの画面収録動画(約7秒、7MB)をGIFに変換してみました。

パターン1: デフォルト設定

python mp4_to_gif.py demo_accel.mov output_accel.gif

→ 出力: 5.5MB(元のサイズ、fps=10)
ちなみに・・このサイズだとアップロード失敗が頻発します(アップできませんでした。)

パターン2: 幅800pxに縮小

python mp4_to_gif.py demo_accel.mov output_accel_800.gif --width 800

→ 出力: 2.1MB(幅800px、fps=10)

幅を縮小することで、ファイルサイズを約60%削減できました。note投稿用には、幅800pxくらいが丁度良いサイズ感ですね。

ファイルサイズの調整

GIFのファイルサイズは以下で調整できます:

  1. fps(フレームレート)を下げる: 10fps程度で十分滑らかに見える

  2. 幅を縮小する: 800px程度でも十分見やすい

  3. 長さを短くする: 必要な部分だけ切り出す

ファイルサイズが大きすぎる場合は、上記の方法で調整してください。

おまけ Google Colabのプログラム

以下GoogleColabで動くようにしたものです。よかったらどうぞ。

まとめ

noteに動画を貼るための簡単なツールを作りました。
音声が不要な操作デモや、ちょっとした動きを見せたい時には便利かなと思います。


最後まで読んでいただきありがとうございました!
普段は「はっきんぐパパ」として電子工作やものづくりの記事も書いていますので、こちらもぜひ覗いてみてください。
はっきんぐパパはこちら↓



いいなと思ったら応援しよう!

Hottarita(ほったりた) いつも読んで頂きありがとうございます! いただいたサポートは子どものためのもの作りの活動費に使わせていただきます!