【保存版】Canvas・drawImageの全3パターンをじっくり解説!

こんにちは!
九保すこひです(フリーランスのITコンサルタント、エンジニア)

さてさて、JavaScriptでcanvasの操作はきっと過去100回はやっているとは思うんですけど、毎回「あれ…どうだったけ?」と思うものがあります。

それは・・・・・・

drawImage

です。

つまり、画像を<canvas></canvas>に描画(転写)する操作ですね。

では、なぜdrawImageだけこんなに使い方を忘れてしまうのかというと、以下3つの理由があります。

  • 引数がが3パターンある
  • そのパターンに一貫性がない
  • 引数の名前が省略されていて意味がわからない

そこで「迷ったら、あのページを見ればいいじゃないか!」という記事をつくっておくことにしました。

ぜひ忘れないようにブックマークしておいてくださいね😊

「銀のエンゼルゲット!
…からの、前のなくした😱」

drawImage:基本的な使い方

あとでそれぞれ詳しく紹介しますが、drawImageは3つの使い方があります。

// キャンバス
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// 画像をキャンバスに描画
const image = new Image();
image.src = '/images/your-image.png'; // 画像
image.onload = () => {

// パターン:1
ctx.drawImage(image, dx, dy);


// パターン:2
ctx.drawImage(image, dx, dy, dWidth, dHeight);


// パターン:3
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

};

こうすることで、画像をキャンバスに描画(転写)することができます。

drawImage:全3パターンの使い方

以下3つのパターンをそれぞれご紹介します。

  1. そのままの大きさで描画する(画像を切り取らない、リサイズしない)
  2. リサイズして描画する(画像を切り取らない)
  3. 画像の一部を切り取ってリサイズし、描画する

【パターン1】そのままの大きさで描画する

まずは一番シンプルな「画像を切り取らない」「リサイズしない」パターンです。
引数は以下3つ。

ctx.drawImage(image, dx, dy);

実際に以下のように使ってみましょう。

const dx = 150; // 左から150px
const dy = 75; // 上から75px


ctx.drawImage(image, dx, dy);

結果はこうなります。

つまり、キャンバスの左上はしっこから同じサイズの画像を描画すると、ぴったりと枠内にはいります。

逆に、貼り付ける画像が枠より大きい部分はカットされることになります。

↓実際の結果はこちら

枠外に出てしまった部分がカットされるのは、他の使い方でも同じです。

【パターン2】リサイズして描画する

次は「画像を切り取らずにそのまま使うけど、サイズは変更する」パターンです。

使い方はこちら(引数は5つ)

const dx = 150; // 左から150px
const dy = 75; // 上から75px
const dWidth = 300; // dx,dy の位置から300pxの横幅
const dHeight = 200; // dx,dy の位置から200pxの高さ

ctx.drawImage(image, dx, dy, dWidth, dHeight);

結果はこうなります。

ここで重要なのが2点です。

  • dWidthとdHeightによっては、画像が拡大 or 縮小される
  • 縦横の比率が違うと画像がゆがむ

【パターン3】画像の切り取り&リサイズして描画する

一番複雑なパターンで、2つ作業を同時に実行することになります。

  1. 画像の一部を切り取る(クロッピング)
  2. 切り取った画像のリサイズする

先に流れを紹介します。
まずこのような画像があります。

浜松餃子ですね😊
今回は「もやし」の部分だけをカットしてみましょう。

もやしの部分(200x200px)をカットしたら、300x100pxにリサイズします。

これをキャバスに描画するというわけです。

実際のコードはこちら(引数は9つ!)

// 切り取る情報
const sx = 100;
const sy = 100;
const sWidth = 300;
const sHeight = 300;

// 描画する情報
const dx = 150;
const dy = 75;
const dWidth = 300;
const dHeight = 200;

ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

実際の結果はこうなります。

drawImage:全体のサンプルコード

【パターン3】の全コードです。
※画像だけご自身のものに変更してください。

<html>
<body>
<canvas id="canvas" width="500" height="500" style="border:1px solid #000;"></canvas>
<script>

window.addEventListener('load', () => {

// キャンバス
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// 画像をキャンバスに描画
const image = new Image();
image.src = '/images/your-image.jpg'; // 画像
image.onload = () => {

// 切り取る情報
const sx = 40;
const sy = 40;
const sWidth = 200;
const sHeight = 200;

// 描画する情報
const dx = 150;
const dy = 75;
const dWidth = 300;
const dHeight = 100;

ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

};

});

</script>
</body>
</html>

drawImage:引数まとめ

では、最後にdrawImageの引数をまとめます。
全部で3グループですね。

【グループ1】画像データ

image:画像データです。

【グループ2】切り取る画像(source)

  • sx:切り取るエリアの開始位置・X座標(SourceX)
  • sy:切り取るエリアの開始位置・Y座標(Source Y)
  • sWidth:切り取るエリアの横幅(Source width)
  • sHeight:切り取るエリアの高さ(Source height)

つまり、切り取るimageの「左上から右下へ範囲指定する」引数です。

【グループ3】貼り付け先(destination)

考え方は先ほどと同じですが、こちらはキャンバス内の「どのエリアへ貼り付けるか」を指定します。

  • dx:貼りつける先の開始位置・X座標(Destination X)
  • dy:貼りつける先の開始位置・Y座標(Destination Y)
  • dWidth:貼りつける先の横幅(Destination width)
  • dHeight:貼りつける先の高さ(Destination height)

つまり、貼り付け先になるcanvasの「左上から右下へ範囲指定する」引数です。

重要な点:切り取ったエリアと貼り付けるエリアの大きさが違う場合、縮小や拡大されることです。

企業様へのご提案:企業向けフロントエンドの開発者をお探しの方へ

canvasなどJavaScriptをつかった技術者をお探しでしょうか。
ぜひご相談ください!

  • Vue 3
  • React
  • vanilla JS(ネイティブJavaScript)

を使った開発経験(特に社内システム)が多数ございます。

まずはお問い合わせからご相談ください。
お待ちしております😊✨

おわりに

ということで、今回はcanvasのdrawImageに焦点を当てて記事を書いてみました。

個人的には毎回調べる手間が減りますし、ショートカットできそうです!(AI使っても毎回説明が違うので読む時間が必要なんですよね)

しかも自分の文章や画像だから、理解も早かったりします。

ブログは自分のためにもなるんですね!

ぜひ皆さんもやってみてください。
ではでは〜!

「今年も本をたくさん読みましたが、
『バカにはわかんねぇ!』ってすぐ捨てた本もあります😅」

このエントリーをはてなブックマークに追加       follow us in feedly  
お問い合わせ、お待ちしております。
開発のご依頼はこちら: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ