— boreal-kiss.com

Archive
Tag "メモ"

FLASHをブログパーツにして配布する場合にはJavaScriptに収めてしまってJSスクリプトを配布する方法がある。しかし自分が今までやっていた方法だとJS経由でFLASHに変数を渡す場合に問題が起こる可能性があることがわかったのでその解決方法について。まず今までの問題のある書き方の場合、例えばJSファイルを以下のように記述していた。

//"http://example.com/showme.js"
function showMe(userid){
    //swfを表示するのに必要な<object>タグ全体。実際は改行無し
    var obj = '<objcet>
            ...略...
            <param name="FlashVars" value="userid='+userid+'" />
            ...略...
            <embed ...略...FlashVars="userid='+userid+'"></embed></object>';
    document.write(obj);
}

配布用ソースをは以下のような書式。

//配布用html貼付けソース
<script type="text/javascript" src="http://example.com/showme.js"></script>
<script type="text/javascript">showMe("borealkiss");</script>

この場合、(万が一)ユーザーがすでにshowMeという関数を他で定義していると関数名がコンフリクトを起こす(以下の例ではユーザーの期待に反しブログパーツが二個表示される)。

<html>
<head>
<!--ユーザー定義のshowMe関数-->
<script type="text/javascript">
function showMe(name){
    alert("Welcome, " + name + "!");
}
</script>
</head>

<body>
<!--ブログパーツのshowMe関数-->
<script type="text/javascript" src="http://example.com/showme.js"></script>
<script type="text/javascript">showMe("borealkiss");</script>

<!--ユーザー定義のshowMe関数を実行させるつもりだったのに!-->
<script type="text/javascript">showMe("borealkiss");</script>
</body>
</html>

このコンフリクトはこちらが定義した関数を匿名関数(無名関数)でラップしてしまい、その場で匿名関数を実行させることで回避できる(special thx: YungSang)。

//"http://example.com/showme.js" 修正版
(function(){
    function showMe(userid){
        var obj = '<objcet>
                ...略...
                <param name="FlashVars" value="userid='+userid+'" />
                ...略...
                <embed ...略...FlashVars="userid='+userid+'"></embed></object>';
        document.write(obj);
    }
    showMe(window._com_example_showMe_userid);
})();

配布ソースは以下のように修正。

//配布用html貼付けソース修正版
<script type="text/javascript">var _com_example_showMe_userid = "borealkiss"</script>
<script type="text/javascript" src="http://example.com/showme.js"></script>

ポイントは匿名関数でラップしてしまうことでブログパーツ表示用関数をローカルスコープにすること;

function(){
    function showMe(...){
        ...
    }
    showMe(***);
}

それと匿名関数をその場で実行させることだ;

(function(){...})();

これでwindow上で定義した変数”_com_example_showMe_userid”がコンフリクトしなければユーザーに迷惑をかけることはないはず。そのためにできるだけユニークな変数名にするとよい(例えば自ドメイン名に由来するものetc.)。

[関連リンク]
JavaScript++かも日記: 【JavaScript】匿名関数で匿名スコープ&インスタンス

Read More

別ドメインの画像を読み込む場合のLoaderクラスについていくつかメモ、クロスドメインポリシーファイル(crossdomain.xml)の読み込み方法と画像ロード速度について。結果的には画像20枚2M程度だと気にするほどでもなかった。Loaderクラスの詳細はAS で別ドメインの画像を読み込むときの注意点 – てっく煮ブログが参考になる。まずLoaderクラスの重要な性質を列挙。

  • crossdomain.xmlの設定に無関係に画像のロードは可能。(その後の画像の扱いにかかわらず必ずload()を行う)
  • 画像を画像として扱う(ただ画像を表示する)場合にはcrossdomain.xmlによる許可は必要ない。つまりどこの画像であろうと表示は可能。
  • 画像をデータとして扱う(サイズを変更するetc.)場合にはcrossdomain.xmlの許可が必要。
  • デフォルトでcrossdomain.xmlを読まない。(URLLoaderクラスは読む)

Loaderクラスを用いて別ドメインの画像をデータとして扱う方法は以下の二種類。どちらもロード完了後、(crossdomain.xmlで許可されている場合)画像データにアクセスが可能になる。

  1. Security.loadPolicyFile()関数でcrossdomain.xmlを読み込ませ、swfファイルに許可があることを知らせてからロードを始める。(実際にはcrossdomain.xmlを読み込むまでロードは自動待機)
  2. //Ex., media.tumblr.com
    Security.loadPolicyFile("http://media.tumblr.com/crossdomain.xml");
    var loader:Loader = new Loader();
    var req:URLRequest = new URLRequest("http://media.tumblr.com/xxx.jpg");
    loader.load(req);
    
  3. LoaderContextクラスのcheckPolicyFileプロパティを用いて、ロードごとにcrossdomain.xmlを読むよう指示する。
  4. var context:LoaderContext = new LoaderContext(true);
    var loader:Loader = new Loader();
    var req:URLRequest = new URLRequest("http://media.tumblr.com/xxx.jpg");
    loader.load(req, context);
    

上記二種の違いは、ロード前にcrossdomain.xmlを読み込ませるか、ロードごとにcrossdomain.xmlを読み込ませるかの違いでなので、画像のロード数が増えると両者の実行速度に差がでてくるのではないかと予想される(Security.loadPolicyFile()を使った方が早そう)。実際に調べてみた。以下はFirefoxのキャッシュを消去してからmedia.tumblr.comの画像20枚(1.7M)を読み込ませた結果をFirebugで表示したもの。左列に読み込んだファイル名一覧、右側にそれぞれ表示完了までにかかった時間が表示されている。

  1. Security.loadPolicyFile()関数を用いた場合 (11.75s)
  2. Security.loadPolicyFile()関数を用いた場合

  3. LoaderContextクラスを用いた場合 (13.21s)
  4. LoaderContextクラスを用いた場合

Security.loadPolicyFile()関数で一回だけcrossdomain.xmlを読み込んだ場合の方が完了が早くなっているが、実験のインターネット環境がよくないのであまり信用しないでください。場合によってはLoaderContextクラスでロードごとにcrossdomain.xmlを読み込ませる場合の方が早かったりもしたのでなんともいえない。結論としては両者に大差なし。というかLoaderContextクラスを用いた場合でも二回目以降同じcrossdomain.xmlの読み込みはキャッシュ化されてるから差がでてないのかもしれない。面白いのは上記二つの方法でcrossdomain.xmlをロードするタイミングが異なること。Security.loadPolicyFile()関数を用いた場合全画像をロード後、LoaderContextクラスを用いた場合画像ロード前にcrossdomain.xmlが読み込まれていて、イメージと逆なので不思議。日本の安定している快適なインターネット環境で誰か実験するのを期待しつつ、以下実験のソースコード。

package {
    import flash.display.Sprite;
    import flash.display.Loader;
    import flash.events.Event;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import flash.system.Security;
    
    public class LoadTest extends Sprite {
        public function LoadTest() {
            
            // 20 sexy images from media.tumblr.com
            var URLs:Array = [
            "http://media.tumblr.com/rJ6tpU7iW6y88so6TV84T1IG_500.jpg",
            "http://media.tumblr.com/z5Ki84RwK7e6bfe7zaGZCGUR_500.jpg",
            "http://media.tumblr.com/F2GLxhk3c6x444v1vma5BvIX_500.jpg",
            "http://media.tumblr.com/1gOzmif8i8oz2hz9GJ68aqBc_500.jpg",
            "http://media.tumblr.com/ky9cwXAKO8pyvjydMxesdNtr_500.jpg",
            "http://media.tumblr.com/7MmWU7n9s8l2gik4NKAlJjev_500.jpg",
            "http://media.tumblr.com/kcq2O9G2O8nggwncmiXj5Q8Z_500.jpg",
            "http://media.tumblr.com/5Vq1ESVSU8mn4n9raQLSFR6q_500.jpg",
            "http://media.tumblr.com/5Vq1ESVSU8mmwc4gekPbI9tl_500.jpg",
            "http://media.tumblr.com/0hxKQCklp2vdfmjiczTJn7v4_500.jpg",
            "http://media.tumblr.com/5Vq1ESVSU8mmtx38rZpmce95_500.jpg",
            "http://media.tumblr.com/0hxKQCklp2vdeqr003dmPyAo_500.jpg",
            "http://media.tumblr.com/0hxKQCklp4amrjwdD250Zy02_500.jpg",
            "http://media.tumblr.com/0hxKQCklp5kgx39bYjGWw6tB_500.jpg",
            "http://media.tumblr.com/0hxKQCklp6hoyaquSCmhzDXR_500.jpg",
            "http://media.tumblr.com/0hxKQCklp5xcqrjwzCIQggYR_500.jpg",
            "http://media.tumblr.com/0hxKQCklp6iz6is1QQJOQpi2_500.jpg",
            "http://media.tumblr.com/0hxKQCklp7swil3bMb5BHmae_500.jpg",
            "http://media.tumblr.com/FXGYbGlnr2pn7ftwSjgoCUtC_500.jpg",
            "http://media.tumblr.com/rJ6tpU7iW7smq0v5T9rpyo7w_500.jpg"];
            
            //loadModule1(URLs);
            loadModule2(URLs);
            
        }
        
        private function loadModule1(imgAry:Array):void{
            //Include crossdomain.xml from media.tumblr.com, once.
            Security.loadPolicyFile("http://media.tumblr.com/crossdomain.xml");
            
            var loaderAry:Array = new Array();
            
            for (var i:int=0; i<imgAry.length; i++){
                var loader:Loader = new Loader();
                var req:URLRequest = new URLRequest(imgAry[i]);
                loader.load(req);
                loader.contentLoaderInfo.addEventListener(Event.INIT,init);
                loaderAry.push(loader);
            }
        }
        
        private function loadModule2(imgAry:Array):void{      
            var loaderAry:Array = new Array();
            
            for (var i:int=0; i<imgAry.length; i++){
                var loader:Loader = new Loader();
                var req:URLRequest = new URLRequest(imgAry[i]);
                
                //Include crossdomain.xml per image (i.e., 20 times)
                var context:LoaderContext = new LoaderContext(true);
                loader.load(req,context);
                loader.contentLoaderInfo.addEventListener(Event.INIT,init);
                loaderAry.push(loader);
            }
        }
        
        private function init(e:Event):void{
            addChild(e.target.content);
        }
    }
}

Read More

ブログパーツでFLASHを別ドメインで表示させる時、読み込み外部ファイルがある場合はそのファイルのロケーションをURLで指定しないといけない(相対パス不可)。URLでの指定はディレクトリの変更があった場合に柔軟に対処できないので極力避けたい。じゃあSWFに埋め込んでしまおうと思い、XMLファイルの埋め込み方法で悩んだ。FlexのEmbedメタタグはデフォルトでXML形式のデータを理解しないので、形式を気にせずとりあえず読み込ませてその後XMLに強制変換してやる必要がある。

埋め込みに使用する MIME タイプは application/octet-stream として指定する必要があります。これにより、バイトデータは、解釈されずにそのまま埋め込まれます。

mx.core.ByteArrayAsset (Flex 3)- adobe

ソース内部で型を変換できるタイプのデータだったらなんでもいけるっぽい。XMLデータ埋め込みの例は以下の通り。

package {
    public class myClass{

        [Embed(source="mydata.xml", mimeType="application/octet-stream")]
        private var myData:Class;

        public function myClass(){
            var myXML:XML = new XML(new myData());
        }
    }
}
Read More

理想的にはクラス内のプロパティは全てprivateにして、クラス外部からプロパティに直接アクセスさせず、かわりにgetter/setterメソッドと呼ばれる関数を用いてプロパティの参照や変更を行うことがOOPで推奨されてるらしい。直接アクセスされて不都合がある理由はよくわからんが、こういった慣例には従っておいた方がよいだろう。

オブジェクト指向プログラミングを実践する際には、クラスのプロパティに直接アクセスすることは推奨されません。クラスではよく、特定のプロパティの読取り用のアクセスに”get”メソッド、書込み用のアクセスに”set”メソッドを定義するということが行われます。

FN0311009 – 黙示的なget/setメソッド – Flash : テクニカルノート

ところでこのsetter/getterメソッドで使う関数名、なんと操作したいプロパティ名と同じ関数名をつけれない。これじゃ使い物にならんがな、と思ってたけどKeith Petersがプロパティ名の頭にアンダースコア(“_”)をつける方法で解決してた。例えばmessageというプロパティにsetter/getterメソッドを用いる場合、こんな感じ。

package{
    public class SomeClass{
        
        private var _message:String;
        
        public function SomeClass(){
            //Some codes here.
        }
        
        public function set message(s:String):void{
            _message = s;
        }
        
        public function get message():String{
            return _message;
        }
    }
}

これで、クラス外部でこのプロパティ値を変更したい場合はsetter関数経由で

var sc:SomeClass = new SomeClass();

//same as sc.message("Shut the fuck up!!");
sc.message = "Shut the fuck up!!";

クラス外部でこのプロパティ値を参照したい場合はgetter関数経由で

//same as trace(sc.message());
trace(sc.message);

なるほど、getter/setterメソッドを用いる場合のプロパティにはアンダースコアを付けるように決めてしまえば、以下のようにソースを見て混乱することもないし、しかもAS2をやってる人には馴染み深いしね。いいチップだ。

getter メソッドと setter メソッドは便利ですが、多用しすぎるとコードの保守が困難になる場合もあるので注意が必要です。

adobe – getter メソッドと setter メソッドについて

Read More

行列で書くとわかりやすい。ColorMatrixFilter(引数a0 – a19の計20個!)による元のピクセル値(R, G, B, alpha)とフィルター処理後のピクセル値(R_new, G_new, B_new, alpha_new)の関係は以下の通り。

theDisplayObject(DisplayObjectのサブクラス or BitmapDataクラス)に上記フィルターをかける場合は以下の通り。


import flash.filters.ColorMatrixFilter;

var matrix:Array = new Array();
matrix = matrix.concat([a0,a1,a2,a3,a4]);	//R
matrix = matrix.concat([a5,a6,a7,a8,a9]);	//G
matrix = matrix.concat([a10,a11,a12,a13,a14]);	//B
matrix = matrix.concat([a15,a16,a17,a18,a19]);	//alpha
var f:ColorMatrixFilter = new ColorMatrixFilter(matrix);
theDisplayObject.filters = [f];

ColorMatrixFilter クラスを使用すると、入力イメージの各ピクセルの RGBA カラー値とアルファ値に 4 × 5 マトリックス変換を適用することで、新しい RGBA カラー値とアルファ値から成る結果を作成できます。

ColorMatrixFilter – ActionScript 3.0 コンポーネントリファレンスガイド

[関連リンク]
幕末古写真ジェネレータをハックする – てっく煮ブログ

Read More

定義を誤解しやすい

Adobe – ActionScript 3.0 コンポーネントリファレンスガイドの説明によると、フィルター処理に使われる式は以下のとおり。


dstPixel[x, y] = srcPixel[x + ((componentX(x, y) - 128) * scaleX) / 256,
y + ((componentY(x, y) - 128) * scaleY) / 256)]

ごちゃごちゃしている部分をdx, dy(dx, dyの中身については後ほど説明するとしてここでは何らかの変位量と思ってもらえればok)に書き換えて見やすくするとこんな感じ。


dstPixel[x, y] = srcPixel[x + dx, y + dy]

ここでdstPixelとsrcPixelを一般的な形で説明すると

  • dstPixel[x, y]はx-y座標(x, y)におけるフィルター処理後の表示画像のピクセル値
  • srcPixel[x, y]はx-y座標(x, y)におけるフィルター処理前の表示画像のピクセル値

したがって上式を翻訳すると「位置(x, y)におけるフィルター処理後の画像のピクセル値は、位置(x+dx, y+dy)におけるフィルター処理前の画像のピクセル値を採用している」となる。座標系がフィルター処理後の画像を元にしているところがポイント。「位置(x, y)におけるフィルター処理前の画像のピクセルを(x+dx, y+dy)に移動させてその結果を処理後の画像として採用する」演算ではない。まとめておくとDisplacementMapFilterは

  • (正) 位置(x, y)におけるフィルター処理後の画像のピクセル値に、位置(x+dx, y+dy)におけるフィルター処理前の画像のピクセル値を採用するフィルター
  • (誤) 位置(x, y)におけるフィルター処理前の画像のピクセルを(x+dx, y+dy)に移動させてその結果を処理後の画像として採用するフィルター

となる。ここの仕組みが直感的ではないのでわかりにくい。他にも元画像の位置(x+dx, y+dy)にピクセル情報がないことにはフィルター処理不可能なことがわかる。つまり、元画像のサイズ以上に引き延ばしたりする変形を表現することはできない。

変位(dx, dy)の求め方

フィルター処理前・後のピクセルの変位量の分布さえわかれば意図したフィルター効果を表現できる。具体的な関係式の求め方はpsyark.jp – DMFチュートリアル1がわかりやすい。

置き換えマップイメージ

さて画像は2Dなので各ピクセルごとにx, y方向の2成分の変位量(dx, dy)がわからないといけない。各ピクセルごとの変位情報を(手軽に)2成分もたせるためにはどうすればよいか。そこで登場するのが置き換えマップイメージ。各ピクセルにアルファ、R、G、Bの情報を独立して持たせることができるという画像の性質を利用して、(dx, dy)の変位分布を画像情報として押し込めてしまうわけ。独立して格納したい情報は(dx, dy)の2成分なので、置き換えマップイメージのアルファ、R、G、Bチャンネルの4チャンネルのうちお好みの2チャンネルに格納すればよい(例えばdx情報をR、dy情報をBなど。dx, dyに同じチャンネルを使う場合も含めれば選択肢は4×4=16通りもある)。この中途半端に選択肢の自由度があるところがわかりにくい。([dx, dy]分布情報を格納できれば原理的には二次元配列などでもよいが、配列に格納するのが面倒くさいし、そもそもこのフィルターの演算に採用されていないので意味がない)

Adobeが定義している式に戻ってみると、(dx, dy)は次のような式であることがわかる。


dx = (componentX(x, y) - 128) * scaleX / 256
dy = (componentY(x, y) - 128) * scaleY / 256

ここでcomponentX(x, y)は位置(x,y)におけるマップイメージのdxを格納したチャンネル(つまりアルファ、R、G、Bのどれか)のピクセル値(0-255)、componentY(x, y)は位置(x,y)におけるマップイメージのdyを格納したチャンネルのピクセル値(0-255)が入る。scaleX, scaleYはフィルター使用時に後から好きな値が入れられる(0以上の数値)のでわかりやすくするため1を代入しよう。そうすると、上式は以下のようになる。


dx = (componentX(x, y) - 128) / 256
dy = (componentY(x, y) - 128) / 256

画像の各チャンネルは0-255の数値しかとれないので、この場合変位量は-1/2から1/2の値をとることがわかる。変位幅を大きくしたいならscaleXとscaleYをフィルター利用時に調整すればよい(これは例えば、-10から10までの乱数を得るのに(Math.random()-0.5)*20と書くのに似ているかな)。置き換えマップイメージと変位の関係はmiscellaneous [ActionScript 3.0] DisplacementMapFilterがわかりやすい。

Read More

CircleParticle


CircleParticle(	x:Number, y:Number, radius:Number,
fixed:Boolean = false, mass:Number = 1,
elasticity:Number = 0.3, friction:Number = 0)

x:Number: 初期x座標
y:Number: 初期y座標
radius:Number: 円の半径。ゼロok。
fixed:Boolean: オプショナル。初期位置に固定するかどうか(true=固定、false=非固定)。デフォルトはfalse。
mass:Number: オプショナル。質量。デフォルトは1。
elasticity:Number: オプショナル。弾性率。デフォルトは0.3。
friction:Number: オプショナル。表面摩擦係数。デフォルトは0(減衰無し)。

Read More

メモ。

シングル・ダブルクオーテーションに関する動作を示すオプションの第2の引数をとり、無指定でデフォルトはENT_COMPAT(ダブルクオーテーションを変換、シングルクオーテーションを無変換)。ENT_QUOTESでダブルおよびシングルクオーテーションをそれぞれ”、’に変換。


<?php
$text = htmlspecialchars($_POST['text'], ENT_QUOTES);
?>

[Reference]
htmlentities – PHPマニュアル
htmlspecialchars – PHPマニュアル

Read More

ブログでレベルアップが時々画面真っ白になって何も表示されないことがあったんだけど、理由はこれかもしれない。一応.htaccessに書いてみたけど、どうなんだろ。確認しにくいな。

可能性として、運用されているPHPスクリプトと、サーバー側でのPHP高速化・キャッシュモジュールとの相性の問題が発生していることがあります。その場合は、下記コマンドを「.htaccess」に記載してください。


php_flag apc.cache_by_default off

(PHPでのエラー対策について – CORESERVER.JP:コアサーバーより)

それと、これはどういう意味だ?外部からうちのドメインのファイルはリモートで読めないようになってるってことなんかな。なるほどね。

標準で、include()/require()によるURLの取得ができなくなっております。おすすめいたしませんが、ご利用いただくには、下記コマンドを「.htaccess」に記載してください。


php_flag allow_url_fopen on
php_flag allow_url_include on
Read More

FLASHのload関数で直接読み込めないファイル(異なるドメインのXMLファイル等)は、PHP等のサーバー側スクリプト言語を利用することでFLASHに読み込ませることができる。PHPを使う場合の手順は以下の通り(具体的なソース等はこちらを参照)。

  1. FLASHからPHPへ。SendAndLoad関数等を用いてPHPへ読み込みたいファイルのURLを送信する。
  2. PHP内部処理。PHPのreadfile関数等で指定されたファイルを読み込む。
  3. PHPからFLASHへ。読み込んだファイル内容(標準出力)をFLASHのSendAndLoad関数の返り値に送り返す。
  4. FLASH内部。SendAndLoad関数の返り値を受け取って続きの処理へ。

しかし、FLASHの日本語文字コードはShift-JISとUTF-8にしか対応していないので(FLASH ActionScript辞典より。ちなみにクソ本)、EUC-JPで記述されたブログ(FC2等)のXMLファイルをPHPでそのまま読み込んでFLASHに送り返すと文字化けしてしまう。そこでPHPで読み込んだファイル内容を文字コードを変換してからFLASHに送り返す必要がある。以下はPHPからFLASHへUTF-8にエンコーディングしてから送るためのPHP内部の処理。


<?php

//readfile関数の内容を標準出力せずに内部バッファに保存させる
ob_start();

//FLASHから送信されたURL先のファイル内容を読み込む(標準出力されない)
readfile($_POST['url_from_flash']);

//内部バッファに保存された内容を変数に格納する
$str = ob_get_contents();

//内部バッファの開放
ob_end_clean();

//上記で変数に格納された内容がEUC-JP, Shift-JIS, UTF-8の場合、UTF-8に再エンコーディング
echo mb_convert_encoding($str,'UTF-8', 'EUC-JP,Shift_JIS,UTF-8');

//UTF-8にエンコーディングされた内容を標準出力(出力内容がFLASHへ送信される)
echo $str;
?>

追記(2007/12/17): なんかコードがダメ出しされてる。ただ肝心な部分のフィードバックがないので何がダメなのかわからず終い。

追記(2007/12/19): 先方で詳細コメント・解説をもらえた。単独では知り得なかった現在の状況が把握できたので有益なTB。

Read More