🖼️

クロスオリジンな画像をキレイにして、Canvasに描画する

2024/10/04に公開

最新情報

こちらの方法が最も高効率かつ高速でした。

結論

こちらの StackOverFlow で示される手順の通り、Object URLを経由します。

Tainted Canvas(汚染されたキャンバス)問題

セキュリティの観点から、クロスオリジンから取得した画像を CanvasRenderingContext2d に対して描画すると、その canvas 要素からは画像を取得できなくなります。
getImageDatatoBlob等の再取得系メソッドは軒並みエラーを投げるようになります。

これを回避するために、取得した画像そのものを汚染されていない画像にする処理を施します。
いわゆるオリジンロンダリングをします(そんな言葉はありません)。

やりかた

① 対象から Blob を取得

const corsBlob = await fetch("https://cors.com/cors.png").then(res => res.blob());

この時点で取得した blob を直接 Canvas に描画すると、期待した効果は得られないので注意が必要です。
ここで、取得した blob を Object URL に経由します。

② Object URL に変換

// ...
const blobURL = URL.createObjectURL(corsBlob);

この URL 文字列から再度fetchを通して、きれいな blob を取得します。

③ Object URL から Blob を取得

// ...
const launderedBlob = await fetch(blobURL).then(res => res.blob());

きれいな blob を手に入れることができたため、描画した canvas から画像を取得してもエラーを投げなくなりました。

いかがでしたか?

上記の引用元が4年前ということもあり、今後そう簡単に修正されるような仕様ではないと思います。
しかしセキュリティの意図に大きく反することには変わりないため、プロダクションには使用せず、個人開発の範疇にとどめるよう注意します。

追記

一番メモリ効率がよく、かつ高速な方法がこちらです。要は最上位互換です。

const launderedBlob = new Response(await fetch(CORS_URL).then(res => res.body)).blob()

Discussion