愛と勇気と缶ビール

ふしぎとぼくらはなにをしたらよいか

canvasのgetImageData(), toDataURL()などにおけるCORSについて

僕のcanvas力はいまだ中学生男子並みなので、そもそもcanvasの一部のAPIにSame Origin Policy的なものが適用されることすら今日まで知らなかったのですが、どうやら

違う生成元がsrcに指定されているimgをputImageData -> その描画領域をgetImageDataしようとするとDOM Exception

という感じに、普通に怒られちゃうみたいですね。知らんかった。

http://www.w3.org/TR/cors/#use-cases

↑のあたりに書いてあるのをみると、taintedなcanvas、というのですかね。getImageDataで同じ生成元から読み込んだimgの描画部分を指定しても怒られないけど、違う生成元の画像を描画した部分に少しでもかかっていると怒られるので、canvasってピクセルごとに "taintedか、そうでないか" を管理してるのかなー、と。ブラウザの中の人もなかなかタイヘンですね。


で、これって何か回避策ないのかなー、と探していたらどうやらCORSの流儀にのっとってimgを読みこめば出来るらしい。要は、

1. img要素にcrossorigin属性をつける (https://developer.mozilla.org/ja/docs/CORS_Enabled_Image)
2. 画像をサーブする側でしかるべき Access-Control-Allow-Origin header をつける

という両方の条件を満たせば、特に怒られることなく異なる生成元のimgをcanvasに読み込んだ上で安心してputImageDataやらtoDataURLができます。もちろんCORS周りのことをちゃんと理解してくれるブラウザでないといけませんが。
XHR Level2とかを知っている人が見ると「後者だけでいけるんじゃね?」という気になりますが、どうやら両方の条件を満たさないとダメなようです。(少なくともChromeでは)

最近Amazon S3がCORSに対応したらしいですが、このへんを組み合わせると「(nginxとかでdomain合わせるためのproxyをかますことなく) ピャーっとS3の画像を読み込んで、canvas上にloadしてチョメチョメして、ピャーっとXHR Level2でその画像をpostしてピャーっとupdateする」というようなことがJSレベルで完結してしまうのかもしれませんね。S3使ったことないのでこの辺は僕の妄想ですが、まあRESTfulっていうんだから多分それぞれのobjectに対するCRUD操作は提供されているんでしょう。多分。


あまりにcanvas力がないので何か作りたいなーと思っていたりします。「裸に見える画像ジェネレーター(服の布のある部分を隠すと裸に見えるアレ)」とか出来たら素敵なのですが、ああいうのって「アイコラ」「アイコラ」言われてうしろ指をさされそうやなあ、と思って、躊躇しております。