[Node.js] デザインQRコードをアニメーションさせる

前回はQRコードの中央にちょっとした画像を貼り付ける「デザインQR」を作成しましたが、今回はその画像をアニメーションさせてみたいと思います。

アニメQRを作成する

準備

適当なディレクトリ作成し、package.jsonを作成後に、node-qrcodenode-canvasモジュール、GIFアニメを簡単に作成できるgifencoderをインストールします。

$ mkdir qr-anime && cd qr-anime
$ npm init
$ npm install qrcode canvas gifencoder

アニメーションするための素材ですが、今回はユニティちゃんを利用させていただきました。 unity-chan.com

アニメーションのフレーム毎にキャラを切り出して保存してあります。

ベースとなるQRコードを作成

作業を2段階に分けました。まずは基本的なQRコードを生成します。

コードは以下の通り。

const QRCode = require('qrcode');

// QRコードの設定準備
const file = "qr.png";
const segment = [
  { data:"UNITY-CHAN!\n", mode:"byte"},
  { data:"http://unity-chan.com/", mode:"byte"}
];
const options = {
  width: 164,
  color:{
    dark: '#FF3300FF',     // QRコードの色
    light: '#FFFFFFFF'     // 背景色
  }
};

// QRコード生成
QRCode.toFile(file, segment, options);

詳細は過去記事を参照ください。 blog.katsubemakito.net

アニメーションさせる

次に先ほど作成したQRコードにアニメを付けていきます。GIFアニメなので要はパラパラ漫画ですね。1フレームずつ画像を作成しgifencoderに渡すと最終的にGIFアニメとして出力してくれます。

const { createCanvas, loadImage } = require('canvas');
const GIFEncoder = require('gifencoder');
const fs = require('fs');

const WIDTH   = 164;             // 画像サイズ X
const HEIGHT  = 164;             // 画像サイズ Y
const GIFFILE = 'UnityQR.gif';   // 出力ファイル名

const makeAnimeQR = async () => {
  // アセット読み込み
  const asset = {
    qr: await loadImage('./qr.png'),    //QRは事前に作成
    chara:[
      await loadImage('./image/s1.png'),
      await loadImage('./image/s2.png'),
      await loadImage('./image/s3.png'),
      await loadImage('./image/s4.png'),
      await loadImage('./image/s5.png'),
      await loadImage('./image/s6.png'),
      await loadImage('./image/s7.png'),
      await loadImage('./image/s8.png')
    ]
  };

  // アニメGIF設定
  const encoder = new GIFEncoder(WIDTH, HEIGHT);
  encoder.createReadStream().pipe( fs.createWriteStream(GIFFILE) );
  encoder.start();
  encoder.setRepeat(0);   // 0:リピートあり, -1:なし
  encoder.setDelay(110);  // フレーム間隔(ミリ秒)
  encoder.setQuality(10); // 画像品質

  // canvas準備
  const canvas = createCanvas(WIDTH, HEIGHT);
  const ctx = canvas.getContext('2d');

  // フレーム生成
  for( let i=0; i<asset.chara.length; i++ ){
    const qr   = asset.qr;
    const icon = asset.chara[i];
    const left = Math.floor((canvas.width - icon.width) / 2);    // x
    const top  = Math.floor((canvas.height - icon.height) / 2);  // y

    // 画像を載せる
    ctx.clearRect(0 ,0, canvas.width, canvas.height);  //リセット
    ctx.drawImage(qr, 0, 0);          //QR
    ctx.drawImage(icon, left, top);   //UNITY CHAN

    // 作成者名も入れておく
    ctx.fillStyle = '#FF3300';
    ctx.fillText('@katsube', canvas.width-50, canvas.height-2);

    // フレームに追加
    encoder.addFrame(ctx);
  }
  encoder.finish();
};

makeAnimeQR();

雑なコードですみませんw

最初に貼り付けたツイートにも書きましたが、デジタルサイネージやWebページなどで表示すると目立って良いかもしれませんね。今回利用したアニメはちょっと運動量が多いので場合によってはうざく感じるかもしれませんので、キャラがまばたきをする、髪が揺れるといった細かい演出をするだけでも印象が違ってくると思います。

あと今回はNodeで作成しましたが、通常は画像編集ソフトなどで作れば良いですw (なぜ書いた←)

続き

blog.katsubemakito.net

参考ページ