SNS用の短いアニメや、操作説明のGIF——「動画の一部だけGIFにしたい」ことは地味に多いです。でも無料の変換サイトは動画をアップロードさせるものが多く、重いしプライバシーも気になります。
この記事では、動画をアップロードせず、ブラウザの中だけでGIFに変換する方法を ffmpeg.wasm でまとめます。ポイントは、素朴に作ると汚くなるGIFを、パレット最適化できれいに仕上げるところです。
ゴール:ブラウザ内で、動画の指定範囲を「軽くて・きれいな」GIFに変換できるようになること。
まずは素朴な変換(そして、なぜ汚いか)
ffmpeg.wasm はブラウザ内で ffmpeg のコマンドをそのまま実行できます。
<script src="https://unpkg.com/@ffmpeg/ffmpeg@0.11.6/dist/ffmpeg.min.js"></script>
const { createFFmpeg, fetchFile } = FFmpeg;
const ffmpeg = createFFmpeg({ log: true });
async function toGif(file) {
await ffmpeg.load();
ffmpeg.FS("writeFile", "in.mp4", await fetchFile(file));
// 素朴なGIF(実はこれは色が汚くなりがち)
await ffmpeg.run("-i", "in.mp4", "-vf", "fps=10,scale=320:-1:flags=lanczos", "out.gif");
const data = ffmpeg.FS("readFile", "out.gif");
return URL.createObjectURL(new Blob([data.buffer], { type: "image/gif" }));
}
GIFは 1フレームあたり256色までしか使えません。ffmpeg の既定パレットは固定なので、写真や実写の動画では色バンディング(帯状のムラ)が目立ち、汚くなります。
きれいにする:2パスのパレット最適化
そこで、動画から最適な256色パレットを作り(palettegen)→ それを使ってGIF化する(paletteuse) の2パスにします。これがffmpegでGIFをきれいに作る定番テクニックです。
const vf = "fps=10,scale=320:-1:flags=lanczos";
// パス1:この動画に最適な256色パレットを生成
await ffmpeg.run("-i", "in.mp4", "-vf", vf + ",palettegen", "palette.png");
// パス2:生成したパレットを使ってGIF化
await ffmpeg.run(
"-i", "in.mp4",
"-i", "palette.png",
"-lavfi", vf + " [x];[x][1:v] paletteuse",
"out.gif"
);
const data = ffmpeg.FS("readFile", "out.gif");
-
fps=10:フレームレート。GIFは高fpsだと一気に重くなるので 8〜15 が現実的 -
scale=320:-1:flags=lanczos:幅320pxに縮小(-1で縦横比維持)。lanczosできれいに縮小 -
palettegen/paletteuse:色を最適化する肝。ディザリングもかかり、バンディングが激減します
サイズを抑える・範囲を切り出す
GIFは長い・大きい・高fpsだとすぐ数MB〜数十MBになります。軽くするコツと、範囲切り出しは次の通り。
// 開始2秒から3秒ぶんだけGIFにする(-ss と -t を入力の前に置くと速い)
const args1 = ["-ss", "2", "-t", "3", "-i", "in.mp4", "-vf", vf + ",palettegen", "palette.png"];
const args2 = ["-ss", "2", "-t", "3", "-i", "in.mp4", "-i", "palette.png",
"-lavfi", vf + " [x];[x][1:v] paletteuse", "out.gif"];
await ffmpeg.run(...args1);
await ffmpeg.run(...args2);
軽くするポイント:
- 長さは短く(数秒)
- 幅を小さく(240〜320px)
- fpsを下げる(8〜10)
環境の注意(初回だけハマるところ)
-
エンジンの初回読み込み:ffmpeg.wasm のコアは数十MB。初回のみ読み込みが入ります(以降はキャッシュ)。
createFFmpeg({ corePath })で自ホスティングも可能。 -
マルチスレッド版は COOP/COEP が必要(
SharedArrayBufferを使うため)。ヘッダーを触れない場合はシングルスレッド版(コアは大きめ)。 -
CSPを使っているなら
blob:をscript-src/connect-srcに許可(ffmpegがBlobワーカー/Blob fetchを使うため。ローカルでは気づけず本番で出がち)。
※ この3点は動画→音声のときと同じで、別記事で詳しく書いています。
コードを書かずに使いたいとき
「1回だけGIFにしたい」「動画をアップロードしたくない」なら、ブラウザ完結のツールが手軽です。
私が作っている Morphy の「動画→GIF」なら、
- 動画を選んで、開始位置・長さ・fps・幅を指定するだけ
- 内部で**パレット最適化(2パス)**して、きれいなGIFを生成
- 処理はすべてブラウザ内で完結し、動画はアップロードされません
- 登録不要・無料
👉 動画→GIF 変換ツール:https://morphytools.com/video-to-gif.html
まとめ
- ffmpeg.wasm を使えば、サーバーなし・ブラウザだけで動画をGIFにできる
- 素朴な変換は色が汚い →
palettegen+paletteuseの2パスできれいに -
fps・幅・長さでサイズを制御、
-ss/-tで範囲を切り出す - マルチスレッド版は COOP/COEP、CSPは
blob:に注意
「動画をアップロードせずに、きれいなGIFを作りたい」に、ブラウザ完結はよく合います。参考になれば嬉しいです。