絹田
絹田
画像を他のドメインからダウンロードすると下記のようなエラーに直面することがあります?

Unable to get data URL. Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported.

Unable to get image data from canvas because the canvas has been tainted by cross-origin data.

直訳すると

「HTMLCanvasElement」で「toDataURL」の実行に失敗しました:汚染されたキャンバスはエクスポートされない可能性があります。

ということです.

これは,CORSポリシーに違反してCanvasへ描写した画像をdataURLやblobに変換しようとすると発生するエラーです.

東証1部の会社でエンジニアをしていて,個人でもiOS, Androidアプリを公開しているその経験をもとに考え方と使い方を説明します?

CORSとはドメインをまたいだリソースのやり取りのことで,クロスオリジン リソース シェアリング(CORS)の略です.ドメインを跨いでリソースをダウンロードしてさらに変換するなんて悪い人がしそうなことですから,そうでない場合はCORSポリシーを適用しない旨を明示的に示す必要があります.

私はGoogle CloudのStorageに保存した画像をAngularのプロジェクトでアクセスするときに上記の問題に直面しました.Google CloudのStorgeのURLとAngularのドメインを同一にできれば問題ないのですがそういうわけにもいきません.その場合,フロントエンド側とサーバ側のそれぞれでCORSポリシーを適用しない旨を明示する必要があります. 私の場合はAngularのプロジェクトでしたが,Reactでも素のJavaScriptでも同じです.CORSポシリーって地味に面倒くさいです..

フロントエンド側の対処

絹田
絹田
Canvas要素に描く際に生成元をanounymousに設定します.


download(){
	var gsReference = this.firestorage.refFromURL(
		'gs://my-app.appspot.com/imgs/'+this.authUid +'/'+this.query_img_name
	);
	const task = gsReference.getDownloadURL().subscribe(
		dataurl => {
			console.log(dataurl,'tsk');
			const image = new Image();
			image.onload = () => {
				this.canvas.nativeElement.width = image.width; 
				this.canvas.nativeElement.height = image.height; 
				this.canvas_rendering_context.drawImage(image, 0, 0);
			};
(これを追加) image.crossOrigin = "anonymous"; 
		image.src = dataurl; 
		}
	)
}

サーバ側の対処

絹田
絹田
jsonファイルでStorageの設定情報を作成し,gsutilコマンドで反映させます

touch my-cors.json
nano my-cors.json

my-cors.jsonは下記のように書きます


[ 
	{ 
		"origin": ["*"], 
		"method": ["GET","POST"], 
		"responseHeader": ["Content-Type"], 
		"maxAgeSeconds": 3600 
	}
]

あとはコマンドから反映させます.

gsutil cors set ./my-cors.json gs://my-app.appspot.com 

参考文献

https://cloud.google.com/storage/docs/configuring-cors