swflib
日本語、使うには気をつけよう。
なんか、やっていることがマイナーなせいか、googleで検索かけると自分のページが直ぐ出てくる。
うざいねん。もっと、まともな文章を書くように心がけよう。
さて、swflibで画像をswfファイルに埋め込むことが出来るようになりました。
今回は、一つ、アクションスクリプトを埋め込んでみようかと思います。
まずは、a=1っていうのを埋め込んでみましょう。
用意するもの
parafla! フリーのswf作成アプリケーション
listswf libmingについてきた、swfファイルを見るコマンドラインプログラム
Flash Decompliler フラッシュのswfファイルをデコンパイルする。
アクションスクリプトのデコンパイルに便利。
FLAGSTONEのswf用ライブラリ Javaからswfを出力できる。アクションスクリプトも気合で作れる。
なんとなく、これに慣れてしまったので使ってます。
swflib ocaml用のswf用ライブラリ ActionScript2.0用のコンパイラMTASCの内部で使われている。
swfファイルの仕様書 マクロメディアのホームページから拾ってきます。
まずは、parafla!でアクションスクリプトを実行するswfファイルを生成します。
次に、listswfを使って中身を見ます。以下のようになります。
listswf test.swf > test.txt File size: 50 Frame size: (0,12800)x(0,9600) Frame rate: 30.000000 / sec. Total frames: 1 Offset: 21 (0x000015) Block type: 12 (DoAction) Block length: 23 0 Declare Dictionary: a0 8 Push "a0" 13 Push 1 21 Set Variable 22 Offset: 46 (0x00002e) Block type: 1 (ShowFrame) Block length: 0 Offset: 48 (0x000030) Block type: 0 (End) Block length: 0
JavaのFLAGSTONEでACTIONSCRIPT入りのプログラムを生成するには以下のようにやります。
import com.flagstone.transform.*; import com.flagstone.transform.util.*; import java.io.*; import java.util.*; public class test { public static void main(String[] args) throws Exception { FSMovie movie = new FSMovie(); movie.setFrameRate(30); movie.setFrameSize(new FSBounds(0, 0, 640 * 20, 480 * 20)); { ArrayList actions = new ArrayList(); // 変数テーブル設定 FSTable literals = new FSTable(new ArrayList()); literals.add("a"); actions.add(literals); { actions.add(new FSPush(new FSTableIndex(0))); actions.add(new FSPush(1)); actions.add(FSAction.SetVariable()); } movie.add(new FSDoAction(actions)); movie.add(new FSShowFrame()); } movie.setSignature("FWS"); movie.encodeToFile("test.swf"); } }
DoActionタグの中で、変数名の登録、変数名をプッシュ、値をプッシュ、値設定とやってあげれば良いようです。
さて、ocamlで対応しそうなものを探します。
swflib/actionScript.ml
mtasc/genSwf.ml
が参考になります。
うーととととと、
{ tdata = TDoAction _ }
ってのがあります。これをつかうのでしょう。
swf.mlでは、
type tag_data = | TEnd ... | TDoAction of actions
とあります。
type action = | AEnd | ANextFrame | APrevFrame | APlay | AStop | AToggleHighQuality | AStopSounds | AAddNum | ASubtract | AMultiply | ADivide | ACompareNum | AEqualNum | ALogicalAnd | ALogicalOr | ANot | AStringEqual | AStringLength | ASubString | APop | AToInt | AEval | ASet | ATellTarget | AStringAdd | AGetProperty | ASetProperty | ADuplicateMC | ARemoveMC | ATrace | AStartDrag | AStopDrag | AThrow | ACast | AImplements | ARandom | AMBStringLength | AOrd | AChr | AGetTimer | AMBStringSub | AMBOrd | AMBChr | ADeleteObj | ADelete | ALocalAssign | ACall | AReturn | AMod | ANew | ALocalVar | AInitArray | AObject | ATypeOf | ATargetPath | AEnum | AAdd | ACompare | AEqual | AToNumber | AToString | ADup | ASwap | AObjGet | AObjSet | AIncrement | ADecrement | AObjCall | ANewMethod | AInstanceOf | AEnum2 | AAnd | AOr | AXor | AShl | AShr | AAsr | APhysEqual | AGreater | AStringGreater | AExtends | AGotoFrame of int | AGetURL of string * string | ASetReg of int | AStringPool of string list | AWaitForFrame of int * int | ASetTarget of string | AGotoLabel of string | AWaitForFrame2 of int | AFunction2 of function_decl2 | ATry of try_block | AWith of int | APush of push_item list | AJump of action_count | AGetURL2 of int | AFunction of function_decl | ACondJump of action_count | ACallFrame (* no data *) | AGotoFrame2 of bool * int option | AUnknown of int * unknown type actions = action DynArray.t
とありますので、DynArray.tにアクションを突っ込んであげればよさそうです。
| AStringPool of string list | APush of push_item list | ASet type push_item = | PString of string | PFloat of int32 | PNull | PUndefined | PReg of int | PBool of bool | PDouble of float | PInt of int32 | PStack of int | PStack2 of int
あたりを使えば良さそうです。
この3つの定義を見てみましょう。
actionScript.mlでは
| AStringPool _ -> 0x88 | APush _ -> 0x96 0x1D => (ASet,"SET");
って言う風にあるのがわかります。
swfの仕様書を見ると
ActionConstantPool UI8 Action = 0x88 ActionPush UI8 Action = 0x96 ActionSetVariable UI8 Action = 0x1D
とありますので、間違いないようです。
TDoAction [(AStringPool["a"]);(APush[(PStack 1);(PInt (Int32.of_int 1))]);ASet]
って感じで作ってあげたらよいことになります。
あとは、DynArray.を使えばよいと。
出来上がったソースは以下のとおりです。
open Swf open SwfParser open SwfZip (* タグ生成 *) let tag ?(ext=false) d = { tid = 0; textended = ext; tdata = d; } (* 領域データ生成 *) let bounds x y w h = { rect_nbits = if (max w h) >= 820 then 16 else 15; left = x; top = y; right = w * 20; bottom = h * 20; } let w = 640 let h = 480 let fps = 40.0 let out = "out.swf" let bgcolor = ref 0xffffff let header = { h_version = 8; h_size = bounds 0 0 w h; h_frame_count = 1; h_fps = to_float16 fps; h_compressed = false; } ;; let ass : Swf.action DynArray.t = DynArray.create();; DynArray.add ass (AStringPool ["a"]);; DynArray.add ass (APush [(PStack 0);(PInt (Int32.of_int 1))]);; DynArray.add ass (ASet);; let data = [ tag (TSetBgColor { cr = 0xFF; cg = 0xFF; cb = 0xFF }); tag (TDoAction ass); tag (TShowFrame)];; SwfParser.init SwfZip.inflate SwfZip.deflate;; Swf.warnings := true;; let ch = IO.output_channel (open_out_bin out);; Swf.write ch (header, data);; IO.close_out ch;;
これを、Flash Decompilerで見てみると、、、。
a = 1
ってかいてあります。成功です。