canvasで画像のリサイズ・トリミングする

サンプルコード

canvasに画像を読み込むサンプルコードです。
以下では画像を読み込み、canvasを読み込んだ画像と同じサイズに設定してcanvasに読み込んだ画像をそのまま描画しています。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <style>
      body {
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
      }
      #canvas {
        border: solid 1px;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas"></canvas>
    <script type="application/javascript">
      document.addEventListener("DOMContentLoaded", () => {
        // 対象のcanvasを取得
        const canvas = document.querySelector("#canvas");

        // キャンバスに対応したブラウザの場合のみ処理する
        if (canvas.getContext) {
            // imgタグ生成
            const img = document.createElement("img");

            // 画像の読み込みが完了したら処理する
            img.addEventListener("load", (e) => {
              // 画像のサイズを取得
              const width = img.naturalWidth;
              const height = img.naturalHeight;

              // canvasのサイズを画像と同じサイズにする
              canvas.width = width;
              canvas.height = height;

              // context取得
              const ctx = canvas.getContext("2d");

              // 画像を描画する
              const sx = 0; // 元画像の切り取り開始位置(x軸)
              const sy = 0; // 元画像の切り取り開始位置(y軸)
              const sw = width; // 元画像の切り取り開始位置から切り取る幅
              const sh = height; // 元画像の切り取り開始位置から切り取る高さ
              const dx = 0; // canvasの描画開始位置(x軸)
              const dy = 0; // canvasの描画開始位置(y軸)
              const dw = width; // canvasの描画開始位置から描画する幅
              const dh = height; // canvasの描画開始位置から描画する高さ
              ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
            });

            // 画像読み込み
            img.src = "https://example.com/path/to/image.jpg"
            // canvasから読み込む場合
            // img.src = document.querySelector("#loadCanvas");.toDataURL();
        }
      });
    </script>
  </body>
</html>

リサイズ

元画像からリサイズ後のサイズを算出して、canvasのサイズと描画サイズを指定します。
以下は元画像のサイズの50%にリサイズしてます。

(e) => {
  // 画像のサイズを取得
  const width = img.naturalWidth;
  const height = img.naturalHeight;

  // リサイズ後のサイズ(半分のサイズにする)
  const scale = 0.5;
  const afterWidth = width * scale;
  const afterHeight = height * scale;

  // canvasのサイズを設定
  canvas.width = afterWidth;
  canvas.height = afterHeight;

  // context取得
  const ctx = canvas.getContext("2d");

  // 画像を描画する
  const sx = 0; // 元画像の切り取り開始位置(x軸)
  const sy = 0; // 元画像の切り取り開始位置(y軸)
  const sw = width; // 元画像の切り取り開始位置から切り取る幅
  const sh = height; // 元画像の切り取り開始位置から切り取る高さ
  const dx = 0; // canvasの描画開始位置(x軸)
  const dy = 0; // canvasの描画開始位置(y軸)
  const dw = canvas.width; // canvasの描画開始位置から描画する幅
  const dh = canvas.height; // canvasの描画開始位置から描画する高さ
  ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
};

トリミング

トリミングはsx、sy、sw、shで切り取り範囲を設定して描画します。
以下は縦、横の短い方の長さに合わせた正方形にトリミングしてます。

(e) => {
  // 画像のサイズを取得
  const width = img.naturalWidth;
  const height = img.naturalHeight;

  // トリミング後のサイズ
  const minSize = Math.min(height, width);
  const afterWidth = minSize;
  const afterHeight = minSize;

  // canvasのサイズを設定
  canvas.width = afterWidth;
  canvas.height = afterHeight;

  // context取得
  const ctx = canvas.getContext("2d");

  // 画像を描画する
  const sx = 0; // 元画像の切り取り開始位置(x軸)
  const sy = 0; // 元画像の切り取り開始位置(y軸)
  const sw = canvas.width; // 元画像の切り取り開始位置から切り取る幅
  const sh = canvas.height; // 元画像の切り取り開始位置から切り取る高さ
  const dx = 0; // canvasの描画開始位置(x軸)
  const dy = 0; // canvasの描画開始位置(y軸)
  const dw = canvas.width; // canvasの描画開始位置から描画する幅
  const dh = canvas.height; // canvasの描画開始位置から描画する高さ
  ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
}

余白を入れる

余白は画像よりも大きなサイズをcanvasに指定します。
以下は縦、横の長い方の長さに合わせた正方形にして、発生した余白をグレーに設定してます。
また、余白を上下、左右に均等に入れる為に描画開始位置のsx、syを調整しています。

(e) => {
  // 画像のサイズを取得
  const width = img.naturalWidth;
  const height = img.naturalHeight;

  // トリミング後のサイズ
  const maxSize = Math.max(height, width);
  const afterWidth = maxSize;
  const afterHeight = maxSize;

  // canvasのサイズを設定
  canvas.width = afterWidth;
  canvas.height = afterHeight;

  // context取得
  const ctx = canvas.getContext("2d");

  // 余白の色を設定
  ctx.fillStyle = "rgb(100, 100, 100)";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  // 画像を描画する
  const sx = (width - afterWidth) / 2; // 元画像の切り取り開始位置(x軸)
  const sy = (height - afterHeight) / 2; // 元画像の切り取り開始位置(y軸)
  const sw = canvas.width; // 元画像の切り取り開始位置から切り取る幅
  const sh = canvas.height; // 元画像の切り取り開始位置から切り取る高さ
  const dx = 0; // canvasの描画開始位置(x軸)
  const dy = 0; // canvasの描画開始位置(y軸)
  const dw = canvas.width; // canvasの描画開始位置から描画する幅
  const dh = canvas.height; // canvasの描画開始位置から描画する高さ
  ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
}

編集した画像をダウンロード

aタグを生成してhrefにdata URI等を設定後、クリックしてあげる事でダウンロードできます。

const downloadButton = document.querySelector("#download");
downloadButton.addEventListener("click", () => {
  let a = document.createElement("a");
  a.href = canvas.toDataURL();
  a.download = "image.png";
  a.click();
});