ActionScript を使って 外部ドメインの画像を読み込むときの注意点を調べてみた。
AS3 で調べたけど、AS2 でもセキュリティの機構自体は同じ(だと思う)。
Loader クラスを使えば外部ドメインの画像をロードできる。
var loader:Loader = new Loader(); var req:URLRequest = new URLRequest("http://www.example.com/sample.gif"); loader.load(req); addChild(loader);
画像形式は PNG、GIF、JPEG のみ。BMP はダメ。アニメーション GIF の場合は1フレーム目しか描画されない。
読み込み完了したことを知るためには、contentLoaderInfo プロパティの complete イベントを監視すればよい。ファイルが存在しなかったり、ファイル形式が不正だった場合は ioError イベントが発生する。ioError を listen していない場合には例外が投げられる。
loader.contentLoaderInfo.addEventListener("complete", completeHandler); loader.contentLoaderInfo.addEventListener("ioError", ioErrorHandler);
読み込んだ画像は、回転・拡大したり、透明度を変えたり、フィルタをかけたりすることが可能だ。以下の例を見ていただきたい。
この例では、mixi のロゴを img.mixi.jp のドメインから動的に読み込んでいる。ColorMatrixFilter で紫色に変色させ、DisplacementMapFilter でマウスの上を歪ませている。
ソースは こちら (77行)。(歪ませる部分は miscellaneous [ActionScript 3.0] DisplacementMapFilterで虫眼鏡効果 を参考にさせてもらいました)
外部ドメインから画像を読み込んで、いろいろできるのは分かっていただけただろうか。だが、1つできないことがある。BitmapData.draw() を使って BitmapData に転写しようとすると、セキュリティサンドボックス侵害の例外が発生するのだ。
セキュリティサンドボックス侵害 : BitmapData.draw:http://localhost/ImageLoader1.swf は http://img.mixi.jp/img/basic/common/mixilogo001.gif にアクセスできません。ポリシーファイルが必要ですが、このメディアがロードされたとき、checkPolicyFile フラグが設定されませんでした。
同様に、Loader で読み込んだ音声ファイルを SoundMixer.computeSpectrum() しようとしたときにも例外が発生する。
このように、外部ドメインからロードしたメディアに対して、ピクセルデータやオーディオデータに直接アクセスすることは許可されない。表示・再生はできるのに、そのメディアを構成するデータを見ることはできない、というわけだ。
対処法は以下の2通り。
画像が置いてあるドメインのクロスドメインポリシーファイル(いわゆる crossdomain.xml)で、アクセスが許可されている場合、データとしてアクセスできる。
(追記) AS2 では crossdomain.xml があっても、BitmapData.draw() できないらしい。
例えば、Flickr のようなサービスでは、全てのドメインからのアクセスを認める設定が記述されている。
<?xml version="1.0" ?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <allow-access-from domain="*" secure="true" /> </cross-domain-policy>
一方、mixi にも crossdomain.xml はあるのだけど、現時点では任意のドメインからのアクセスは許可されていない。
<?xml version="1.0" ?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <allow-access-from domain="*.mixi.jp" secure="true" /> </cross-domain-policy>
では、実際にロード時に crossdomain.xml を読み込ませてみよう。といっても2箇所修正するだけだ。
// LoaderContextを準備 var context:LoaderContext = new LoaderContext(true); var loader:Loader = new Loader(); var req:URLRequest = new URLRequest("http://www.example.com/sample.gif"); loader.load(req, context); // 第2引数に context を渡す addChild(loader);
LoaderContext の checkPolicyFile を true にするところがポイント。これ以外に、Security.loadPolicyFile() メソッドを使って、事前に読み込んでおく方法もある。loadPolicyFile() を使うと、crossdomain.xml 以外の URL からクロスドメインポリシーファイルを読み取ることができる。
crossdomain.xml が存在しない場合、もしくは許可されなかった場合にも、画像はロードされる。ロードした段階では例外も発生しない。BitmapData.draw() しようとした段階になって初めて例外が出るので注意が必要だ。
では、どうやって許可されたかを調べるかというと、実際に試してみて例外を拾うのが一番簡単。
loader.contentLoaderInfo.addEventListener("complete", function(event:*):void{ var bmd:BitmapData = new BitmapData(loader.width, loader.height); try{ bmd.draw(loader); } catch(e:SecurityError){ trace(e.toString()); } });
もう1つの方法として、loader.contentLoaderInfo.childAllowsParent で調べることもできる。
loader.contentLoaderInfo.addEventListener("complete", function(event:*):void{ if(loader.contentLoaderInfo.childAllowsParent) { // あとはお好きに } });
どちらでもお好きな方を。
具体例を1つ。
assets2.twitter.com から動的に twitter のロゴを読み取って getPixel している。ロゴの上にマウスを持っていくと、マウスの下の色が表示される。ソースは こちら (44行)。
(追記)twitter.com の crossdomain.xml の制約が強化されて、getPixel 出来なくなりました。
Firebug の Net タブを見れば、crossdomain.xml とロゴを拾ってきていることが確認できるだろう。

諦めろ。もしくは、自鯖に proxy となる CGI を設置するしかない。
その他、注意点、気づいたことなど。
関連URL:
標準Adobe AIR完全解説 に共著者として参加しました。