Edited at

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

こんにちは。

俳句や川柳から動くGIF画像を生成できるWebサービス「五七五メーカー」をリリースしたアカネヤ(@ToshioAkaneya)です。

ユーザーが入力した俳句から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


終わりに

Ruby on RailsとVueで作成したプログラミングスクールのレビューサイトを運営しています。良ければご覧ください。https://school-report.com/