ブラウザのスクショを繋げてGIF画像を作ろう【Puppeteerを使って爆速】

ユーザーが入力した俳句からGIF画像を生成しています。
これはサーバーでブラウザ(Chrome)を立ち上げ、そのスクリーンショットを繋げることで生成されています。
<a href="https://575maker.toshioakaneya.com/">
\###################################################
![gifjs (22).gif](https://qiita-image-store.s3.amazonaws.com/0/250231/45daf6d9-28b2-0943-11bf-823ae3399f3e.gif)
\###################################################
↑こんな感じのGIFが作れます。ぜひ実際にやってみて下さい。</a>

## どうやってGIF画像を作るのか、コード付きで解説
今回使用する言語はNodejsです。
まずは適当な空ディレクトリに移動して、以下のコマンドを実行して下さい。

```bash
$ npm init -f
$ npm install puppeteer  png-js gifencoder
```

使用する３つのライブラリを簡単に説明します。
まずPuppeteerは、GUIを操作することなく、プログラムからAPIでブラウザ(Chrome)を制御できるNode.jsで作られたライブラリ です。今回はPuppeteerのスクリーンショット機能を利用します。
png-jsはPuppteerで撮ったスクショのPNGデータをNodeで扱うためのライブラリで、gifencoderはpngからGIFを作るためのライブラリです。

次に、index.jsを作成し、次のようにして下さい。一回コピペして頂き、動作を確認するのが良いと思います。

```javascript:index.js
const fs = require('fs');
const puppeteer = require('puppeteer');

const GIFEncoder = require('gifencoder');
const PNG = require('png-js');
function decode(png) {
  return new Promise(r => {
    png.decode(pixels => r(pixels))
  });
}

async function gifAddFrame(page, encoder) {
  const pngBuffer = await page.screenshot({clip: {width: 1024, height: 200, x: 0, y: 0}});
  const png = new PNG(pngBuffer);
  await decode(png).then(pixels => encoder.addFrame(pixels));
}

(async () => {
  const browser = await puppeteer.launch({
    headless: false, slowMo: 0,
  });
  const page = await browser.newPage();
  page.setViewport({width: 1024, height: 200});
  const text = '私は猫になりたい';
  const html = `<div id="main" style="font-size: 100px;">${text[0]}</div>`;
  await page.setContent(html, {
    waitUntil: ['networkidle0']
  });

  // record gif
  var encoder = new GIFEncoder(1024, 200);
  encoder.createWriteStream()
    .pipe(fs.createWriteStream('test.gif'));

  // setting gif encoder
  encoder.start();
  encoder.setRepeat(0);
  encoder.setDelay(150);
  encoder.setQuality(10); // default

  for (let i = 0; i < 10; i++) {
    await gifAddFrame(page, encoder);
    await page.evaluate(`document.getElementById("main").innerHTML = '${text.slice(0, i + 1)}'`)
  }

  // finish encoder, test.gif saved
  encoder.finish();

  await browser.close();
})();
```
そして実行します。

```bash
$ node index.js
```
動作が終了すると、`test.gif`というファイルが出来ているはずです。
それを開くと、次のような画像が出来ています！
![gifjs (22).gif](https://toshioakaneya.com/wp-content/uploads/2019/03/test.gif)

## 詳しく解説
先ほどのコードを読み解くための解説をします。

全体の流れは
PuppeteerでHTMLをレンダリングさせる(この時、「私は猫になりたい」の、「私」だけをレンダリングします。)
以下ループ
→スクショを撮る
→gifencoderにスクショのデータを読ませる
⇨Puppeteerに、ブラウザでJSを実行するように指示する。

です。最後のJSを実行というのは、

```javascript
await page.evaluate(`document.getElementById("main").innerHTML = '${text.slice(0, i + 1)}'`)
````
の部分です。ブラウザが表示するHTMLを変えるようなJSを実行することで、アニメーションを作ることが出来るのです。
あとはコードを読んでもらえると、理解できると思います。
## まとめ
「[五七五メーカー](https://575maker.toshioakaneya.com/)」を作るにあたり、どうすれば良いか試行錯誤したところ、この形になりました。
GIF生成が出来るようになると、面白いサービスがたくさん出来そうでワクワクしますね。
最後まで読んでいただきありがとうございます。いいね、ストック、コメントをお待ちしております。
それでは、最後に一句。
![gifjs (24).gif](https://qiita-image-store.s3.amazonaws.com/0/250231/98fe527c-444c-f0b4-4822-aeac5cbc8676.gif)
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)