🎞️

giflerでgifをcanvas描画する [JavaScript]

2022/09/22に公開

giflerというライブラリを使用して、gifアニメーションをcanvasに描画する方法を備忘録的にまとめます。

使用

giflerのライブラリを読み込む

giflerのライブラリですが、npmで公開されているバージョン(v0.1.0)は古く、2022年9月現在、公式ドキュメントの記述通りに動作しないため公式ページよりコードをダウンロードしてくるのがいいかと思います。

▼公式ページ
https://themadcreator.github.io/gifler/

gifアニメーションを描画

背景透過でないgifの場合

背景透過でないgifの場合、
gilferのanimate()メソッドを使うことで以下のように短いコードで動かすことができます。

declare let gifler: any;
const addGif = () => {
  let image = new Image();
  image.onload = () => {
    const canvas = document.createElement("canvas");
    document.body.appendChild(canvas);
    canvas.width = image.width / 2;
    canvas.height = image.height / 2;
    
    // giflerのアニメーション処理
    gifler(image.src).animate(canvas);
  };
  image.src = "/static/image/image.gif";
};

window.onload = () => {
  addGif();
};

背景透過のgifの場合

animate()メソッドは、背景をリセットしないまま上書きで描画するので
背景が透明のgifの場合は、前のフレームの描画が残ってしまいます。

▼フレームが残っている例

この場合は、より高い自由度で制御できるget()メソッドを使って処理を書くのが良さそうです。

const onDrawFrame = (ctx, frame) => {
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.drawImage(frame.buffer, 0, 0, ctx.canvas.width, ctx.canvas.height);
};

gifler(image.src)
  .get()
  .then((animator) => {
    animator.onDrawFrame = onDrawFrame;
    animator.animateInCanvas(canvas, false);
  });

onDrawFrameは毎秒呼ばれる処理で、このなかで毎秒canvasの描画をリセットするclearRect()を実行。

▼フレーム残りなく動作している様子

アニメーションの停止

giflerのget()メソッドの返り値animatorに対して、animator.stop()とすることでアニメーションの停止ができます。

// animatorを入れておく変数を用意
let giflerAnimator;

gifler(image.src)
  .get()
  .then((animator) => {
    // 上で用意した変数にanimatorを入れておく
    giflerAnimator = animator;
    animator.onDrawFrame = onDrawFrame;
    animator.animateInCanvas(canvas, false);
  });
  
const stopGif = () => {
  // animator.stop() でアニメーション(毎秒呼ばれるonDrawFrame処理)が停止する
  giflerAnimator.stop();
};

おまけ: ボタンで制御

以上を組み合わせると、gifのアニメーションをボタンで制御できるようにもできます。

declare let gifler: any;

let giflerAnimator;

const addGif = () => {
  let image = new Image();
  image.onload = () => {
    const canvas = document.createElement("canvas");
    document.body.appendChild(canvas);
    canvas.width = image.width / 2;
    canvas.height = image.height / 2;

    const onDrawFrame = (ctx, frame) => {
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      ctx.drawImage(frame.buffer, 0, 0, ctx.canvas.width, ctx.canvas.height);
    };

    gifler(image.src)
      .get()
      .then((animator) => {
        giflerAnimator = animator;
        animator.onDrawFrame = onDrawFrame;
        animator.animateInCanvas(canvas, false);
      });
  };
  image.src = "/static/image/image.gif";
};

const startGif = () => {
  giflerAnimator.start();
};
const stopGif = () => {
  giflerAnimator.stop();
};

const addEvent = () => {
  const start = document.getElementById("start");
  start.addEventListener("click", startGif, false);
  const stop = document.getElementById("stop");
  stop.addEventListener("click", stopGif, false);
};

window.onload = () => {
  addGif();
  addEvent();
};

参考

giflerのメソッドの詳細は、ライブラリのgilfer.coffeeの中身を見ることで確認できます。
https://github.com/themadcreator/gifler/blob/master/src/gifler.coffee

Discussion