2008年7月アーカイブ

一部更新、追加があったのでdocsも更新しときました。
といっても、このライブラリ使ってんの僕だけだったりして。

Utils
http://www.libspark.org/browser/as3/Utils/src/org/libspark/utils

asdocs
http://www.libspark.org/htdocs/as3/utils/

ダウンロード
http://www.libspark.org/svn/as3/Utils/docs/utils_docs.zip

是非挑戦してみてください。
先攻・後攻は「SETTING」ボタンから変更できます。


ルール
  • 同じ行なら何個でも取れます。
  • 間を飛ばして取ることはできません。
  • 最後の1つになったら負け


FlashDeverop + FlexSDK で作ってます。
Flash IDE は今回使ってません。
FlexSDK だと、書き出しが早くてすばらしいですね。

AS3 で FLV のメタデータの取り方が分からずに、かなり無駄に時間を費やしてしまった。。。
FLV のメタデータは NetStream から onMetaData を使って取得できるんだけども、
この onMetaData の使い方がさっぱり分からなかったので忘れないようにメモ。
経過があまりにもアホくさすぎて絶対忘れないけども。

ビデオメタデータの使用
NetStreamオブジェクトの client プロパティを指定して、
指定したオブジェクトに onMetaData メソッドを定義しておくと使える。

この client プロパティの存在に気づかずに四苦八苦してた自分が情けない。

挙句の果てに、ここ見て自前で ByteArray からメタデータ取ろうとしてしまった。

ByteArray から取得した FLV の値を出力した一例。
// FLV Header
Signature = FLV
Version = 1
Flags = 5
Offset = 9

// FLV Stream
PreviousTagSize = 0

// FLV Tag
Type = 18
BodyLength = 224
Timestamp = 0
TimestampExtended = 0
StreamId = 0

// MetaData
videodatarate = 1000
audiocodecid = 2
canSeekToEnd = true
duration = 8.866
audiodatarate = 128
framerate = 30
width = 450
videocodecid = 4
height = 400
audiodelay = 0.038

アホですよ。まったく。

ここまでやって、ちゃんと取得できることに気づいた。
そもそも何で AS3 なのに NetStream はこんな実装なんだ。
腹立たしい。アホか!

一応以下にソース残しときます。
結果的に中途半端なものになってますが、
なんか消してしまうのも勿体ない気がしてしまって。(費やした時間が。)

public function readFLV(data:ByteArray):void
{
    // FLV Header
    var Signature:String = data.readUTFBytes(3);
    var Version:uint = uint8(data);
    var Flags:uint = uint8(data);
    var Offset:uint = uint32(data);
    
    // FLV Stream
    var PreviousTagSize:uint = uint32(data);
    
    // FLV Tag
    var Type:uint = uint8(data);
    var BodyLength:uint = uint24(data);
    var Timestamp:uint = uint24(data);
    var TimestampExtended:uint = uint8(data);
    var StreamId:uint = uint24(data);
    var Body:ByteArray = new ByteArray();
    data.readBytes(Body, 0, BodyLength);
    
    
    // Body(FLV Tag Type = 0x12 : AMF)
    var a:uint = uint8(Body);// ???
    var b:uint = uint8(Body);// ???
    
    // MetaData
    readString(Body);
    var metadata:Object = readMixedArray(Body);
    
    
    trace(Signature, Version, Flags, Offset);
    trace(PreviousTagSize);
    trace(Type, BodyLength, Timestamp, TimestampExtended, StreamId);
    
    // MetaData の中身
    for (var val:String in metadata) {
        trace(val + "=" + metadata[val]);
    }
    
}

public function  uint8(data:ByteArray):uint { return data.readByte(); }
public function uint16(data:ByteArray):uint { return data.readUnsignedShort(); }
public function uint24(data:ByteArray):uint { return data[data.position++]<<16 | data[data.position++]<<8 | data[data.position++]; }
public function uint32(data:ByteArray):uint { return data.readUnsignedInt(); }

public function readNumber(data:ByteArray):Number
{
    return data.readDouble();
}
public function readBoolean(data:ByteArray):Boolean
{
    return data.readByte() == 0x01;
}
public function readString(data:ByteArray):String
{
    var len:uint = data.readByte();
    return data.readUTFBytes(len);
}
public function readObject(data:ByteArray):Object
{
    return null;
}
public function readMixedArray(data:ByteArray):Object
{
    data.readByte();
    var length:uint = data.readInt();
    var res:Object = { };
    var value:*;
    var name:String;
    var type:uint;
    var len:uint = data.length;
    for (;; ) {
        var separator:uint = data.readByte();
        name = readString(data);
        type = data.readByte();
        
        if (type == 0x09) break;
        
        switch(type) {
            case 0x00 : { value = readNumber(data); break; } // Object
            case 0x01 : { value = readBoolean(data); break; } // Object
            case 0x02 : { value = readString(data); break; } // Object
            case 0x03 : { value = readObject(data); break; } // Object
            //case 0x04 : { break; } // Movie Clip
            case 0x05 : { value = null; break; } // Object
            case 0x06 : { value = undefined; break; } // Object
            //case 0x07 : { break; } // Reference
            case 0x08 : { value = readMixedArray(data); break; } // MixedArray
            case 0x0a : { value = readArray(data); break; } // Array
            case 0x0b : { value = readDate(data); break; } // Date
        }
        res[name] = value;
    }
    return res;
}
public function readArray(data:ByteArray):Array
{
    return null;
}
public function readDate(data:ByteArray):String
{
    return null;
}
リンケージの設定と同時にクラスファイルを自動生成する
Flash CS3 用の JSFLコマンドをアップしました。

LinkageSettings.mxp

Flashのメニューから「コマンド」>「LinkageSettings」で使用できます。
このコマンドを呼び出す際は、以下の条件が必要です。

  • flaファイルが保存されたもの。
    (新規作成で開いた状態で未保存の場合は使用できません。)
  • ステージ上のシンボル、もしくはライブラリ内のシンボルを1つ以上選択した状態であること。
  • ドキュメントのActionScriptのバージョンが3であること。

まだベータ版ってことで、Macで検証できてないのと、 AS2 には使用できません。
実行すると以下のダイアログが表示されます。



特徴
  • ステージ上、もしくはライブラリ内で選択中の複数のシンボルをまとめてリンケージ設定可能
  • リンケージの設定対象は MovieClip, Bitmap, Font, Sound, Button の5種類です。
  • リンケージ設定時にクラスファイルが存在しない場合、自動で生成することができます。
  • クラスファイルの自動生成時に特定のイベントを追加しておくことができます。
  • クラスファイルの自動生成時にEmbedタグを設定しておくことができます。
  • 複数選択時、クラス名に*を使用することで、各シンボル名と同名のクラスを作成します。
    例)classes.display.*
  • 複数選択時、基本クラス名に*を使用することで、
    各アイテムのデフォルトで割り当てられるクラスを基本クラスに設定することができます。
  • 対象がムービークリップの場合、内包するインスタンス名を変数宣言しておくことができます。
  • 対象がムービークリップの場合、タイムライン上のスクリプトを調べて、クラス内に addFrameScript として設定することができます。
  • 書き出すクラスファイルのテンプレートは単独のファイルとなっているため、比較的容易に編集が可能です。
    "Commands/seyself/templates/as3_class.tmpl" がテンプレートファイルです。
    テンプレートファイル内で[XXXX]と書かれている箇所が、
    それぞれ置き換えられる場所になっているので、編集の際はご注意ください。

注意事項
  • まだ検証が十分ではありませんので、ご使用には注意してください。
    特に複数のシンボルをまとめてリンケージ設定する際に、クラス生成も同時に行うと
    予期せぬ結果になる可能性があります。
  • クラスパスは相対パスで記述してください
  • Embedタグを追加した際、自動的にswfファイルへの参照が記述されますが、
    この機能はflaファイルの位置を指しています。
    flash側でパプリッシュ先を、他のディレクトリに指定を変更した場合でも、
    flaファイルの位置を元に書き込まれます。

困ってること
  • Flash側でSWFのパブリッシュ先を変更した場合の、書き出し先の取得方法が分かりません。
  • XULがよく分からず、表示パネルの外枠がやたらデカくて困ってます。
  • Mac にて検証する環境がないため、ディレクトリの指定等がまったく分かりません。

もしどなたか Mac 環境で検証してくれるって方がおられましたら
是非以下の JSFL ファイル(DirectoryTest.jsfl)を使用して、
出力された結果を教えていただけませんでしょうか。

directory_access_test.jsfl

ちなみに「 Windows XP SP2 / Flash CS3 」での出力結果は以下のようになりました。 ご参考まで。
//==== Directory Access Test ====

■fl.configURI =
file:///C|/Documents%20and%20Settings/wada/Local%20Settings/Application%20Data/Adobe/Flash%20CS3/ja/Configuration/

■document.path =
D:\wada\00_works\2008_latter\20080709_test_commands\flash\20080709\index.fla

■fl.browseForFolderURL() =
file:///C|/flex_sdk_3/bin

■fl.browseForFileURL() =
file:///C|/Program%20Files/Adobe/Adobe%20Flash%20CS3/Flash.exe

//==== Test Complete ====

以後、ゆっくりとですが調整していく予定です。

現状 Flash CS3 では、 JSFLで画像(BitmapItem)のリンケージ設定で
「ActionScript に書き出し」の設定をしようとしても値が false のままで変更できません。
item.linkageExportForAS = true;
alert(item.linkageExportForAS); // output : false
lib.setItemProperty('linkageExportForAS', true);
alert(item.linkageExportForAS); // output : false
プロパティを直接設定しても、 setItemProperty を使っても同じです。

で、ちょっと無茶な方法ですが以下のようにスクリプトを変更します。
var item = fl.getDocumentDOM().library.getSelectedItems()[0];
if(item.itemType=="bitmap") item.linkageExportForRS = true;
item.linkageExportForAS = true;
item.linkageExportInFirstFrame = true;
こうすると、ライブラリからマウス操作でリンケージパネルを開いたとき、以下のようになります。



このように「ランタイム共有用に書き出し」が true に設定された状態で、
「ActionScript に書き出し」は設定されていないという、パネルを直接操作しても
再現出来ないようなおかしなことになってますが、このときのBitmapItem のプロパティを
出力すると以下のようになります。
linkageExportForRS = true
linkageExportForAS = undefined
linkageExportInFirstFrame = true
linkageClassName = image.jpg
linkageBaseClass = 
allowSmoothing = false
compressionType = photo
quality = -1
useImportedJPEGQuality = true
itemType = bitmap
name = items/image.jpg
linkageImportForRS = undefined
linkageIdentifier = image.jpg
linkageURL = 
linkageClassName(太字)のところを見ると、クラスが設定されています。
この状態であれば、linkageClassName、linkageBaseClass 共にスクリプトで設定しなおすことが出来ます。
linkageURL はそのまま空でもパブリッシュは可能です。

このJSFLコマンドを実行した後、リンケージパネルを変更せずに
以下の ActionScript をタイムラインに書いてプレビューしてみると、
ちゃんと書き出されてることが確認できます。
linkageClassName は JFSL に追記して "image_jpg" に変更しています。
import flash.display.Bitmap;
addChild(new Bitmap(new image_jpg(1,1)));
ただし、「ランタイム共有用に書き出し」を行ってしまうので、これを使うと
Bitmap に設定したクラス名とファイルを配置した SWF の URL が分かれば、
他のドキュメントソースファイルから「ランタイム共有用に読み込み」で読み込んでしまえる。

残念ながら linkageExportForRS を false にすると、結局 AS への書き出しも行われなくなってしまうので
今のところ対処方法はまだわかりません。無いのかもしれない。

FlashDevelop + FlexSDK とかで開発する上で、
SWF から [Embed] タグで画像を読み込む分には使えるかもしんない。
それをしないといけない状況があるかどうかなんですが。

Spark Project の Utils ライブラリの ASDoc を書き出してアップしてみました。
HTMLでアップするとファイルが多いのでZIPに圧縮してます。

あとちょろちょろとクラスファイルを足してます。
何か無駄なところも多々あると思います。
実装が微妙なところも結構あります。EventUtil とか。

Utils
http://www.libspark.org/browser/as3/Utils/src/org/libspark/utils

utils_docs.zip
http://www.libspark.org/svn/as3/Utils/docs/utils_docs.zip


とりあえず、今こんなのが入ってるってのが把握できればと思います。

今までまったく気づかなかったことなんですが
addEventListener("enterFrame", handler);
function handler():void {}
ってすると
ArgumentError: Error #1063: _fla::MainTimeline/handler() の引数の数が一致していません。0 が必要ですが、1 が指定されました。
ってエラーが出て怒られるんだけども、
addEventListener("enterFrame", handler);
function handler():void { arguments; }
上記の場合はそのまま何事もなく実行される。
上記のようにイベントハンドラの中に「arguments」が入ってると、引数は別に定義されてなくてもいいみたい。

これは引数の数は関係ないみたいだけども、「...rest」が入ってると「arguments」が使えなくなるのでダメっぽい。
まあ、そもそも「...rest」入れてる時点で引数の数はあんまり関係なくなるけども。

じゃあ、普通に関数でも使えるかと思って試してみた。
function test():void {arguments;}
test(1, 2, 3);
普通に怒られた。
引数の数が正しくありません。0個以下であることが必要です。
って。
で少し呼び出し方を変えてみる。
function test():void {arguments;}
test.apply(null, [1, 2, 3]);
と、今度はすんなり通った。
ようはイベントの通知には apply が使われてるってことか。

もしかして dispatchEvent もこの要領で「dispatchEvent.apply」とかすれば引数勝手に増やせるかも?
とか思ったけど、やっぱりそれはダメでした。

で、結局のところ「だから何なんだ」って話しで、
特に何も得することもないんですが。


通常、外部からの呼び出しの時は引数無しだったり、個定数の引数を渡さないといけなくしておいて
内部処理のみ、内緒でこっそり引数渡してやりたい時なんかは使えるかもしれないですね。
再起処理の時のフラグとか。
久しぶりの投稿です。
どうもご無沙汰しております。

Airでクリップボードランチャを作ってみました。
インストール、解説もろもろは以下にページを作っておきました。

AirClip [http://www.seyself.com/airclip/]

一応このアプリケーションはスニペット的な使用を想定して作ってみました。
(ショートカットとかないですけども)

テキストと画像の管理ができますが、画像管理はほとんどおまけ状態です。
というのも、クリップボードにコピーした画像データを取得しても、
アルファ情報が破棄されちゃってて透過画像をうまく管理できなかったんです。
これについて、誰か対処方法知ってたら是非とも教えてほしいです。

あと、複数の履歴を管理できるようにしようかとも思いましたが
UIが思いつかなかったので、とりあえず放置しました。


履歴1000件とかは試してないので、あんまり多くなったときにどうなるかは謎です。

僕自身、ちょいちょい使いながら手直ししていこうかなと思ってます。

何か不具合とか要望とか、コメントもらえれば追々対応しますです。
致命的過ぎない限り即日対応とかは無理ですが。