ダメ人間オンライン

あまり信用しないほうがいい技術メモとか備忘録とかその他雑記

携帯向けSWFファイルで動的表示

SWFで表示する文字列をアクセスしたユーザーごとに変更したいとか、

パラメータを渡して処理させるとかを実現する方法はいくつかあると思いますが

そのうちの一つの方法としてSWFファイルに直接渡したいパラメータを埋め込む方法を紹介したいと思います。



と、書きましたが別に「こんな方法考案したぜ!」ってわけではなく

既にある方が実装した方法を少しだけ噛み砕いて紹介するという形になります。



手法の引用元

FLASH-JP.COM - フォーラム

原理

ソースコード(perl)





処理概要


ものすごくざっくり説明すると、



1.値の入っていない変数を用いた処理を含むSWFをパブリッシュする。

2.パブリッシュされたSWFバイナリをhead部とbody部に分割する。

3.head部とbody部の間に変数の代入処理を埋め込む。

4.head部と変数の代入処理とbody部をくっつける。



という流れになります。





実装方法


SWFのファイル仕様(adobe)と引用元のソースコードを見ていただければ大体把握できると思います。



head部とbody部を分割するにはhead部の長さがわかればいいので、SWFファイルをバイナリエディタで開いて見てみることにします。


46 57 53 04 73 2D 00 00 70 00 09 60 00 00 96 00 00 08 0E 00

バイナリと聞くだけで逃げてしまう人もいますが、仕様さえわかっていれば特に恐れることはないです。



バイナリは良い子です^^




  • 最初の3バイト:固定文字列

  • 次の1バイト:パブリッシュのバージョン

  • 次の4バイト:ファイルサイズ


パブリッシュのバージョンについて補足すると、上記の場合「4」になりますがこれはFlashLite1.1に相当します。

FlashLite3.0の場合だと「8」です。



ファイルサイズの次のバイトからはSWFの縦横サイズを表しますが、これはRECT構造体で表現されており可変長です。



ですので、head部とbody部を分割するにはSWFの縦横サイズを表すバイトの長さを計算する必要があります。



RECT構造体の説明は割愛しますが、どれだけの長さかを判断するにはRECT構造体の頭5ビットの値を見れば計算することができます。



それがソースコード中の下記の箇所になります。


$srcswf = "base.swf";

# basefile 読み込み
open(FR, $srcswf);
read(FR,$headtmp, 9);
$rb = ord(substr($headtmp, 8,1)) >> 3;




変換前のswfファイルを読み込み頭から9バイト目をとってきます。



上のバイナリの例ですと「70」です。



16進数「70」を2進数に直すと「01110000」となります。



「01110000」の頭から5ビットの値を計算するために「>> 3」で3ビット分右にビットシフトしています。



単純に書くと「01110000」が「00001110」となりこれを10進数変換すると「14」の値を得ることができます。



この値を用いて下記の処理で縦横サイズのバイト長を求めています。




int(((( 8 - (($rb*4+5)&7) )&7)+ $rb*4 + 5 )/8)



最後に、縦横サイズの後2バイトがfps、その後2バイトがrootのフレーム数になります。



これでhead部は終わりです。



ソースコード


$headlen = int(((( 8 - (($rb*4+5)&7) )&7)+ $rb*4 + 5 )/8) + 12 + 5;



縦横サイズの後ろで「 + 12 + 5」してますが「12」は縦横サイズを除いたhead部の長さ(固定長)、「5」は後ほど説明いたしますが背景色設定タグの長さになります。



これでhead部の長さがわかったので後はその後に変数の代入処理を埋め込むだけです。



ただし、変数の代入処理を埋め込むとファイルサイズが増加するためファイルサイズを表す箇所の更新も行っています。





以上がソースコード内で行っている処理の概要になります。





vs背景色タグ


背景色タグは5バイト分あり

43 02 FF FF FF

のような形になります。



上記原文のソースコードではhead部の次には背景色タグが確実にくるものとして扱われていますが、私がパブリッシュしたswfファイル(CS4からFlashLite1.1で)ではhead部と背景色タグの間に別のタグが入っていました。



その別のタグのバイト長が6バイトであり処理がうまくいきませんでした。



このタグが何者かという話以前に、何故head部の直後に変数代入のタグを挿入せず背景色タグの後に挿入していたかということですが、背景色タグの前に変数代入タグ(doactionタグ)を挿入するとエラーとなるという説明がありました。



しかしながら、試しに背景色タグの前に変数代入タグを入れてみたところ特にエラーも出ず正常に再生することができたため私はhead部直後に挿入する方法を採用しています。



また、rdfのMETAデータを含むswfファイルに対しても正常に再生できたので問題ないかと思います。








ダイナミックテキストとして変数を表示する場合について簡単に使用例を挙げてみます。



以下のような画像で構成されている簡単なswfに対して

f:id:dameninngenn_owata:20120814201218p:plain


答えの空欄の箇所に文字列を表示させるとします。



テキストボックスの作成を行う際に静止テキストではなくダイナミックテキストを選択します。

f:id:dameninngenn_owata:20120814201258p:plain


そして以下のように配置します。

f:id:dameninngenn_owata:20120814201335p:plain


最後にテキストボックスのプロパティにある変数欄に変数名「answer」を入れておきます。

f:id:dameninngenn_owata:20120814201411p:plain


これでパブリッシュすると以下のSWFが生成されます。

※swfファイルは死にました

生成されたSWFに対して「answer = colombia」を挿入すると以下のようなSWFになります。

※swfファイルは死にました

ソースコードで言うと


%datahash = ("answer"=>"colombia");



とすればOKです。





文字コードについて




変数にマルチバイトの値を入れる場合は文字コードに注意する必要があります。



FlashLite1.1の場合はShift-JIS、FlashLite2.0以降の場合はUTF-8エンコードしてから挿入しないと文字化けしてしまいます。