動的コンテンツを画像化できるJSライブラリ "html2canvas" を使おう

こんにちは、HTMLファイ部新卒の石崎です。
今回は、Webページを画像化できるJavaScriptライブラリ、html2canvas について紹介します。 html2canvasを上手に活用することで、Webサイト側で表示ページのキャプチャを用意して処理したり、ユーザに提供したり出来るため、作れるWebサービスの幅がきっと広がります。

スクリーンショットを撮る

html2canvasを使うとWebページのキャプチャを作れますが、そもそもスクリーンショットを得る方法は他にいくつもあります。

Webページの見えている部分のキャプチャをユーザが撮る

  • Mac command + shift + 4 + space
  • Windows Alt + PrintScreen

このコマンドで、Webページのウィンドウに表示されている部分のキャプチャを撮ることができます。

スマートフォンであれば、端末の電源ボタンと音量ダウンボタンを同時に押すことで同様のことができますね。 もはや言うまでもないレベルかもしれません。

Webページ全体のキャプチャをユーザが撮る

縦に長いことが多いページ全体のキャプチャを撮る方法もいくつかあります。 手っ取り早いのはブラウザの拡張機能やアドオンを利用する方法です。

なかでも、 FireShotBlipshot は利用者が多く、使い勝手もよいです。

FireShot

Blipshot

拡張機能を使用せずとも、Google ChromeであればDeveloper Toolsから、ページ全体のキャプチャを撮ることができます。 スマートフォンでページ全体のキャプチャを撮影できるアプリも、Android, iOSともにあるようです。

Webページ(全体)のキャプチャを自動的に出力する

上記までの方法で、ユーザがWebページのキャプチャを撮ることはできるのですが、例えば以下のようなことをしたい場合があります。

  • ユーザのアクションによって生成された動的ページを画像化して、さらにその画像を使って何か処理をしたい
  • 現在表示されているWebページをユーザが気軽に(1クリックで)保存できるような機能をつけたい

このような、Webサイト側でページのキャプチャを用意してあげたいときに使えるのが、html2canvasというライブラリです。

html2canvasとは

前置きが長くなりましたが、html2canvasは、WebページをレンダリングしてCanvasエレメント上に描画することで、画像化してくれるJSライブラリです。 Niklas von Hertzen氏によって開発されたもので、ライセンスはMITとなっています。

html2canvas公式サイト

html2canvasの公式サイトには、ドキュメントや使用方法が載っています。

html2canvas(element, {
    onrendered: function(canvas) {
        canvas.toDataURL(); // base64形式で描画内容を出力する
    }
});

第1引数であるelementには、画像化したいDOM要素を入れます。複数指定することはできないようです。 第2引数には、オブジェクトの形式でオプションを設定します。なかでも、onrenderedはレンダリング処理後のコールバック関数を指定できるので、必須オプションです。

レンダリング処理は非同期なので、複数の要素をそれぞれ画像化したい場合は、ループ処理とPromiseを組み合わせると良いでしょう。

実際の利用例

html2canvasは、画像化が必要であり、かつユーザ入力によってコンテンツが動的に変化するようなWebページに相性が良いです。 最近のカヤックでの案件でhtml2canvasを利用したので、2つを例にしてみたいと思います。

社内メルマガ

メルマガはHTMLを使うことで表現の幅が広がりますが、毎月送信するメルマガの内容を変更するために、エンジニアが載せる情報をもらって更新する作業を行うのは面倒です。 そこで、HTML5のcontentEditable属性・FileReaderAPIを使って、コードに馴染みがない社員でもWeb上で簡単にHTMLメールを作成・編集できる"メルマガメーカー"を作成しました。 (こちらは社内用メルマガとなるので、出来たサイトをお見せすることはできません…)

一般的なメールマガジンではbackground-imageプロパティを使用できず、また内容差し替えがあるということでコンテンツ量も可変となる等の事情がありました。 そこで、編集後のページが十数枚の画像化した別ページを出力するようにし、あとはコピー&ペーストをするだけでメルマガを送れるようになりました。

両家のレシピ

https://ryoke-reci.pe/

両家のレシピは、自分とパートナーの育った味を、1冊の幸せのレシピ本としてプレゼントできるサービスです。

このサービスでは、利用者が入力したデータを元に、実際に送られるレシピ本の各ページ・プレビューに使われる画像をhtml2canvasを用いて自動生成しています。その結果情報入力から本発送までにかかる時間が大幅に削減され、また利用者はどんな本が出来るのかその場で確認できるようになりました。

両家のレシピ

使用するときに注意したいところ

このように、ユーザ自身がキャプチャしなくてもページのキャプチャを撮れる便利なツールですが、使用する上で気をつけておきたいことがいくつかあります。

実際にはスクリーンショットを撮っているわけではない

html2canvasは、WebページのDOMやCSSを読み込み、その結果を元に解釈した結果をCanvasエレメント上に描画するライブラリです。 すなわち、実際にスクリーンショットを撮っているわけではなく、挙動としてはレンダリングエンジンに近いです。 (CSSの解釈はなんと1つ1つ実装されているので、作者は本当にすごいと思います)

このため、一部の新しいCSSプロパティの解釈が出来なかったり、一般的なブラウザとは別の表示がされてしまう場合があります。 導入する際は、期待通りの画像が生成されているか逐一確かめながら進めるのが良いでしょう。

先の両家のレシピでは、文章を縦書きする際に用いるプロパティwriting-modeが正しく動作せず、1文字ずつ決まった位置に配置して、文字によってはtransform: rotate()/translate();をかけるようにしていました。

外部サイトの画像利用について

セキュリティ上の理由から、Canvas APIは同一生成元ポリシーの制約を受けます。

このため、別オリジン(スキームやホストが異なる場合も別オリジンとなります)の画像を読み込んだ場合はCanvasが汚染されてしまい、描画内容を出力するtoBlob()toDataURL()などの関数を実行できません。 これに対応するためには、サーバ側でAccess-Control-Allow-Originなどのレスポンスヘッダを付与して、CORS(Cross-Origin Resource Sharing)を行う必要があります。

html2canvasで別オリジンの画像を含むページをそのまま出力したい場合は、CORSを行った上で、html2canvasのオプションであるproxyuseCORSをそれぞれ設定しましょう。

html2canvas(element, {
    proxy: true,
    useCORS: true,
    onrendered: function(canvas) {
        canvas.toDataURL();
    }
});

Canvas描画領域制限

Canvasを通常利用する場合には意識すらしないことですが、Canvasには1ページ辺りに描画できる最大領域と、横幅縦幅それぞれの上限がブラウザごとに設定されています。

  • IE11:ページ当たりのCanvas描画領域の横幅と縦幅がそれぞれ8192pxまで
  • iOS Safari:横幅 * 縦幅 の値が16,777,216pxまで(正方形の場合は4096px * 4096px)
  • その他主要ブラウザ(Google Chrome, Firefox, Mac Safari, IE Edge, Android Chrome等)は上記制限よりも緩いため、基本的には考慮不要

ページ内で大量の画像を生成しようとした場合、この制限に引っかかってしまう可能性があるので、注意する必要があります。 どうしても1ページ内でこの制限を突破したいという場合は、画像を生成させるための子ファイルをいくつか作って、親要素からiframeを使用して読み込むことで対応可能です。

Retinaディスプレイ対応

html2canvasのデフォルト設定では、生成された画像をRetinaディスプレイで見たときに、画質が荒くなってしまいます。 公式対応は現状されていないのですが、なんと有志の手によってRetina対応が可能となりました。 https://github.com/niklasvh/html2canvas/pull/1087

ファイルを一部書き換える手間は生じますが、その後はdpi, scaleオプションを設定することで、生成された画像を綺麗に表示することが可能となります。 ただし、サイズや画質を上げると、その分レンダリング処理に時間がかかり、また上記の描画領域制限に引っかかる可能性があるので、注意が必要です。

画像生成をさせるボタン等の位置について

ボタンのクリックなどページ内でのユーザアクションによってhtml2canvasを走らせる場合は、ユーザアクションさせる要素と、画像化したい要素の位置関係に注意する必要があります。 レンダリング過程での不具合があるのか、ブラウザで見えている画面より描画したい要素が上側にあると、生成された画像が見切れてしまうようです。

このため、ユーザアクションさせるボタンは、画像化したい要素より上に置くのが無難です。

まとめ

注意するべき点はいくつかありますが、html2canvasは非常に有用性の高いJSライブラリです。 コンテンツが動的に変化して画像化が必要なWebサービスを作る際は、活用してみてはいかがでしょうか!

カヤックでは、通年でフロントエンドエンジニアを募集しています。 応募はこちらからどうぞ!

【新卒採用】 https://www.kayac.com/recruit/fresh

【中途採用】 https://www.kayac.com/recruit/career

【インターン】 https://www.kayac.com/recruit/intern