Canvas + JavascriptでAmazonの本を立体化の道のり
こんなのは出来たのですが、結局Canvasのセキュリティ対策が引っかかって、Greasemonkey Scriptにはならなかったわけです。
CanvasのgetImageData/toDataURIはセキュリティの都合上、別サイトから画像を読み込んだ場合にはNS_ERROR_DOM_SECURITY_ERRを返すようになっています。
問題発生その1
まずはローカル(d:\program\html\amazon3dbook\test.htm)で書き書きと。
サンプルはAmazonからDLして同じフォルダにおいた画像。
問題:drawImageした場合、getImageDataでNS_ERROR_DOM_SECURITY_ERRが発生する
同じサーバなら問題無いはずだったのだが、file:///でアクセスしている場合、同じサーバとみなしてくれないらしい。
対処:だいぶ嵌った後に、ローカルのWebサーバ上で動作させたらあっさり動いてorz
問題発生その2
画像の生成はできた。Amazonで動くGreasemonkey Scriptにでもしようか。と考えた所。
問題:Amazonの画像ファイル。実は画像だけ別サーバなのですorz
GreasemonkeyScriptはhttp://www.amazon.co.jp/で動く。
画像はhttp://ec2.images-amazon.com/にある。
一見同じ画面にあるから同じサーバに思えるが、drawImage($("prodImage"), ...);とCanvasに描画すると、
描画自体は問題なく行える物の、getImageDataがセキュリティ例外を返すorzorzorz
(結局はダメだったがこの時思いついた)対策:しかし、GreaseMonkeyの場合、どうしても別サーバにアクセスしたい場合はGM_xmlhttpRequestという手がある。(元ページからアクセスされるとまずいので、脆弱性の元にならないように注意が必要だが)
試験用にちょっと確認
○http://localhost/test.htmからhttp://localhost/test.jpg
×http://localhost/test.htmからhttp://127.0.0.1/test.jpg
上記のように同じホストでも表現が違うとエラーが起きることを確認できたので、試験にはこれを使用する。
localhostからGM_xmlhttpRequestを用いて127.0.0.1にあるjpegファイルのバイナリデータを取得。
うむ。alertで出しても見事にわけがわからない。
このバイナリデータはjpegファイルの中身そのまま。canvasへ描画する方法が無い。
ということで、DataURIへ変換→<img>タグのsrcにセット→drawImage→getImageDataを試みる。
問題発生その3
base64への変換が必要だがfirefoxにはbtoaという便利な関数があるらしい。
早速btoaで変換してためしに<img>タグに放り込んで表示してみる。
問題:btoaでの変換時にNS_ERROR_DOM_INVALID_CHARACTER_ERR
firefox標準で使えるbtoaはバイナリデータとか、2バイト文字とかには使えないっぽい。
javascript:alert(btoa("あ"));でエラー出たりとか。
対策:バイナリに対応したBase64変換モジュールを使用
JavaScript で Base64 の符号化と復号化
これが対応していたので使わせて頂く。
問題発生その4
無事画像を読み込んでの表示が完成。
さて、drawImage→getImageData・・・
問題:getImageDataでやっぱりエラー
data://スキーマからhttp://スキーマへのコピーだからだろうか。
外部から読み込まれているとみなされて、getImageDataが動作しないorz
対策:・・・無し、かなぁ。
Jpegのバイナリは読めるのでそれを解析してDIBとして放り込み、putImageDataで描画とかすればいけるだろう。
不可能じゃないけど厳しいなぁ・・・と、そいえばゼロが卒業研究で必要に駆られてJpeg読み込んでたな。
JavaScript用Jpegライブラリとか作れば何とか・・・かな。
結局
まぁ、冬もあるのでこの辺りでとめておいた。
CanvasのセキュリティやXHR使ったバイナリ読み込み、btoaの問題、外部ライブラリのGreasemonkey組み込みと色々学べておなかいっぱい。
まとめ
○同じサーバの画像を<img>タグで読み込み、drawImage($("img"), ...);とした場合
×file:///D:/test.htm上でfile:///D:/test.jpgをdrawImage(これは何故ダメなんだろう?localhostなら動くのに。)
×同じサーバの画像だがサーバ名指定が違う(http://localhost/test.htmの中でhttp://127.0.0.1/test.jpg)
×DataURIの画像をdrawImage(httpスキーマからdataスキーマの画像を使っている。とみなされるのかな)