JavaScriptでjsgifを使ってアニメーションGIFを動的生成する

先日の記事、「JavaScriptでcanvasを録画して動画ファイルに保存する方法」では複数の画像ファイルからwebm形式の動画を生成しましたが、Twitter等のSNSではwebm形式に対応していないようなので、今回は汎用性の高いアニメーションGIFを作ってみようと思います。

必要なライブラリ

canvasに描いた画像をアニメーションGIFにしてくれるjsgifというオープンソースのライブラリがあるので、ありがたく使わせて頂きましょう。

https://github.com/antimatter15/jsgif

リンク先のZIP内にある下記4つのJavaScriptファイルを読み込んで使う感じです。

  • LZWEncoder.js
  • NeuQuant.js
  • GIFEncoder.js
  • b64.js

HTMLの例

<script src="/js/b64.js"></script>
<script src="/js/LZWEncoder.js"></script>
<script src="/js/NeuQuant.js"></script>
<script src="/js/GIFEncoder.js"></script>

<div id="anime">
<img src="[画像ファイル01]" width="80" />
<img src="[画像ファイル02]" width="80" />
<img src="[画像ファイル03]" width="80" />
<img src="[画像ファイル04]" width="80" />
<img src="[画像ファイル05]" width="80" />
<img src="[画像ファイル06]" width="80" />
<img src="[画像ファイル07]" width="80" />
<img src="[画像ファイル08]" width="80" />
<img src="[画像ファイル09]" width="80" />
<img src="[画像ファイル10]" width="80" />
<img src="[画像ファイル11]" width="80" />
<img src="[画像ファイル12]" width="80" />
<img src="[画像ファイル13]" width="80" />
</div>

<p>速度:<input type="range" id="anime_speed" value="500" min="100" max="500"></p>
<p><button onclick="createGIF();">アニメGIFを作成する</button></p>

<canvas id="canvas" style="display:none;"></canvas>

<p><img id="anime_gif" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p>

<p><button id="download" onclick="downloadGIF();" style="display:none;">ダウンロード</button></p>

解説

最初の4つのスクリプト読み込みはjsgif用です。それぞれのjsファイルを置いたパスに適宜書き換えてください。

次にGIFアニメーションにする画像ファイルを並べます。13枚という数に特に意味はありません。以前撮った写真を使いまわしているだけですw

任意の画像を選択してアニメーションGIFを作りたい場合はこの部分を「JavaScriptでFileReaderを使った複数画像のプレビュー例」あたりを参考に書き換えると良いでしょう。

input type=”range”の速度調整は「JavaScriptで画像を連続表示してコマ撮りムービー風の表示をしてみる」で使ったスライダーですが、そのときと違ってCSSによる左右反転はしていません。というのも、Chromeだと良い感じでしたが、Edgeだと反転させただけでは見た目がイマイチだったんですよね。

それなら変に小細工せずにそのまま使っちゃおうかな、と。

canvasはアニメーションGIFの作成時の一時的な保管場所として使うだけなのでdisplay:none;で非表示にしてあります。

また、imgタグのID=”anime_gif”には完成したアニメーションGIFが入る予定なので、空の画像 (data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)を入れています。このエンコード、わざわざファイルを用意しなくても良いので地味に便利。

ボタン類はJavaScriptのほうで解説しましょう。

JavaScriptの例

<script>
var encoder;

function createGIF()
{
	//canvasの取得
	var canvas = document.getElementById('canvas');
	var ctx = canvas.getContext('2d');
	//GIFEncoderの初期処理
	encoder = new GIFEncoder();
	encoder.setRepeat(0); //繰り返し回数 0=無限ループ
	encoder.setDelay(document.getElementById('anime_speed').value); //1コマあたりの待機秒数(ミリ秒)
	encoder.start();
	//画像ファイル一覧を取得
	frames = document.getElementById('anime').getElementsByTagName('img');
	//canvasのサイズを1枚目のコマに合わせる
	canvas.width = frames[0].naturalWidth;
	canvas.height = frames[0].naturalHeight;
	//全ての画像をcanvasへ描画
	for (var frame_no = 0; frame_no < frames.length; frame_no++) {
		ctx.drawImage(frames[frame_no], 0, 0);
		encoder.addFrame(ctx); //コマ追加
	}
	//アニメGIFの生成
	encoder.finish();
	document.getElementById('anime_gif').src = 'data:image/gif;base64,' + encode64(encoder.stream().getData());
	//ダウンロードボタンを表示
	document.getElementById('download').style.display = 'block';
}
function downloadGIF()
{
	encoder.download("download.gif");
}
</script>

解説

[アニメGIFを作成する]というボタンから呼ばれるcreateGIF関数と、[ダウンロード]ボタンから呼ばれるdownloadGIF関数を用意しました。

createGIFでは、

  • canvasの取得
  • GIFEncoderの初期処理(速度とか繰り返し回数とか)
  • 画像ファイルの一覧取得
  • canvasの大きさ調整
  • 全画像をcanvasへ書きつつ、GIFEncoderへコマ追加
  • 最後に生成されたデータをimgタグのsrcへセット
  • [ダウンロード]ボタンの表示

というようなことを実行しています。

downloadGIFでは、GIFEncoderのdownload関数を呼び出しているだけですね。そのために変数encoderをグローバル変数として宣言しています。

自前でファイルを作りたい人は下記のように encoder.stream().bin からblobデータを生成して、アンカータグのURLに埋め込むなんて方法もアリです。

	var bin = new Uint8Array(encoder.stream().bin);
	var blob = new Blob([bin.buffer], {type: 'image/gif'});
	var dataUrl = window.URL.createObjectURL(blob);
	var anchor = document.createElement('a');
	anchor.download = 'download.gif';
	anchor.href = dataUrl;

実行結果

速度:

[アニメGIFを作成する]ボタンをクリックするといつものクマちゃんのアニメーションGIFが生成されて表示されるハズです。
(PCスペック次第ですが、生成まで少し時間がかかるかも)

一応、ChromeとEdgeで動作確認済み。

アニメーションGIFって256色しか使えないからかなり画質が劣化するだろうと思いましたが、意外と綺麗ですね。

adsbygoogle

フォロー