[HTML5] Canvasを画像としてダウンロード

  • このエントリーをはてなブックマークに追加
  • LINEで送る

canvasタグに現在描画されている内容を画像としてクライアントにダウンロードしてみます。
Webブラウザなどのクライアントだけで完結するためサーバの負荷などを気にする必要がありません。

今回はひたすらカウントアップするcanvasを、ボタンを押したタイミングでダウンロードできるサンプルです。

- Sponsored Link -

Canvasダウンロード

サンプル

以下のページから実際にサンプルを実行できます。

適当なタイミングで「ダウンロード」ボタンをクリックしてください。クリックした瞬間のcanvasの状態が画像としてダウンロードされます。

ソースコード

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>CANVAS ダウンロード</title>
  <style>
    #countup{ border: 1px solid gray; }
    #btn-dl{ width: 300px; height: 50px; }
  </style>
</head>
<body>

<h1>CANVAS ダウンロード</h1>

<section>
  <!-- このCanvasをダウンロードします -->
  <canvas id="countup" width="300" height="200"></canvas>
  <p><button type="button" id="btn-dl"><img src="icon/download-solid.svg" width="32" height="32"></button></p>
</section>

<script>
window.onload = () => {
  const canvas = document.querySelector("#countup");
  const ctx = canvas.getContext("2d");

  // カウントアップを開始
  ctx.font = "38px serif";
  ctx.fillStyle = "Red";
  setInterval( () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillText(getFormatDate(), 10, 110);
  }, 100);

  // DLボタンをクリック
  document.querySelector("#btn-dl").addEventListener("click", ()=>{
    canvasDownload("#countup");
  });
};

/**
 * 現在時間をhh:mm:ss.msecで返却
 *
 * return {string}
 */
function getFormatDate(){
  const time = new Date();
  const str  =  ("0" + time.getHours()).slice(-2)   + ':'
              + ("0" + time.getMinutes()).slice(-2) + ':'
              + ("0" + time.getSeconds()).slice(-2)
              + '.'
              + ("00" + time.getMilliseconds()).slice(-3);

  return(str);
}

/**
 * Canvasを画像としてダウンロード
 *
 * @param {string} id          対象とするcanvasのid
 * @param {string} [type]      画像フォーマット
 * @param {string} [filename]  DL時のデフォルトファイル名
 * @return {void}
 */
function canvasDownload(id, type="image/png", filename="canvas"){
  const blob    = getBlobFromCanvas(id, type);       // canvasをBlobデータとして取得
  const dataURI = window.URL.createObjectURL(blob);  // Blobデータを「URI」に変換

  // JS内部でクリックイベントを発動→ダウンロード
  const event = document.createEvent("MouseEvents");
  event.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  const a = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
  a.href = dataURI;         // URI化した画像
  a.download = filename;    // デフォルトのファイル名
  a.dispatchEvent(event);   // イベント発動
}

/**
  * 現状のCanvasを画像データとして返却
  *
  * @param {string}  id     対象とするcanvasのid
  * @param {string}  [type] MimeType
  * @return {blob}
  */
function getBlobFromCanvas(id, type="image/png"){
  const canvas = document.querySelector(id);
  const base64 = canvas.toDataURL(type);              // "data:image/png;base64,iVBORw0k~"
  const tmp  = base64.split(",");                     // ["data:image/png;base64,", "iVBORw0k~"]
  const data = atob(tmp[1]);                          // 右側のデータ部分(iVBORw0k~)をデコード
  const mime = tmp[0].split(":")[1].split(";")[0];    // 画像形式(image/png)を取り出す

  // Blobのコンストラクタに食わせる値を作成
  let buff = new Uint8Array(data.length);
  for (let i = 0; i < data.length; i++) {
    buff[i] = data.charCodeAt(i);
  }

  return(
    new Blob([buff], { type: mime })
  );
}
</script>
</body>
</html>

ダウンロード部分は以下のページを参考にさせていただきました。

解説

大雑把なロジック

正直まどろっこしいのですが、canvasのデータを一発で変換できないので以下のような流れをたどります。

  1. CanvasをBase64に変換
  2. Base64をBlobに変換
  3. BlobをdataURIに変換

最終的にこのdataURIをJSで生成したaタグにセット、JSでクリックイベントを発生させダウンロードを行っています。

ここらへんもう少しかんたんに実装できる機能がHTML5標準でありそうな気もするんですけどね。

素材

参考ページ

- Sponsored Link -

ご質問やリクエストなどお気軽に。メールアドレスの入力は任意です。書き込みが反映されるまで時間がかかります。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください