Back

Canvas を使用した画像の Base64 への変換

Canvas を使用した画像の Base64 への変換

ブラウザから画像データをエクスポートする必要がある場合—クライアント側でのプレビュー、小さなグラフィックの埋め込み、アップロード前の画像処理など—HTML Canvas API が最も直接的なツールです。この記事では、JavaScript による Canvas から Base64 への変換がどのように機能するか、いつ使用すべきか、そして一般的な落とし穴がどこにあるかを説明します。

重要なポイント

  • Canvas の toDataURL() メソッドは、生の Base64 文字列ではなく、完全な data URI(MIME プレフィックス付き)を返します。エンコードされたデータのみが必要な場合は、プレフィックスを削除してください。
  • ファイルアップロードや大きな画像には、toDataURL() よりも toBlob() を使用することを推奨します。非同期で、よりメモリ効率的です。
  • PNG は唯一普遍的にサポートされている出力形式です。JPEG と WebP のサポートはブラウザによって異なります。
  • クロスオリジンの画像は、サーバーが適切な CORS ヘッダーを送信し、画像の src を割り当てる前に crossOrigin = 'anonymous' を設定しない限り、Canvas を汚染します。

基本的なワークフロー

Canvas を使用して画像を Base64 に変換するには、3つのステップがあります:画像を読み込み、Canvas 要素に描画し、Canvas データをエンコードされた文字列としてエクスポートします。

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const image = new Image();

image.onload = function () {
  canvas.width = image.width;
  canvas.height = image.height;
  ctx.drawImage(image, 0, 0);

  const dataURL = canvas.toDataURL('image/png');
  console.log(dataURL); // "data:image/png;base64,iVBORw0KGg..."
};

image.src = '/path/to/local-image.jpg';

これが Canvas ベースの画像エンコーディングの基礎です。toDataURL() メソッドは、生の Base64 文字列ではなく、完全な data URI を返します。

Data URL と生の Base64 文字列の違い

この違いを理解することは重要です。canvas.toDataURL() は次の形式の文字列を返します:

data:image/png;base64,iVBORw0KGg...

これには MIME タイプのプレフィックス、エンコーディングラベル、そして実際の Base64 データが含まれています。生の Base64 部分のみが必要な場合—たとえば、JSON としてサーバーに送信する場合—プレフィックスを削除します:

const base64String = canvas.toDataURL('image/jpeg').split(',')[1];

これは最初のカンマで分割し、その後のすべてを取得します。プレフィックスは破棄され、生のエンコードされたデータが残ります。

toDataURL vs. toBlob: どちらを使用すべきか?

これは多くの記事が飛ばしてしまう決定です。以下は直接的な比較です:

機能toDataURL()toBlob()
戻り値の型文字列(同期)Blob(非同期、コールバックベース)
メモリ使用量高い(Base64 は約 33% のオーバーヘッドを追加)低い(バイナリ表現)
最適な用途小さな画像、クイック埋め込みアップロード、大きな画像

toDataURL() は同期的で便利ですが、エンコードされた文字列全体を一度にメモリに読み込みます。Base64 エンコーディングは、元のバイナリと比較してデータサイズを約 33% 増加させます。大きな画像の場合、これは重要です。

toBlob() は非同期で、バイナリ Blob を直接生成するため、アップロードに対してより効率的です:

canvas.toBlob((blob) => {
  const formData = new FormData();
  formData.append('image', blob, 'export.jpg');
  fetch('/upload', { method: 'POST', body: formData });
}, 'image/jpeg', 0.85);

Base64 は文字列が特に必要な場合にのみ使用してください—JSON への埋め込み、テキストフィールドへの保存、または <img> タグ用の data URI の生成などです。ファイルアップロードには、toBlob() がより良い選択です。

フォーマットサポートと品質パラメータ

PNG は、すべてのブラウザで保証されている唯一の出力形式です。JPEG と WebP のサポートは環境に依存します:

canvas.toDataURL('image/jpeg', 0.85); // 品質: 0 から 1、JPEG/WebP のみ
canvas.toDataURL('image/webp', 0.9);  // すべてのブラウザでサポートされているわけではない

品質パラメータは PNG には影響しません。PNG は常に可逆圧縮です。JPEG の場合、0.85 はファイルサイズと視覚的品質のバランスをとる妥当なデフォルト値です。サポートされていない形式を渡すと、ブラウザは黙って PNG にフォールバックします。

汚染された Canvas の問題

適切な CORS 設定なしでクロスオリジンの画像を Canvas に描画すると、Canvas は「汚染」されます。汚染された Canvas で toDataURL() または toBlob() を呼び出すと、SecurityError がスローされます。

これを回避するには、画像をホストしているサーバーが適切な CORS ヘッダー(Access-Control-Allow-Origin)を送信する必要があり、画像要素の src を割り当てる前に crossOrigin を設定する必要があります:

const image = new Image();
image.crossOrigin = 'anonymous';
image.src = 'https://other-origin.com/image.png';

ここでの順序は重要です。src の後に crossOrigin を設定すると、ブラウザが CORS フラグなしでフェッチを開始する可能性があり、それでも Canvas が汚染されます。同一オリジンから読み込まれた画像は決して問題になりません。CORS ヘッダーのないクロスオリジン画像はエクスポートできません—クライアント側の回避策はありません。

Canvas ベースのエンコーディングが意味を持つ場合

次のような場合に Canvas アプローチを使用します:

  • エンコード前にクライアント側で画像をリサイズまたはクロップする
  • エクスポート前にフィルターや変換を適用する
  • 処理された小さな画像を data URI として埋め込む

Canvas 操作なしでローカルファイルを Base64 として読み取るだけの場合、FileReader.readAsDataURL() の方がシンプルで、Canvas を完全にスキップします。

まとめ

Canvas API は、ブラウザでの画像エンコーディングを正確に制御できます。小さな画像や文字列ベースのユースケースには toDataURL() を使用し、アップロードやパフォーマンスに敏感な作業には toBlob() を優先し、外部画像を扱う際は常に CORS を考慮してください。ピクセル操作が不要な場合は、Canvas を完全にスキップして FileReader を使用してください。

よくある質問

はい、SVG を Canvas に描画して toDataURL() を呼び出すことができます。ただし、SVG は最初に Image 要素として読み込む必要があり、クロスオリジン制限も引き続き適用されます。エクスポートされた結果はラスタライズされたビットマップであり、スケーラブルなベクターではありません。SVG が参照する外部リソース(フォントやリンクされた画像など)は、Canvas 上で正しくレンダリングされない可能性があります。

これは通常、画像の読み込みが完了する前に toDataURL() が呼び出されるために発生します。画像の onload ハンドラー内で呼び出すようにしてください。黒い画像は、描画前に Canvas の幅と高さをソース画像の寸法に合わせて設定しなかった場合にも発生する可能性があります。これにより、Canvas はデフォルトサイズの 300 × 150 ピクセルのままになります。

正式な仕様上の制限はありませんが、ブラウザは実用的な制約を課しています。非常に大きな Canvas は、大量のメモリを消費する Base64 文字列を生成したり、ブラウザタブが遅くなったりクラッシュしたりする原因となる可能性があります。大きな画像の場合、toBlob() がより安全でメモリ効率的な代替手段です。

標準の Canvas 要素は DOM に依存しているため、Web Worker では使用できません。ただし、最新のブラウザでサポートされている OffscreenCanvas を使用して、Worker 内で描画を実行し、その convertToBlob() メソッドを呼び出すことができます。OffscreenCanvas は toDataURL() をサポートしていないため、文字列が必要な場合は、結果の Blob を FileReader を使用して Base64 に変換する必要があります。

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay