Reveal.jsのスクリーンショットをPhantomJSでガンガン撮る

Gistぺたり

短いながら、phantomjsの便利なAPIが詰まってたので貼ってみた。

% phantomjs shot.js

Reveal.jsって?

いわゆるHTMLスライドのフレームワークです。最初からある程度かっこよく作られていて、そのままでも十分使えると思います。APIもちゃんと整備されているので、コントロールを追加することもできます。

  • 複数のテーマが用意されている
  • 複数のトランジションが用意されている
  • Markdownで書ける(data-markdownを付与したsectionのみ)
  • nodeでKeynoteみたいなスライドウインドウ+スピーカーノートウインドウの連携ができる

などなど。今用意している最中のスライドでは、これを使ってみています。

なんでスクリーンショット?

普通にPDFで出力するだけであれば、Reveal.jsのPDF Exportを参考に、?print-pdfを末尾につけてアクセスすれば良いです。きれいに出力してくれます。

ただし、data-stateというのを絡めた、背景全面のコントロールにはJavaScriptが必要なため、通常の印刷ではそのあたりの再現がうまくいきません。フォントのこともあるしなー、とか色々ございまして。

ならば丸々、スクリーンショットとして撮ってしまえばいいじゃない → 手作業はめんどう → phantomjsでスクショとる遊びしたことあった!という流れです。

説明

全体としては、phantomjsでページを開いて、順番にスライドを進めながら都度pngファイルを出力する、という簡単な処理です。

phantomjsでWebページを開く

Web Page moduleのあたりを利用しています。

var page = require('webpage').create();
var url = 'http://localhost:1947/';
page.viewportSize = {
  width: 1024,
  height: 768
};
page.open(url, function() {
  //...
});

ページを開いたあとの処理は、page.openのコールバックとして渡します。

スライドの枚数を数える

ループでまわす前に、スライドの枚数を数えます。

iz = page.evaluate(function() {
  return document.querySelector('.slides').children.length;
});

page.evaluateで、ページ内のJavaScriptにアクセスできて、returnで結果を返せば値を取得できます。これ楽しい。

ページをめくる

ループをぶん回してキューを作って1枚ずつ処理させてるだけですが、ページめくりも先ほどと同様にpage.evaluateで行えます。

page.evaluate(function(i) {
  Reveal.navigateTo(i);
}, i);

page.evaluateへの引数として、変数を送ることもできるので、それをReveal側のnavigateToメソッドに渡してページを進めていきます。

PNGでスクショを撮る

page.renderでスクリーンショットを撮ります。

指定したファイル名で拡張子を判別してくれますが、これをpdfにすると印刷のPDF出力も利用できたりします。ほんとに印刷と同じような扱いになるので、今回のケースでは意味がありません。

setTimeout(function() {
  var next = queue[(i+1)];
  page.render('./shot/shot-'+i+'.png');
  if (next) {
    next();
  } else {
    phantom.exit();
  }
}, 1000);

タイマーを仕込んでいるのは、主にスライドのトランジションが終わるまでの待ち時間です。トランジションをオフにすれば、ある程度高速で回せますが、タイマーなしだとReveal側のJS処理が追いついていなかったりするので、少なくとも100ms程度はあったほうがよいでしょう。

キューがなくなったらphantom.exitで処理を終えます。

phantomjs楽しいなぁ

phantomjsはこれまでヘッドレステストなどで利用していましたが、こういう用途でも遊べると楽しいですね。資料用にサイトのスクリーンショットを大量に撮りたいときにも便利かもしれません。