こんにちわ、先日行った伊豆大島旅行が忘れられず、すぐに同じ船を再度予約してしまった@nihimotoです。星空がすごかったものでつい・・あぁ、あんなところで開発したい。
さて、弊社では携帯向けFlashの開発のご依頼をいただくことが多く、最近FlashLite1.1で高度なGUIをもったアプリケーションを開発する機会がありました。その際にswfの動的生成にのめり込むこととなりましたので、使わせていただいたライブラリへの感謝の念を込めて、ここにその試行錯誤の記録を残しておきたいと思います。
まず、FlashLite1.1を使うに当たって必ずぶち当たるのは下記の2つの壁であることはご存知かと思います。
- 外部からパラメーターを受け取ることができない
- 外部のデータを読み込むのにワンボタン必要となる
これら2つの問題をクリアするためにswfを内に必要なデータを埋め込んでswfを動的生成する、という技術を今回使うことにしました。つまりデータを渡せないのであればはじめから埋め込んでしまえばいい、というわけです。
ちなみにswfの容量が100kまでしか読み込めないというさらに大きな壁もあったりしますが、これはFlashLiteのバージョンが上がっても解決できないですし、swfの動的生成で解決できるわけでもないので割愛したいと思います。がんばって容量を縮めてください。それしかないです。
それではまずはじめに使用した各技術の簡単な説明です
- SwfMill
- SwfをXmlに分解することができます。そして、そのXmlを逆にSwfファイルに組み上げて保存することができます。
- このXMLにはswf内の全情報(画像や変数やシェイプやアクションや…etc)が詰まっているので、一度分解して必要な書き換え処理を行ない、またswfに戻すことで画像や変数の置き換えなどが可能となります。
- また、SwfMill専用の形式でXmlを書くことで、それをswfに変換する機能もあります(Simpleモード)
- 参考:swfmill swf2xml and xml2swf
- 参考:swfmillでケータイFlashを動的生成してみよう(インストール編) | 携帯サイトをつくろう
- SwfをXmlに分解することができます。そして、そのXmlを逆にSwfファイルに組み上げて保存することができます。
- SwfEditor
- Swfをバイナリで解析して指定したデータを書き換えてくれるphpのextentionです。
- できることはSwfMillとそんなに違いはないのですが、Xmlにわざわざ変換する必要がないので動作が早いという特徴があります(当方では未検証ですが・・)
- 扱いも非常に楽なのでこれでできることならこれですませたい・・
- 参考:SWF Editor for PHP – Yoya Wiki
- 力技のバイナリ書き換え
- SwfEditorがやってくれるパラメーター差し替えを、力技で普通にphpで書いたものです。
- ここでやっていることは上記の2つで実現できるので不要ではあるのですが、上記2つのように何かをインストールする必要がないので、エンジニア以外が簡易的にパラメーターを埋め込みたいときに何気に重宝します。
- 参考:FACEs: 携帯Flash (FLASH Lite 1.1) へ普通にパラメータを渡す
では、下記が試行錯誤のログです。
■gif画像差し替え
- SwfEditorでもSwfMillでも実現できます
- SwfEditorの場合は $swfeditor->replaceGIFData( $image_id, $binary_image ); という感じで一発で書き換えできます。
- さらに書き換え前と後の画像サイズが違った場合、swf内の<DefineBitsLossless2>というデータに記述されているサイズまで書き換えてくれます
- ここで使う$image_idとはSwfファイル内でデータに割り振られたidになります。$swfeditor->swfInfo()でデータをdumpするか、SwfMillでXMLに分解してあげれば、割り振られたidを知ることができます。
- SwfMillの場合には、gifのデータをエンコードしてXML内の該当画像を正規表現で探して置き換える必要があるので若干面倒です。
- データ本体だけではなく、画像のwidthとheightが埋め込まれたタグも修正してあげないと不都合がでる場合があります
- らくちんなので、とりあえずSwfEditorで実装。
- が、画像サイズが変動する置き換えでトラブル発生
- 置き換え後の画像が、置き換え前の大きさ分しか表示されないことが判明
- 2010.10.20追記:制作者のyoya様から「対応する予定」との旨お教えいただきました。この問題は解決可能になっている可能性が高いのでYoya様のサイトを確認してみてください
- 置き換え後の画像が、置き換え前の大きさ分しか表示されないことが判明
- 色々試して画像をはめ込んでいるShapeのサイズも書き換えないと、描画領域が書き換え前の範囲だけになってしまうことが判明
- そのため、画像サイズの変動をなくそうと、画像サイズを大きめに固定して、それより小さい画像は全て透過領域を作ってサイズを揃える、という荒業をやってみたが失敗
- 画像サイズを透過領域を使って揃えてしまうことで、結果として透過gifが10枚近く重なるピクセルが存在することになりました。
- その影響で携帯のメモリ不足なのかなんなのか不明ですが、画像の描画が追いつかなくなるという現象が発生するようになりました。
- そのためこの方法はボツ
- 仕方ないので画像データをSwfEditorで置き換えた後、さらにSwfMillを使ってサイズが記述された下記のタグ類まで書き換えを行うように組みました
- <DefineBitsLossless2> ※これはSwfEditorを使っていれば勝手に書き換えてくれます
- <Rectangle>
- <Transform>
- <ShapeSetup>
- ここまでやってようやく全ての問題をクリアして自由にgif画像の置き換えができるようになりました。
- ただしユーザーアクセス時にリアルタイム生成をするのであれば、SwfEditorとSwfMillを両方使うやり方は無駄が多いので、SwfMillだけで全てできるようにしたほうがいいと思います
- 本当はSwfEditorのほうが軽くていいのですが、サイズ値の書き換えが自由にできないためやむをえません・・
- さらに最良なのはそもそも画像差し替えの際にサイズの変動が不要になること、ですが。
■ ベクター画像の差し替え
- SwfMillで実施
- ベクター画像はSwfMillでXMLに分解してみると、<Shape>になっている
- ベクター画像自身も簡単なSwfに埋め込んでからXMLに展開すれば、置き換え用の<Shape>タグが入手できます。
- 置き換え元画像内の<Shape>を、ベクター画像の<Shape>に置き換えてあげれば、画像差し替えが可能でした。
- 上記を手作業で行ない、差し替えが可能なことを確認。
- ただし、画像自身をswf化する必要があったり、複雑なタグ構造になるので正規表現での置き換えがやりにくかったりするので、ベクター画像の埋め込みを自動化しようとすると結構大変な目に合いそうです
■ パラメーターの埋め込み
- SwfMill、SwfEditor、力技のバイナリ置換、どれでも可能ですが、手間を考えて力技のバイナリ置換を採用しました。
- 画像差し替えまで必要ないケースでは力技のほうが便利です
- ライブラリをインストールしてない環境でも実行できるため
–
ということで、以上がFlashLite1.1関連で四苦八苦した作業記録になります。
ざっくりした記録なので、多分実際に試した方でないと内容を把握することは難しいのではと思いますが、とりあえず公開しておきます。
ではでは。