Canvas getImageDataで背景透過する仕組み|色距離とアルファチャンネル
手軽屋の「画像の背景を透過」ツールは、サーバーを使わずブラウザだけで動いています。 その仕組みを、MDN(Mozilla Developer Network)仕様準拠で解説します。 JavaScriptを知らない方でも「強さスライダーの数値が何を意味するか」がわかる読み物として書きました。
1. 画像はピクセルの集まり
デジタル画像は、小さな点(ピクセル)が縦横に並んだものです。 たとえばiPhoneで撮った写真が4032×3024なら、約1218万個のピクセルが格子状に並んでいます。
各ピクセルは「赤・緑・青」の3つの数値(0〜255)で色を表します。 白は (255, 255, 255)、黒は (0, 0, 0)、純粋な赤は (255, 0, 0) です。 これに「アルファ(透明度)」を加えた RGBA の4値で表現するのが、Web画像の標準的なやり方です。
2. Canvas API でピクセルを取り出す
ブラウザには <canvas> という描画専用のHTML要素があります。 ここに画像を描いて、 CanvasRenderingContext2D.getImageData() を呼ぶと、 ピクセルのRGBA値が4個ずつ並んだ巨大な配列(Uint8ClampedArray)が返ってきます。
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
const data = ctx.getImageData(0, 0, w, h);
// data.data は [R0,G0,B0,A0, R1,G1,B1,A1, ...] の配列MDNの仕様では、配列の長さは「幅 × 高さ × 4」になります。1ピクセルあたり4要素(R/G/B/A)なので、 4032×3024 の画像なら 4032 × 3024 × 4 = 約4870万個の数値が並んだ配列になります。 このサイズでも現代のスマホなら一瞬で処理できます。
3. 「色が近い」を数値で表す(色距離)
背景透過の判定で必要なのは、「このピクセルは『白』に近いか?」という判定です。 これを数値化するのが「色距離」の考え方です。
ピクセルの色 (r, g, b) と基準色 (br, bg, bb) の距離は、3次元のユークリッド距離で計算します:
distance = √((r - br)² + (g - bg)² + (b - bb)²)
たとえば真っ白 (255, 255, 255) と少し汚れた白 (240, 245, 250) の距離は、 √((255-240)² + (255-245)² + (255-250)²) = √(225 + 100 + 25) = √350 ≈ 18.7 になります。 まったく違う黒 (0, 0, 0) との距離は √(195075) ≈ 441.7 で、これが理論上の最大値です。
4. 「強さ」スライダーの正体
本ツールの「強さ」(0〜80)は、上で計算した色距離のしきい値(limit)を決めるパラメータです。 内部では次の式で変換しています:
limit = (強さ / 100) × 441.7
強さ20なら limit ≈ 88、強さ50なら limit ≈ 220、強さ80なら limit ≈ 353 です。 このしきい値より近いピクセルは「背景」と判定して、アルファ値(透明度)を0(完全透明)に書き換えます。
つまり強さを上げるほど「白に近い色」の範囲が広がり、影や色むらまで透過対象になります。 ただし上げすぎると、薄い線や淡い色まで「白に近い」と判定されて消えてしまいます。
5. 境界のソフト化(アンチエイリアス)
完全透明(alpha=0)と完全不透明(alpha=255)だけで切り分けると、輪郭がギザギザになってしまいます(ジャギー)。 本ツールは、しきい値の前後25%を「グラデーション領域」として扱い、距離に応じて半透明にします:
soft = limit × 0.25;
if (distance <= limit) {
alpha = 0; // 完全透明
} else if (distance <= limit + soft) {
alpha = alpha × (distance - limit) / soft; // 半透明
}
// それ以外はそのまま(不透明)これにより、印鑑の朱肉と白背景の境目がふわっとしたグラデーションになり、 別の背景(薄い色のPowerPointスライドなど)に重ねたときに自然に馴染みます。
6. クリックで「白以外の色」を基準にする
白以外の背景(青背景・緑背景)でも、画像をクリックすればその点のピクセル色を基準色に設定できます。 内部ではマウス座標を画像座標に換算し、 getImageData(x, y, 1, 1) で1ピクセルだけ取得しています:
const ctx = tmpCanvas.getContext("2d");
ctx.drawImage(img, 0, 0);
const p = ctx.getImageData(x, y, 1, 1).data;
setBaseColor([p[0], p[1], p[2]]); // R, G, Bこれで基準色(baseColor)が更新され、再描画時に「青に近いピクセル」が透過対象になります。 縮小表示しているキャンバスから原寸の座標への換算は、表示倍率(scale)を使って計算します。
7. アルファチャンネル付きPNGとして保存
処理後のピクセル配列を putImageData() でキャンバスに書き戻し、HTMLCanvasElement.toBlob(callback, "image/png") でPNGとしてダウンロード可能にします。
ctx.putImageData(data, 0, 0);
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "印鑑_透過.png";
a.click();
URL.revokeObjectURL(url);
}, "image/png");MDN仕様によると、toBlob の第2引数で image/png を指定すると、 アルファチャンネル付き(PNG-24 + アルファ8bit)のロスレス画像として書き出されます。 JPEG(image/jpeg)はアルファ非対応のため指定不可です。
8. すべてブラウザ内で完結する意味
ここまでの処理は すべてあなたのブラウザのJavaScriptエンジン上 で動いています。 画像はサーバーに送信されず、社内の機密文書や個人情報を含む画像も外部に漏れません。
また、サーバーを介さないので料金も発生せず、回数制限もありません。 通信が混雑する時間帯でも処理速度は端末の性能だけで決まります(最近のスマホなら4000×3000ピクセルでも1秒以内)。
「ブラウザだけで画像処理する」というアプローチは、Canvas APIが2012年に標準化されてから可能になりました。 この記事で紹介したテクニックは、フォトレタッチ・QRコード生成・PDF合成など、多くの手軽屋ツールの基盤になっています。
9. 限界と向き不向き
色距離による透過は 「背景が単色に近い画像」 に強く、複雑な背景(風景・室内)には向きません。 人物切り抜きにはセマンティックセグメンテーション(機械学習)ベースの専用サービス(remove.bg等)が適しています。
また、「白い字に白背景」のように被写体と背景が同じ色の領域があると、その部分も透明になってしまいます。 このようなケースでは、レイヤー分離可能な元データ(Illustrator AI ファイル等)が必要です。
10. まとめ
背景透過の仕組みは、突き詰めれば「全ピクセルをループして、基準色との距離がしきい値以下ならアルファを0にする」という単純なアルゴリズムです。 それでも、ピクセル取得・色距離計算・境界ソフト化・基準色のクリック取得・PNG保存といった ブラウザAPIの組み合わせで、十分実用的な結果が得られます。
手軽屋のツールは、Canvas APIのMDN仕様に準拠した実装で、すべて端末内で動作します。 次に印鑑PNGや透過素材が必要になったら、ぜひこの仕組みを思い出して使ってみてください。
このツールを試す
→ 画像の背景を透過(無料・登録不要)