JavaScript | Web API:グラフィック・メディア - 画像読み込み

JavaScript JavaScript
スポンサーリンク

「画像読み込み」は“ファイルをブラウザに連れてきて、キャンバスに貼る”こと

Canvas で画像を扱うときに必ず通るのが「画像読み込み」です。
ざっくり言うと、

  1. 画像ファイルをブラウザに読み込む
  2. 読み込みが終わったら、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 でできる表現の幅が一気に広がっていきます。

タイトルとURLをコピーしました