canvas の getImageDataが少しめんどくさい(特にローカルで動かす場合)

egg (JavaScript Effect Library)にモザイクイン・モザイクアウトを追加しました。

egg とは?

HTML5canvas を使った画像エフェクトライブライブラリです。
まだ数は少ないですが、結構きれいなエフェクトがかかります。
Firefox, Google Chrome をご利用の方は、ぜひ下記のページからサンプルをご覧ください。


Ver0.1.1の変化点

  • モザイクイン・モザイクアウトを追加

ダウンロードとサンプルは こちら(egg (JavaScript Effect Library)) からどうぞ!


今回追加したエフェクトで、初めて canvas の getImageDataを使いました。
ピクセル単位で色を扱えて便利かなーと思ったんですが、少し扱いがめんどくさかったです。

1.ピクセルデータはキャンバスからしか取得できない

画像から直接 getImageData でピクセルを取得できると思っていました。
しかし、実際は画像を一度キャンバスに貼り付けないとピクセルが取得できないようです。
そのために、わざわざバッファー用のキャンバスを用意しなくてはいけない少しめんどくさい…。

2.デフォルトの設定だと、ローカルで動かない

ローカルにある画像をキャンバスへ張り付けた場合、getImageData が動かなくなります。
(Firefox だと「'Security error" code: "1000'」、Google Chrome だと「SECURITY_ERR: DOM Exception 18」が発生します)

これは、JavaScript の同一出身ポリシー*1に引っかかるために発生するそうです。

                            • -

回避方法

about:config から*2、security.fileuri.strict_origin_policy を false に設定する
参考:HTML5 Canvas/getImageData and the nefarious(Matthias Siegel のコメントに詳しく書かれています)

起動オプションに「--allow-file-access-from-files」を付加する
参考:JavaScriptにおけるローカルファイルアクセス権限のポリシー: 発火後忘失

                            • -

2011年4月23日追記:
HttpServerAnywhere を使えば、どのブラウザでも問題なく動かすことができます。

                            • -


ちなみに、画像データを取得するだけなのに、なんで同一出身ポリシーを適用しているのかというと、
不用意に画像がどこかに送信されるということを防ぐためだそうです。

I’m not on expert on Firefox’s security model, but I believe this is because drawImage from google.com makes your canvas write-only. The canvas is flagged write-only because the image is not in the same security domain as your page.

What’s the attack vector? Not quite sure, but it might go something like:
1) there is an image on another domain that contains sensitive information about you (could just be your profile pic, could be an image of where you live)
2) attacker grabs cross-domain image and puts it in dom
3) attacker uses drawImage and getImageData, and send the dump of sensitive images to a server


Here’s a few relevant bugs:
https://bugzilla.mozilla.org/show_bug.cgi?id=530928
https://bugzilla.mozilla.org/show_bug.cgi?id=417836

I found these with a quicksearch for getImageData:
https://bugzilla.mozilla.org/buglist.cgi?quicksearch=ALL%20getImageData

This bugzilla quicksearch reference is super helpful:
http://www.squarefree.com/bugzilla/quicksearch-help.html


私はFirefoxのセキュリティモデルのエキスパートじゃないけど、google.com から drawImage をしたことによって canvas が書き込み専用になったんだと思う。canvas の書き込み専用フラグは、画像とあなたのページが同一のセキュリティドメインに属していないから立ったんだ。

画像に対してどのように攻撃すのか? はっきりわからないけど、たぶんこういうことだと思う。
1) 他のドメインにあるイメージに、あなたの個人情報を含む画像がある(あなたの顔写真や、住んでいるところの画像とか)
2)攻撃者はクロスドメインの画像を取得、それをDOMに挿入する
3)攻撃者は、drawImage と getImageData を使って、個人情報の画像のダンプをサーバに送信する

(以下、翻訳略)

HTML5 Canvas/getImageData and the nefarious(Benjamin Stover のコメント)


とはいえ、ローカルであれば、同じフォルダ = 同一出身じゃないのかなと思ったんですが…。
いろいろ調べたら、ユーザが意図して同じフォルダに置いていると言いきれない(ダウンロード用のフォルダとかいろいろごちゃごちゃ置いたりする)ので、同一の出身と扱わないそうです(ただしブラウザ実装に依存)。
参考:http://journal.mycom.co.jp/news/2008/12/08/031/



この辺は、みごとにはまりました。
とはいえ、開発用に解除する手段があるので、まぁいいのかなと思います。
ただ、もう少し分かりやすいエラーにして欲しいです…(ーー;)

*1:The same origin policy のこと。この訳は、オライリーのサイ本(JavaScript 第五版)より

*2:ブラウザのURL入力欄に「about:config」と入れる