3
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

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

こんにちは。ゲームを作って学ぶプログラミング学習サービスプロアカを開発しているアカネヤです。

ユーザーが入力した俳句からGIF画像を生成しています。
これはサーバーでブラウザ(Chrome)を立ち上げ、そのスクリーンショットを繋げることで生成されています。

###################################################
gifjs (22).gif
###################################################
↑こんな感じのGIFが作れます。ぜひ実際にやってみて下さい。

どうやってGIF画像を作るのか、コード付きで解説

今回使用する言語はNodejsです。
まずは適当な空ディレクトリに移動して、以下のコマンドを実行して下さい。

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

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

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

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();
})();

そして実行します。

$ node index.js

動作が終了すると、test.gifというファイルが出来ているはずです。
それを開くと、次のような画像が出来ています!
gifjs (22).gif

詳しく解説

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

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

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

await page.evaluate(`document.getElementById("main").innerHTML = '${text.slice(0, i + 1)}'`)

の部分です。ブラウザが表示するHTMLを変えるようなJSを実行することで、アニメーションを作ることが出来るのです。
あとはコードを読んでもらえると、理解できると思います。

まとめ

五七五メーカー」を作るにあたり、どうすれば良いか試行錯誤したところ、この形になりました。
GIF生成が出来るようになると、面白いサービスがたくさん出来そうでワクワクしますね。
最後まで読んでいただきありがとうございます。いいね、ストック、コメントをお待ちしております。
それでは、最後に一句。
gifjs (24).gif

終わりに

私が開発しているゲームを作って学ぶプログラミング学習サービスプロアカでは無料体験も行っています。ぜひご覧下さい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
3
Help us understand the problem. What are the problem?