IT系おじさんのチラシの裏
2018年10月~
当サイトの記事にはアフィリエイト広告のリンクが含まれる場合があります

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色しか使えないからかなり画質が劣化するだろうと思いましたが、意外と綺麗ですね。

関連記事

JavaScriptのcanvasで縦書きを行う際の備忘録

canvas上に縦書きの文章を出力して画像化しようと考えてちょっとハマったので忘れないうちにメモしておきます。 結論から先に書くと、基本的にcanvasにはwriting-modeの設定が効くの

JavaScriptのWebAudioAPIで楽曲の口パクをしてみる

以前、ソフトウェアの解説動画を作った際、おっさんの声だけ流れてるのもアレだし、最近流行りのアバターにしゃべらせるやつやってみよう、と思ったことがあります。 vtuberとかおじさんよくわからない

コメント

新しいコメントを投稿する

[新規投稿]
 
TOP