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
ってかいてあります。成功です。