preload
1月 13

遅ればせながら jeweler から bundler への移行をちゃんと経験しておくべく、何やらこしらえてみました。といっても、$ bundle gem <ライブラリ名> としてスケルトンを作ったら、あとは gemspec をごにょごにょ書くだけだったので、さして難しくはなかったのですが。

今回公開した SwfRuby (swf_ruby) は、SWFバイナリを解析したり、内部に含まれる画像などのリソースを置換したりするための Ruby ライブラリ(およびコマンドラインツール)です。ruby-1.8.7 と ruby-1.9.2 で動作確認をおこなっています。こちらのライブラリは、GPL2(the GNU GENERAL PUBLIC LICENSE Version 2)にて使用を許諾します。

swf_ruby | RubyGems.org | your community gem host

tmtysk/swf_ruby – GitHub

SwfRuby のメイン機能を司るクラスは2つあります。SWF に含まれるタグ群やタグの登場箇所(オフセット値)をダンプする SwfDumper と、SWF に含まれるリソースを置換する SwfTamperer です。

昨年は携帯向けソーシャルアプリのブームもあり、サーバサイドでの Flash(SWF) 操作のニーズが高かったように思います。このサイトでは、2009年4月ごろから、swfmill を使った SWF の解析方法や、swfmill の Ruby ラッパーである SwfmillRuby を紹介してきました。しかしながら、莫大なアクセス負荷のかかるソーシャルアプリサイトですから、こちらで紹介してきたやり方では機能要件は満たせども、swfmill の起動コストや XML の操作コストに頭を悩ませた開発者の方も多かったのではないでしょうか。

SwfRuby は冒頭で述べた通り、swfmill などの中間ソフトウェアを一切介在させず、SWF バイナリを直接操作するライブラリです。現時点では荒削りなのでお世辞にも使い易い状態とは言えませんが、SWF の仕組みを大体理解している人にとっては、それなりに便利に使える部分があると考えています。(SWF のバイナリ編集については、グリーエンジニアブログでの連載がとても丁寧に解説されているので、そちらを参考にすると良いでしょう。)

以下、簡単に使い方を紹介します。

SWF のバイナリを直接操作するに当たって、まず調べないといけないのは「置換対象のリソースがSWF中のどこ(オフセット位置)に含まれているか」です。SwfDumper を使った解析プログラムを書くのも良いですが、swf_ruby をインストール( $ gem install swf_ruby )すると、SwfDumper を使ったコマンドラインツール swf_dump が使えるようになりますので、今回はそちらのツールを使った方法を紹介します。swf_dump の引数として SWF ファイルパスを指定してください。

$ swf_dump samples/sample.swf
SetBackgroundColor, offset: 20, length: 5
DefineFont2, offset: 25, length: 34
DefineEditText, offset: 59, length: 50
PlaceObject2, offset: 109, length: 11
DefineBitsLossless2, offset: 120, length: 178
DefineShape, offset: 298, length: 55
:
DefineBitsJPEG2, offset: 623, length: 10986
:

このような形で、SWF 内部のタグ一覧と、個々のタグの登場位置/長さを得ることができます。ちなみに、タグ情報は最新の SWF 仕様書を取り込んでありますので、Flash Lite の SWF に限らず、(たぶん)どんな SWF を指定しても、こういったダンプ情報を得ることができます。

さて、上記のダンプ情報により、DefineBitsJPEG2 タグがオフセット位置 623 バイト目から始まることがわかりました。つまり 623 バイト目以降にある JPEG バイト列と関連する情報をよしなに書き換えてやれば、この JPEG を差し替えることができるということになります。SwfTamperer は、この「よしなに書き換える」操作を支援するクラスです。swf_ruby をインストールすると、SwfTamperer を使ったコマンドラインツール swf_jpeg_replace が使えるようになりますので、ここでは、その使い方を紹介します。swf_jpeg_replace の引数として、SWF ファイルパス、書き換えを行う JPEG のオフセット位置(swf_dumpで取得可能)、書き換え後の JPEG ファイルパスを指定してください。

$ swf_jpeg_replace samples/sample.swf 623 samples/bg.jpg > samples/sample2.swf

書き換え後の SWF は標準出力へ出力されますが、ここでは、ファイルへリダイレクトをおこなっています。

最後に、拙作 SwfmillRuby と SwfRuby とで、SWF 読み込み → SWF 中の JPEG 1 ファイルを置換 → ファイル書き出しする際の簡単な速度比較をおこないましたので、ご参考までに紹介します。それぞれのプログラムを手元の PC のターミナルから100回連続実行(つまり100件のSWFを合成)した際の処理時間は以下のとおりでした。比較に使用した Ruby バージョンは 1.8.7 です。

  • SwfmillRuby .. 11.697s
  • SwfRuby .. 5.301s

SwfRuby は SwfmillRuby の約半分といったところでしょうか。減少分は swfmill の起動や libxml による xml 処理、RMagick による画像処理のオーバーヘッド分かと考えられます(期待値的には、もうちょっと(桁ひとつくらいは)速くなって欲しかったところですが、SwfRuby 側にまだまだ改善の余地があるのかもしれません)。

以上、SwfRuby の概要とコマンドラインツールの簡単な使い方を紹介しました。SwfTamperer は現時点では JPEG と ActionScript 内変数の書き換え機能しか提供しておりませんが、これに DefineEditText や DefineBitsLossless 系の書き換え機能が付けば、それなりに有用なものになると思います。また、ご興味の方には、コマンドラインツールだけでなく、SwfDumper や SwfTamperer クラス群をうまいこと使ってみていただいても良いかも知れません。SwfmillRuby ともども、フィードバック、pull request は大歓迎ですので、ぜひともご意見ご感想などお聞かせいただけると嬉しいです!

Tagged with: