「画像読み込み」は“ファイルをブラウザに連れてきて、キャンバスに貼る”こと
Canvas で画像を扱うときに必ず通るのが「画像読み込み」です。
ざっくり言うと、
- 画像ファイルをブラウザに読み込む
- 読み込みが終わったら、Canvas に描く
この二段階です。
ここで一番つまずきやすいポイントは、
「画像の読み込みは時間がかかる=非同期」ということです。
この感覚をちゃんと掴めると、画像まわりのコードが一気に理解しやすくなります。
基本の流れをまずコードで見てみる
最小の例:1 枚の画像をキャンバスに描く
HTML:
<canvas id="canvas" width="300" height="200" style="border:1px solid #ccc;"></canvas>
JavaScript:
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
// 1. Image オブジェクトを作る
const img = new Image();
// 2. 読み込み完了したらキャンバスに描く
img.addEventListener("load", () => {
ctx.drawImage(img, 0, 0); // 左上にそのまま描画
});
// 3. 読み込みを開始する(src をセット)
img.src = "sample.png";
JavaScriptこの 3 ステップが、画像読み込みの基本パターンです。
Image オブジェクトを作る
load イベントで「読み込み完了後の処理」を登録する
最後に src をセットして読み込みを開始する
ここで大事なのは、「描くのは load の中だけ」ということです。
読み込みが終わる前に drawImage を呼んでも、まだ画像は使えません。
Image オブジェクトでの読み込みをもう少し深掘りする
なぜ「load イベント」が必要なのか
画像ファイルは、ネットワークやディスクから読み込まれます。
これは一瞬で終わるとは限りません。
JavaScript は「先に進んでしまう」ので、
もしこう書いたら危険です。
const img = new Image();
img.src = "sample.png";
ctx.drawImage(img, 0, 0); // まだ読み込み中かもしれない
JavaScriptこの時点では、img の中身がまだ空っぽの可能性があります。
だからこそ、
「読み込みが終わったタイミングで呼ばれる場所」
として img.addEventListener("load", ...) を使うわけです。
「画像読み込みは非同期」という感覚を、ここでしっかり掴んでおいてください。
キャンバスのサイズと画像サイズの関係
drawImage(img, 0, 0) とだけ書くと、
画像は「元のサイズのまま」描かれます。
キャンバスより画像が大きいと、はみ出します。
逆に小さいと余白ができます。
サイズを指定して描きたいときは、こうします。
img.addEventListener("load", () => {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
});
JavaScriptこの形は、
drawImage(画像, 描画先 x, 描画先 y, 描画先の幅, 描画先の高さ)
という意味です。
キャンバス全体にフィットさせたいときによく使います。
HTML の <img> 要素から読み込むパターン
すでにある <img> をキャンバスに貼る
HTML に画像タグがある場合、それをそのまま Canvas に描けます。
HTML:
<img id="source" src="sample.png" alt="" style="display:none;">
<canvas id="canvas" width="300" height="200" style="border:1px solid #ccc;"></canvas>
JavaScript:
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
const img = document.querySelector("#source");
img.addEventListener("load", () => {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
});
JavaScriptブラウザは <img> の読み込みも非同期で行うので、
ここでも load イベントを使うのが安全です。
すでに読み込み済みのこともありますが、
初心者のうちは「画像を使うときは load の中で描く」と覚えておくと混乱しにくいです。
画像の一部だけを切り取って描く(トリミング)
drawImage の「9 引数」バージョン
drawImage には、もう一つ強力な使い方があります。
ctx.drawImage(
img,
sx, sy, sw, sh, // 元画像のどの部分を
dx, dy, dw, dh // キャンバスのどこに、どのサイズで描くか
);
JavaScript例えば、スプライトシート(1 枚の画像にキャラが並んでいるやつ)の
左上 32×32 だけを取り出して描きたいなら、こうです。
img.addEventListener("load", () => {
ctx.drawImage(
img,
0, 0, 32, 32, // 元画像の (0,0) から 32x32 を切り出す
50, 50, 64, 64 // キャンバスの (50,50) に 64x64 に拡大して描く
);
});
JavaScriptここで重要なのは、
元画像の座標系(sx, sy, sw, sh)
キャンバスの座標系(dx, dy, dw, dh)
この二つを頭の中で分けて考えることです。
最初は少し混乱しますが、
「元画像のどの部分を」「キャンバスのどこに」という日本語に戻して考えると整理しやすくなります。
ファイル入力から画像を読み込む(ユーザーの画像を使う)
<input type=”file”> と FileReader を組み合わせる
ユーザーが自分の画像をアップロードして、
それを Canvas に描きたい、というケースもよくあります。
HTML:
<input type="file" id="fileInput" accept="image/*">
<canvas id="canvas" width="300" height="200" style="border:1px solid #ccc;"></canvas>
JavaScript:
const fileInput = document.querySelector("#fileInput");
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
fileInput.addEventListener("change", () => {
const file = fileInput.files[0];
if (!file) return;
const reader = new FileReader();
reader.addEventListener("load", () => {
const img = new Image();
img.addEventListener("load", () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
});
img.src = reader.result;
});
reader.readAsDataURL(file);
});
JavaScriptここでは、
ファイル入力から File オブジェクトを受け取る
FileReader で Data URL として読み込む
その結果を Image の src に渡す
Image の load が終わったら Canvas に描く
という「非同期の階段」を登っています。
一見ややこしいですが、
やっていることは「ファイル → 画像 → キャンバス」という流れだけです。
初心者として「画像読み込み」で本当に掴んでほしいこと
画像読み込みで一番大事なのは、
「読み込みは時間がかかる=終わってから描く」 という感覚です。
そのうえで、次のポイントを押さえておいてください。
Image オブジェクトを作り、load イベントの中で drawImage する。
src をセットした瞬間に読み込みが始まり、完了前に描こうとしてもダメ。
drawImage は「そのまま描く」「サイズを変えて描く」「一部だけ切り取って描く」の 3 パターンがある。
ファイル入力や <img> からも、結局は「Image と load と drawImage」の組み合わせになる。
まずは、
固定の画像ファイルを 1 枚読み込んでキャンバスに貼る
その画像をキャンバス全体にフィットさせて描く
画像の一部だけを切り取って描いてみる
この 3 段階を自分の手で書いてみてください。
「画像を読み込んで、好きなように貼れる」感覚が一度つかめると、
Canvas でできる表現の幅が一気に広がっていきます。
