[JavaScript] JSだけでスクリーンショットを撮ってダウンロードもする方法


# 背景

htmlファイルを画像化して送って欲しい、共有したい、という時はどうしますか？
htmlの画像化は実はいろいろな使い道があります。

 * サムネイルを表示したい
 * 問い合わせの際に、そのページの状態を把握したい
 * 動的に変更されるサイトの断面図を保存したい　　　...などなど

もちろん、htmlファイルを画像化する方法は様々あります。
SnippingTool、WinShot、PRTSCキー、各ブラウザのプラグイン、各種ツール・・・。
しかし、どれもクライアント側に何か準備が生じ、意外と面倒で環境にも左右されます。
htmlを見る送り手側にとって結構手間になりますので、html提供側にその機能を組み込みたいですよね。

# 本投稿の内容

JavaScriptだけで、htmlのスクリーンショットを撮れる「html2canvas」の紹介をします。
最後の実コードを使ってすぐにお手元で試すことが出来ます。

 * JavaScriptだけで実現（クライアント側にソフトは不要）
 * スクリーンショットを撮って画像として表示する
 * 撮ったスクリーンショットをダウンロード出来るようにする
 * 出来たファイルをPDF化したり、直接サーバにPOSTしたり、もこの応用で可能です。
 * （本投稿では応用編までは踏み込みません）  

※html2canvasを解説しているサイトはいくつかあったのですが、どれも分かりにくかったり、
　説明不足な印象なため、使いやすいコード例としてまとめるために作りました。

 
# html内でスクリーンショットを撮った例

### 百聞は一見に如かず、実際に作成したHTMLのキャプチャ画像
 
 * 一見、同じ表が二個ありますが、上はhtml、下はそれを画像化して表示したものです。
 * さらにこの画像自体、「スクリーンショットをダウンロード」のボタンで生成したものです。


![html_ss.png](https://qiita-image-store.s3.amazonaws.com/0/193512/4b57e47a-4bfa-4d35-11dd-cf404f2446b2.png)


# 実現方法

html2canvas.js というライブラリですぐに実現可能です。

```javascript:html2canvasの使い方

//ロードされた際の処理として実施：
window.onload = function(){
  //HTML内に画像を表示
  html2canvas(document.getElementById("target"),{
    onrendered: function(canvas){
      //imgタグのsrcの中に、html2canvasがレンダリングした画像を指定する。
      var imgData = canvas.toDataURL();
      document.getElementById("result").src = imgData;
    }
  });
}

```

注意点として、このライブラリは、本当にスクリーンショットを撮っているのではありません。
DOMやCSSを解釈して、Canvas上に描画するという、いわばjsで出来たレンダリングエンジンなのです。
そのため、ブラウザと表示が異なったり、flashやiframeは上手くキャプチャ出来なかったりします。


# ■ コードの全文 ■

* 丸ごと張り付けてhtmlファイルを作れば、このファイル単体で直ぐにお手元で試すことが出来ます。


```html:HTML_Capture.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>JavaScriptで撮るスクリーンショット</title>
</head>
<body>

  <hr>
  <div style="background-color : #AAEEDD"><h1>JavaScriptで撮るスクリーンショット</h1></div>
  <div id="target">
  <h2>導入方法と処理概要</h2>
  <table border="1" width="500" cellspacing="0" cellpadding="5" bordercolor="#333333" style="table-layout: fixed;">
    <tr>
      <th bgcolor="#7b9ad0" width="40"><font color="#FFFFFF">No</font></th>
      <th bgcolor="#7b9ad0" width="230"><font color="#FFFFFF">概要</font></th>
      <th bgcolor="#7b9ad0" width="230"><font color="#FFFFFF">補足</font></th>
    </tr>
    <tr>
      <td bgcolor="#b1d7e4" width="40" align="right">１</td>
      <td bgcolor="#FFFFFF" width="230" >html2canvas.jsを読み込む</td>
      <td bgcolor="#FFFFFF" width="230" ></td>
    </tr>
    <tr>
      <td bgcolor="#b1d7e4" width="40" align="right">２</td>
      <td bgcolor="#FFFFFF" width="230" >任意のタイミングでhtml2canvas関数を呼ぶ</td>
      <td bgcolor="#FFFFFF" width="230" >※今回はオンロード処理</td>
    </tr>
    <tr>
      <td bgcolor="#b1d7e4" width="40" align="right">３</td>
      <td bgcolor="#FFFFFF" width="230" >onrendered 処理にて指定のElementに画像を追記</td>
      <td bgcolor="#FFFFFF" width="230" >※[img]タグの[src]や、[a]タグの[href]など</td>
    </tr>
  </table>
  </div>
  <br>
  <hr>
  <h3>↓↓ここから画像↓↓　（上の対象のDIVを画像化）<h3>
  <img src="" id="result" />
  <h3>↑↑ここまで画像↑↑</h3>

  <hr>

  <a href="" id="ss" download="html_ss.png">スクリーンショット(document.body全体)をダウンロード</a>

  <hr>
  <h3>注意</h3>
  <ul>
    <li>実際にはスクリーンショットを撮っているわけではない</li>
    <li>html2canvasは、HTML内のDOMやCSSを解釈してCanvas上に描画するライブラリ</li>
    <li>つまり、レンダリングエンジンに近い動作をする</li>
    <li>そのため、ブラウザと異なる表示がされる場合がある</li>
    <li>flashやapplet,iframe（別URL）はうまくキャプチャできない</li>
  </ul>
  </div>
  

  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.js"></script>
  <script>
    //ロードされた際の処理として実施：
    window.onload = function(){

      //HTML内に画像を表示
      html2canvas(document.getElementById("target"),{
        onrendered: function(canvas){
          //imgタグのsrcの中に、html2canvasがレンダリングした画像を指定する。
          var imgData = canvas.toDataURL();
          document.getElementById("result").src = imgData;
        }
      });

      //ボタンを押下した際にダウンロードする画像を作る
      html2canvas(document.body,{
        onrendered: function(canvas){
          //aタグのhrefにキャプチャ画像のURLを設定
          var imgData = canvas.toDataURL();
          document.getElementById("ss").href = imgData;
        }
      });

    }
  </script>

</body>
</html>

```



以上