preload
4月 24

このたび「Rails で携帯サイトを作る」という趣旨の解説書の執筆に参加させていただきました。共著者のお二方、お声がけいただいた編集者様には、大変お世話になりました。このたびは、ご一緒させていただき、ありがとうございました。

いわゆる「スマートフォン」向けサイト開発の解説書ではありません。iPhone も android も出てきません。あまり好きな表現では無いですが、あえて言えば「ガラケー」サイト開発の解説書です。

今さら?という声も聞こえてきそうですが、僕は、ある意味良いタイミングだったかも、と思ってます。まだまだ今の状況では「スマートフォン」サイトに(堅実に)お金をかけられるところは少ないという印象ですし、一方で「ガラケー」は「ガラケー」で、わりと基本的なところは変わらなくなってきつつありますし。

個人的には「ガラケー」に固執するつもりはさらさらないですし、かといって今すぐ「スマートフォン」に飛びついてズッポリ浸かりたいというノリでもない感じです。が、まあ、一方で、僕は「ケータイ」がわりと好きなので、どっちにせよ、携帯向けサービスを Ruby/Rails で作っちゃおうぜ、という流れが少しでも広がると、周りから楽しいサービスが生まれていったり、便利なライブラリやノウハウが蓄積されていったりで、そしたら僕もずっと楽しく Ruby と付き合っていけたりで嬉しいので、そんなきっかけになればいいなーと思いながら書きました。

ちなみに、僕はメールに関する章と、Flash Lite に関する章を書きました。Flash Lite の章は Rails からだいぶ離れた話題になっていますが、昨今の携帯サイトを作るという意味では外せない話題だったと思います。概要だけとはいえ、 SWF の内部構造やら、(Flash Liteの各種制限に着目しつつ)オープンソースソフトウェアを併用した SWF のサーバサイドでの生成について扱っている書籍は、他にあまり見ないな、と思いますです。(Flash Liteに限らなければ洋書では何冊かあるのですが。)

あとは、これに動画/音楽系サイト、オートGPS、モバイル向けソーシャルアプリとかの話が加えられるとさらに良かったかな、と思いますが、その辺の話はまだまだ非公開部分が多いので何ともですね。テスト周りが書けなかったのは惜しかったかな。とはいえ、そこそこ守備範囲の広い内容になっていると思います。

最後に、Flash Lite の章で、ページの都合で載せられなかった幾つかのコラムについて、許可をいただいたので、こちらに紹介しておきます。(ちょっと文脈が無いと意味わかんないところがありますが、Flash Lite の章は、こういう文章が途中に入るような内容になっているとご想像いただく材料になれば。)

コラム 利用できるActionScriptバージョンに注意

ActionScriptはFlashプレーヤおよびFlash Liteプレーヤ上で動作するスクリプト言語で、よりインタラクティブなFlashコンテンツを制作するうえで欠かせない存在です。本書執筆時点の最新バージョンは3.0(Flash Liteプレーヤでは利用不可)です。Flashプレーヤのバージョンアップに伴い、ActionScriptの言語仕様やプログラミング環境/実行環境は大きく様変わりしてきています。表7-1で示した通り、Flash Liteバージョンを決定することは、利用できるActionScriptバージョンを決定することにもなりますので、対象のFlash Liteプレーヤバージョンを選択する際は、注意しておきましょう。

コラム Flash Liteコンテンツ内での絵文字利用

バージョン/キャリアによっては、Flash Liteコンテンツ内で各キャリアの絵文字を利用できます。ただし、(本書でこれまで紹介してきた通り)絵文字の表記方法はキャリア別に異なりますし、上記で示した通り、プレーヤバージョンごとに利用できる文字符号化方式も異なっていますので、絵文字の利用には十分に注意が必要です。

コラム SWFの動的生成はボトルネックになりやすい

本章では、swfmillを利用した “元のSWF→元のXML→書き換え後XML→書き換え後SWF”というSWF動的生成の一連の流れを紹介しました。しかしながら、swfmillの利用やXMLの解析/書き換え処理は、それなりに時間のかかる処理ですので、Webアプリケーション内でこれらの処理を実行する際は注意が必要です。必要に応じて、書き換え後のXMLやSWFをキャッシュしたり、非同期(バッチ)処理でSWFを生成したりといった方策、あるいは、より用途に見合ったswfmill以外のソフトウェアの利用も検討すると良いでしょう。

ところで、Amazon.co.jp からも案内が来てました。笑

Screenshot-24

Tagged with:
5月 08

前回までのエントリ(第1回, 第2回)では、FlashLite コンテンツのサーバでの動的生成/合成処理について、開発ステップの全体的な流れや、swfmill を使用する際の SWF 構造の見方などについて紹介してきました。

今回は、前回のサンプルを使って、実際に swfmill を使用しながら SWF の動的生成をおこなう手順を紹介していきます。

前回の後半で、swfmill swf2xml で得られた XML をテンプレート化しておき、これを操作する方法として、次の2種類を紹介しました。

  • XML 中の置き換えをおこなう部分を場所を一意に特定できる文字列にしておき、プログラムからは文字列置換により書き換える
  • 置き換え対象部分を独自に定義した要素などに編集しておき、適当な XML 操作のための API (僕の場合は、PHP であれば SimpleXML、Ruby であれば REXML や Libxml-Ruby などを使ったりしてます) を介して書き換える

ここでは、手軽な前者の方法により、前回紹介したサンプルの背景画像の入れ替えをやってみます。背景画像は、XML 中:

182       <DefineBitsJPEG2 objectID="4">
183         <data>
184           <data>/9n/2P/Y/+AAEEp..

の data で定義されていますので、これを下のような形に書き換えてみます。

182       <DefineBitsJPEG2 objectID="4">
183         <data>
184           <data>####BACKGROUND_IMAGE####</data>

この XML を sample.xml として保存します。あとは、プログラムから、この XML の ####BACKGROUND_IMAGE#### の部分を文字列置換により JPEG 画像に差し替え => swfmill xml2swf とやれば、背景画像の差し替え完了となります。

せっかくの XML データですから、各種 XML API を介して操作するのが良いのかもしれませんが、システム内外からの不特定な入力の余地がないのであれば、こういった単純な文字列置換の方が、よりシンプルに実装でき、かつ高速な動作が期待できると思います。

今回は、ruby から swfmill を起動、XML の文字列置換をするためのクラスとして、下のような簡単なクラスを書いてみました。

module SwfmillUtil

  SWFMILL = "/Users/tmtysk/bin/swfmill"

  class Swfmill

    def self.xml2swf(xml, option = "-e cp932")
      IO.popen("#{SWFMILL} #{option} xml2swf stdin", "r+") do |io|
        io.write xml
        io.close_write
        io.read
      end
    end 

    def self.swf2xml(swf, option = "-e cp932")
      IO.popen("#{SWFMILL} #{option} swf2xml stdin", "r+") do |io|
        io.write swf
        io.close_write
        io.read
      end
    end

  end 

end

これを使って、以下のように差し替え処理を書いてみます。背景画像は bg.jpg とします。

require '../lib/swfmill_util'

xml = File.open('sample.xml').read
xml.gsub!(Regexp.new('####BACKGROUND_IMAGE####'),
            Base64.encode64([0xff, 0xd9, 0xff, 0xd8].pack("C*") +
            File.open('bg.jpg').read).gsub("\n",""))                                                                                                        

File.open('foo.swf', 'w') do |f|
  f.write SwfmillUtil::Swfmill.xml2swf(xml)
end

上記では、ファイルからオープンした jpeg データの先頭に [0xff, 0xd9, 0xff, 0xd8].pack(“C*”) の4Byteの文字列を付加していますが、これは SWF File Format Specification にも記載されている接頭子(マーカー)になります。このマーカーを忘れたり、また、Base64エンコーディングした後の改行文字を取り除くのを忘れたりすると、SWF 生成に失敗したり、SWF 生成は一見うまく行くのに再生すると画像部分が真っ赤になっていたりします。この「画像が真っ赤になる現象」は、プレイヤーが画像をレンダリングできない <= 画像データがどこかマズいという事のようで、画像の差し替えをやるとよくハマる箇所ですので、もし発生したら、上の画像エンコード周りを確認してみると良いと思います。

上のコードを実行すると、差し替え後の swf が foo.swf として保存されます。生成した swf をそのままブラウザに返すのであれば、適当な Content-Type を設定した上で SwfmillUtil::Swfmill.xml2swf(xml) の値をそのまま送信してやれば OK です。ただし、swfmill の起動コストもありますので、(程度にもよりますが)アクセスが集中するようなサイトで、同期的に SWF を生成してブラウザへ返す、というような事をやるのは、あまりオススメできません。あらかじめ SWF を作り置きしておくとか、非同期処理やバッチ処理で回避できるよう画面遷移を調整するとか、SWF 再生中のボタンアクションで非同期に loadMovie するように SWF の構成を見直すとか考える必要が出てくる事もあります。swfmill だと限界が見えてくるかもしれませんが、この他、負荷軽減のアイデアや実績があれば、コメントなどで教えていただければ幸いです。

さて、今回は、文字列置換により背景画像のみ差し替える、というやり方を紹介しましたが、同様の方法で、前回紹介したような「ムービークリップシンボルを丸ごと差し替える」というのも可能です。具体的には DefineBitsLossless2, DefineShape, DefineSprite 辺りを丸ごと文字列置換や XML 操作で置き換えてやれば OK です。この際、置き換え前後で objectID の参照関係が変わってしまわないように注意する必要があります。この辺の話も書こうと思ってたのですが、似たような話になってきたので、ここは割愛することにします。

今回使用したコードや、もうちょっと便利に使えるようにしたクラス群を github かどこかに置こうと思っています。ご興味の方、適当に遊んでみていただければと思います。

最後に、この手の事を swfmill 経由でやっていて、よく聞かれる事をまとめておきます。

Q. jpeg の部分に gif, png など他の形式の画像を置く事ってできる?

A. もっとも簡単な方法は、swfmill 外部で GD やら ImageMagick やら使って画像形式を相互変換してしまうことです。が、それだと SWF の容量制限上アレだったり、圧縮がかかって見た目上ナニだったりするので嫌、ということになると思います。そういうときは、swf2xml した後で、DefineBitsJPEG2 と DefineBitsLossless2 を置き換えてやれば OK です。jpeg 画像は DefineBitsJPEG2 で定義されていますし、それ以外の画像(gifやらpngやらbmpやら)は、すべて SWF の独自ビットマップ形式として DefineBitsLossless2 で定義されています。

DefineBitsJPEG2 では、今回の上で紹介した通り、比較的簡単な方法で JPEG データを流し込む事ができますが、DefineBitsLossless2 のデータについては SWF の独自形式ですので、既存の画像形式からの変換処理を書いてやる必要があります。この辺りの処理は、後ほど公開するクラス群に入っていたりするので、ご興味のある方はご覧ください。あまりよく確認してないですが、PHP や Perl でも実装例があったようななかったような気がしますので、そちらをお求めの方は適当に検索してみると良いと思います。

Q. 文字(テキスト)の入れ替えをやりたい?フォントを変える事もできる?

A. FlashLite1.1 の場合、テキストデータは DefineEditText(ダイナミックテキスト)要素 の initialText 属性で定義されているのがほとんどです(DefineText でパブリッシュされたのを見た事無いだけで仕様的には存在しうると思うのですが)。なので、この initialText を書き換えて xml2swf してやればテキストの入れ替えが可能です。テキストに日本語を含む場合もありますので、KLab の方が公開されている swfmill への文字エンコーディング指定パッチを適用しておくと便利です。(紹介を忘れてましたが、このパッチ、FlashLite1.1 を swfmill で扱う場合は、ほぼ必須と思います。)

フォントを変えるというのは、不可能ではありませんが、ちょっと手の込んだ事をやる必要があります。というのも、指定されうるテキストのフォント情報(グリフ)を SWF に埋め込むと、たいていの場合、それだけで FlashLite の容量制限をオーバーしてしまうからです。やるのであれば、「テキストではなく画像にしてしまう」、もしくは、「表示するテキスト情報から使用されている文字を抽出し、使用する文字の分だけグリフを埋め込む」という事をやることになるでしょう。グリフ情報はあらかじめ DB などで保持しておけば OK です。なお、フォント種類や文字にもよりますが、幾つか試してみた感じでは、日本語の漢字一文字を埋め込むと、SWF サイズが大体 300〜500Byte くらい増加するようです。

ちなみに、グリフ情報は DefineFont タグなどで定義されています。適当に1,2文字フォント埋め込みをしたSWFをパブリッシュして、構造を解析してみると良いかもしれません。

Q. ActionScript 部分を差し替えたい

A. これは、わりと僕がよくやる方法です。ActionScript のロジックは DoAction タグで定義されていますので、この子要素を SWF File Format Specification の action model 仕様を見ながら書き換えてやれば OK です。具体的には、SWF の再生フローを ActionScript 内の特定の変数値によって分岐するように書いておき、この変数値をプログラムから書き換える、といった感じです。Flashゲームや、ちょっとしたツールなど、アプリケーションライクな SWF を動的生成する際、動的な部分をある程度 SWF 側に持たせてしまうことで、生成プログラムの開発コスト/個別対応コストを下げる事も期待できます。

単に変数の置き換えをするのであれば、変数値を固定長(長さが変わってしまうと、内部で管理されているタグの長さの不一致が発生し、swf 構造が不正なものとなってしまいます)にしておけば、swf をそのまま(バイナリセーフな)文字列置換処理にかける事で、swfmill すら使わずに動的に swf を書き換える事もできます。swf の動的生成(と呼んでいいのかアレですが)としてはかなり高速な方法ですので、ゲームなど多量なアクセスが発生しうる SWF のセッション管理用にユーザ/セッション固有の ID を埋め込む、というのにも有効です。

Q. swf2xml したものを xml2swf しただけなのに、再生できなくなった

A. これはかなり稀なケースなんですが、swfmill で if / else の ActionScript コードを含む SWF を swf2xml したときの ActionScript のバイトコード変換処理に不都合があるらしく、ブロックジャンプのオフセット値が間違って出力されることがあるようです。swfmill のどの辺りかを追えてないので、根本的な解決ができてないのが申し訳ないのですが、こいつも SWF File Format Specification の action model 周りの仕様を睨みながら、出力された XML 中のオフセット値を適当に調整してやる事で、問題が解決できる場合があります。

以上、3回にわたって書いてきましたが、この手の話で、現時点で文章にできるのはこんなところです。機会があれば、今後は、こういう仕組みを使って個人的に作ったものを紹介していければ良いなあと思ってます。

何か参考になれば幸いです。

Tagged with:
5月 04

前回のエントリでは、サーバで生成した FlashLite コンテンツを配信するケータイサイトの開発/制作フローとして、以下のような流れを紹介しました。

  1. SWF への入出力(input/output)に見通しを立てる (全員で)
  2. Flash IDE でプロトタイプの fla ファイルを制作し、SWF でパブリッシュ (デザイナ)
  3. SWF 中の何(What)を、どのように動的にいじりたいかを整理 (全員で) (ここまでが前の項)
  4. 動的にいじる手段を選択 (主に開発者で)
  5. 決定した手段に応じて、SWF への入出力を決定 (主に開発者とデザイナで)
  6. fla の制作ルールを決める (主に開発者とデザイナで)
  7. 上の制作ルールに基づいて Flash IDE で fla ファイルを制作し、本番用の SWF をパブリッシュ (デザイナ)
  8. 制作した SWF を必要に応じてテンプレート化する (開発者もしくはデザイナで)
  9. テンプレート化した SWF をいじるアプリケーションを実装する (開発者)
  10. できあがり。運用時の更新は、7〜8〜9の繰り返し

前回は、このフローの4まで、つまり SWF をサーバ上でどのようにいじりたいかを検討し、そのための手段(ツール)として、swfmill を選択する、というところまで紹介しました。

今回は、具体的なコンテンツを想定しながら、このフローの5以降の流れについてまとめていきたいと思います。

サンプルコンテンツの概要

動的にいじるサンプルコンテンツとして、以下のような背景画像+キャラクタのアニメーションを再生するシンプルなFlashLiteコンテンツの動的生成要件を考えてみます。(上記のフローの 3 までの検討結果イメージについても併記してみます。)

  • ステージサイズは 176×208
  • 背景画像とキャラクタのアニメーションをステージ上に持つ
  • SWF を動的に生成するときの入力(input)
    • 背景画像
    • キャラクタ画像
  • SWF 再生後の出力(output)
    • なし。ただ再生するだけ
  • SWF 中の何(what)をいじるのか
    • 背景画像とキャラクタ画像

文字だけだとどんなコンテンツなのかイメージがわきにくいので、サンプルも貼っておきます。(DeviceCentral で再生しているものをキャプチャしています。)

今回は、このコンテンツをベースに、

  • 背景の jpeg 画像を指定のものに差し替え、
  • 飛んでいるキャラクタの画像とアニメーションを指定のムービークリップシンボルに差し替える

ということをやってみます。具体的には、背景画像を以下のもの:

bg2

に差し替え、さらに、キャラクタのアニメーションを、別途作成した以下のようなムービークリップシンボル:

に差し替えたものを、新しい FlashLite コンテンツとして生成することとします。(余談ですが、FlashLite の動的生成が「FlashLite の(動的)合成」と表現されている事がありますが、その意味するところは、上記のように「ムービー中の画像素材などを指定して、これらを組み合わせて(合成して)FlashLite の生成をおこなう」ということと理解しています。)

それでは、以下、先に紹介した制作フローの続きを紹介していきます。

SWF 生成(合成) 時の入出力を決める

先に検討した入出力を精査し、何を入力パラメタとして SWF をつくり、ムービー再生後にどのような出力パラメタをもってサイト遷移に戻るか、を決定します。今回は、以下のように決定したとします。

  • 入力
    • 背景画像: ステージサイズと同じ大きさの jpeg データ
    • キャラクタ画像: アニメーションを伴ったムービークリップシンボルとして指定される(元のキャラクタ画像は GIF89a)
  • 出力
    • なし

なお、実際の要件や制作/開発の現場では、上のようにまとめられるとは限りません。「背景画像には jpeg と GIF の形式のどちらかが指定されうる」とか「キャラクタ画像は画像のビットマップのみ入力として与えるだけとし、アニメーションは固定で良い」などの要望が出る場合があります。今回は、この後のステップを紹介するのに都合が良いように要件を決めていますので、まずは以下をお読みいただいた上で、上記のような要件変更/要望の取り込みがどの辺りの開発ステップ/難易度/コストに影響を与えてきそうかを捉えていただければと思います。正直なところ、ここ以降の制作フローの詰めが、FlashLite コンテンツの動的生成をおこなう際の一番の難所(業務でやる場合は、リスク要因となりやすいフェーズ)と、個人的には感じています。

.flaの制作ルールを決める

SWF 中の差し替えをおこなう要素と、そのときに与えられる入力が決まったところで、デザイナと開発者との間でベースとなる SWF の制作ルールを決めていきます。なぜ、制作ルールを決める必要があるかと言うと、一番の理由は、プログラムから差し替えをおこなう要素が特定できるようになっていないことには、画一的な処理で要素の差し替え(SWF の動的生成)をすることができず、ベースとなる SWF ごとに処理をつくってやらなければならなくなるからです。

これは逆を言えば、ベースとなる SWF が少なく、運用時の SWF 追加や更新も無い、などの理由で、個別の動的生成処理を実装していくのにコストがかからないのであれば、この時点で厳密な制作ルールの握りをつくる必要は無い、ということにもなります。

今回は、この後の説明を簡単にする都合で、以下のように制作ルールを決める事ができた、と仮定します。

  • 背景画像は、jpeg を貼付けただけのムービークリップシンボルを別途作成しておき、これをステージに配置する際に “bg” というインスタンス名を付与しておく事にする
  • キャラクタ画像は、アニメーションを含める形でムービークリップシンボルを別途作成しておき、これをステージに配置する際に “animation” というインスタンス名を付与しておく事にする

上記のように、今回は、差し替えをおこなう要素をふたつともムービークリップシンボル化しておくことを仮定しています。

ただ設置するだけの背景画像を、わざわざシンボル化して、インスタンス名まで付与するのは、制作側からすれば一見非効率かも知れません。ただし、これらのルールは、先にも述べた通り、プログラム側から差し替えをおこなう要素(ムービークリップ)を特定/識別するためのルールですので、ケースバイケースと考えていただければよろしいかと思います。たとえば、「SWF 中には、背景画像として唯一 jpeg 要素を使用する」という制作ルールがあれば、「背景画像として入力した jpeg を SWF 中の jpeg データと置き換える」という処理を作ってやれば、わざわざインスタンス名で特定する必要がないということにもなります。

本番用 SWF をパブリッシュし、必要に応じてテンプレート化し、差し替え処理を実装する

上記のルールに基づいて .fla を制作し、SWF をパブリッシュしたら、いよいよ、具体的な FlashLite 動的生成処理の実装に入っていきます。

まずは swfmill swf2xml を使って、できあがったベースの SWF の構造を確認してみます。(swfmill の基本的な使い方は、他のサイトでもわかりやすい説明が多いので、ここでは割愛します。)今回のサンプル SWF は以下のようになっていたとします。

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <swf version="4" compressed="0">
:
 13       <DefineBitsLossless2 objectID="1" format="3" width="30" height="30" n_colormap="7">
 14         <data>
 15           <data>eNq9kEsO...
:
 17       </DefineBitsLossless2>
 18       <DefineShape objectID="2">
:
 30               <ClippedBitmap objectID="1">
 31                 <matrix>
 32                   <Transform scaleX="20.00000000000000" scaleY="20.00000000000000" transX="-300" transY="-300"/>
 33                 </matrix>
 34               </ClippedBitmap>
:
 52       <DefineSprite objectID="3" frames="20">
 53         <tags>
 54           <PlaceObject2 replace="0" depth="1" objectID="2">
 55             <transform>
 56               <Transform transX="299" transY="299"/>
 57             </transform>
 58           </PlaceObject2>
 59           <ShowFrame/>
:
176       </DefineSprite>
177       <PlaceObject2 replace="0" depth="3" objectID="3" name="animation">
178         <transform>
179           <Transform transX="3541" transY="1031"/>
180         </transform>
181       </PlaceObject2>
:
182       <DefineBitsJPEG2 objectID="4">
183         <data>
184           <data>/9n/2P/Y/+AAEEp..
:
186       </DefineBitsJPEG2>
187       <DefineShape objectID="5">
188         <bounds>
189           <Rectangle left="0" right="3520" top="0" bottom="4160"/>
190         </bounds>
191         <styles>
192           <StyleList>
193             <fillStyles>
194               <ClippedBitmap objectID="4">
195                 <matrix>
196                   <Transform scaleX="20.00000000000000" scaleY="20.00000000000000" transX="0" transY="0"/>
197                 </matrix>
198               </ClippedBitmap>
:
216       <DefineSprite objectID="6" frames="1">
217         <tags>
218           <PlaceObject2 replace="0" depth="1" objectID="5">
219             <transform>
220               <Transform transX="0" transY="0"/>
221             </transform>
222           </PlaceObject2>
223           <ShowFrame/>
224           <End/>
225         </tags>
226       </DefineSprite>
227       <PlaceObject2 replace="0" depth="1" objectID="6" name="bg">

swfmill を使った FlashLite の動的生成処理を作る際は、(場合にもよりますが、)

  • ベースの SWF をそのまま保持しておき、動的に swf2xml => 差し替え処理 => xml2swf するよりは、
  • 上記のように XML 化したものを要素を差し替え可能な状態に適宜編集して保持しておき、動的に 差し替え処理 => xml2swf  したほうが、

応答速度的にも効率が良くなると思います。ですので、ここでベースの SWF の構造を XML 化しておき、差し替えをおこなう要素の構造を理解しておくとともに、この XML を差し替え可能な状態に編集し、テンプレートとして保存しておく事にします。

今回の要件では、ステージにムービークリップを配置した際のインスタンス名を “bg” または “animation” で指定してもらっているはずですので、まずはこれらがどこに位置しているかを見ていきます。FlashLite 1.1 でパブリッシュされた SWF では、ムービークリップは PlaceObject2 要素(Tag)で name 属性をともなって配置されているはずです。(このあたりの SWF の構造に関しては、Adobe 社が公開している SWF の仕様 – SWF Technology Center (必要に応じて Open Screen Project )も参考にしてください。)上記の場合では、

177       <PlaceObject2 replace="0" depth="3" objectID="3" name="animation">

の行と、

227       <PlaceObject2 replace="0" depth="1" objectID="6" name="bg">

が該当する事になります。

ここから、さらに PlaceObject2 が参照している object を辿っていきます。objectID 属性を確認すると、たとえば animation インスタンスは objectID=”3″ ですので、objectID=”3″ となっているムービークリップ要素 = DefineSprite 要素を探します。今回の例ですと:

 52       <DefineSprite objectID="3" frames="20">
 53         <tags>
 54           <PlaceObject2 replace="0" depth="1" objectID="2">
 55             <transform>

ここが該当します。このなかで、さらに PlaceObject2 により objectID=”2″ が参照されていますが、ここではムービークリップ内に設置されたキャラクタ画像が参照されているはずです。FlashLite 1.1 でムービークリップ内に画像を定義する方法は何種類かありますが、基本的には、

  • DefineBitsLossless2 もしくは DefineBitsJPEG2 で定義した画像データを、
  • //DefineShape/styles/fillStyles/ClippedBitmap で参照し、このシェイプを PlaceObject2 で配置する

というのが一般的な構造になるようです。今回は、上で指定されていた objectID=”2″ な DefineShape を辿って、さらにそのなかの ClippedBitmap というように、objectID をたどっていきます。最終的には、

 13       <DefineBitsLossless2 objectID="1" format="3" width="30" height="30" n_colormap="7">
 14         <data>
 15           <data>eNq9kEsO...

に行き着きます。ここの data 要素の中身が、アニメーションをおこなっているキャラクタ画像のビットマップデータということになります。今回はアニメーションとキャラクタ画像を丸ごと差し替えたいという要件ですので、このあたりの DefineBitsLossless2, DefineShape, DefineSprite の構造を、objectID の参照関係を維持したまま作り替えてやれば、アニメーション部分の差し替えができるということになります。

同様に、背景画像については上記 227 行目の PlaceObject2 で参照されている objectID=”6″ を追っていってやれば、

182       <DefineBitsJPEG2 objectID="4">
183         <data>
184           <data>/9n/2P/Y/+AAEEp..

に辿り着きますので、この data 要素を差し替えてやれば良い、ということになります。

対象の SWF の構造がわかったところで、この XML をテンプレート化します。差し替え処理の実装方法は幾つか考えられますが、

  • XML 中の置き換えをおこなう部分を場所を一意に特定できる文字列にしておき、プログラムからは文字列置換により書き換える
  • 置き換え対象部分を独自に定義した要素などに編集しておき、適当な XML 操作のための API (僕の場合は、PHP であれば SimpleXML、Ruby であれば REXML や Libxml-Ruby などを使ったりしてます) を介して書き換える

などの方法があります。前者は単純な文字列置換なので、対象の SWF がシンプルであれば非常に簡単に実装できますが、その分、.fla の制作ルールや実行環境によってはバグやセキュリティホールを作り込んでしまう可能性もあるので、注意した方が良いかもしれません。

ちょっと長くなってきたので、実際の入れ替え処理を書いていくところは、次回以降にしたいと思います。

まとめ

以上、2回にわたってケータイサイトで FlashLite コンテンツを動的生成する方法の概要をまとめてきました。全体の流れが見えると、ベースとなる SWF の制作ルールと、システム開発コストがどのように関連してきそうか、が、なんとなく見えてくるんじゃないかな、と思います。

実際のところ、制作ルールの策定は、動的生成処理の開発コストを、システム開発側とSWF制作側とで分担する割合/バランスを探る作業であるようにも感じています。ですので、全体の流れや仕組みの見通しが立たない事には、実サービスにこういった仕組みを入れていくのは大変かもしれません。

FlashLite 動的生成のシステムには何回か関わらせていただいていますが、正直なところ、こういった流れ、とくに制作側にいろんな制作ルールをお願いするようなやり方が本当に良いのかどうかは見え切れていません。今でも、わりと試行錯誤しています。この手のシステムに関わった方と情報交換する機会がほとんど無いので、いろんな方のご意見をうかがってみたいです。

さて、次回以降は、今回紹介したサンプルコンテンツの動的生成の続きから、実際に FlashLite 動的生成をやっていて使用したコードや、ハマったところなどが紹介できればと思います。

長々と読んでいただいてありがとうございました。期待せずにお待ちください。

Tagged with:
4月 16

以前、ケータイ Flash を中心に、細々と SWF バイナリを読んでいた時期があったのですが、そんなこんななご縁で、FlashLite コンテンツの動的生成(FlashIDEを介さずに、Webアプリケーションサーバ側で、SWF を自動作成する)方法について聞かれることが多いです。なんか、最近になってやけに多くなった気がするので、ちょっと理由を考えてみたのですが、

  • 大半のユーザが FlashLite 対応機種を持つようになった
    • アバター系(キャラとか部屋とか)着せ替え提供サイトが、より高精細(キレイでなめらか)なアニメーション素材を提供できるようになった
    • ケータイでFlashゲームをやる、という文化/リテラシが浸透してきた
  • FlashLite コンテンツは、通信制限や、1URLあたりのファイルサイズ制限などのケータイ特有の制限により、FlashLite 単独で動的なコンテンツにしづらい (ActionScript により、動的な処理をすべて SWF に入れ込む、というのが現実的でなく、Webアプリと絡めて都度 SWF を作り替える必要がある)
    • しかも、たいていの場合、FlashLite バージョンは下位機種に合わせて 1.1 にする必要があって、上記の制限がなかなか緩和されない

あたりの事が関係しているような気がします(もっとも、これ以外にも複数の理由が絡んでいるでしょうけど)。

もちろん、これ系のネタは検索すればいっぱい出てくるのですが、最近やけに聞かれるのは、新旧織り交ぜた情報が出てくるので、なかなか落としどころがわかりにくい、ということも関係しているような気がします。ということで、2009年4月現時点の情報として、僕の説明の省力化と知ってる事の整理も兼ねて、この件について、これから何回かに分けてまとめていこうと思います。

話題にするのは、たぶん、以下のような内容になります。

  • FlashLite コンテンツを動的に作成するケータイサイトの開発ステップ
    • 選択できる FlashLite の生成方法について
  • swfmill と適当な XML 処理系を組み合わせた方法による FlashLite コンテンツ動的生成
    • 画像を置き換えたつもりが、画像部分だけ真っ赤になった
    • jpegの部分にpngとかgifの画像を入れたい
    • swfmillでswf2xmlしたのを、そのままxml2swfしただけなのに再生できなくなった
    • 文字の入れ替えもやりたい。デバイスフォント以外も使える?
    • ActionScript 部分を書き換えたい

後半の swfmill を使う方法は、基本的なやり方はわりと Web で目にするので、上のような実際にサービスに入れ込んでいくときのハマりどころ/課題について、具体的に書けるといいなあ、と。

ただし、改めて書くまでもないことですが、あくまで僕の見解ですので、ご参考程度としていただければと思います。むしろ、実際どういう事やってるのかって聞く機会が少ないので、教えて欲しかったりします。あと、途中で書くのに飽きたらやめるかもしれません。すみませんすみません。

では、今回は、上記の前半部分、まずは FlashLite コンテンツを動的に作成するケータイサイトの開発ステップについて書いてみます。なお、ここで話題にするのは、「ケータイサイトの作り方」ではなく、「ケータイサイトのなかでも、FlashLite コンテンツを扱う部分の作り方」だけですので、ご期待に添えられなかったらすみません。

動的生成する範囲を見積もる

まずはじめに、サイト(サービス)のどの部分(Where)を FlashLite にするのかを見積もります。

画面遷移の資料やら、あとは、サイト全容の妄想やらをベースに、どこを FlashLite コンテンツにしたいのかを整理します。

(すくなくとも現時点では、)サイト全体が FlashLite コンテンツになる、ということは稀だとおもいます。たぶん、多くの場合、

  • スプラッシュページ
  • トップページの(階層)メニュー
  • ユーザ別にカスタマイズされたコンテンツ(アバターとか)
  • ゲーム

のいずれかに収まるんじゃないかとおもいます。

FlashLite コンテンツへの入出力と、そのなかで動的に取り扱いたい部分を確認する

以下、FlashLite コンテンツを SWF と表記します。

サイト内に SWF を入れ込む範囲が見えたら、具体的に、その SWF のなかの何(What)を動的に扱いたいのかを確認します。もうちょっと細かくいうと、

  • SWF が再生される際、どういう入力(input)をもらって、
  • その入力の結果、SWF のなかの何(What)を書き換えて、
  • SWF を操作(再生)した結果、どういう出力(output)を持って違う画面に遷移するのか

を整理する事になるのですが、ここでは、少なくとも2番目のWhatを押さえておきたいです。具体的には、以下のようなものが挙がるとおもいます。

  • 画像
  • 文字列
  • アニメーション
  • その他 ( ActionScript 内のロジックとか変数とか)

ここで挙がったものの種類/組み合わせと分量、それから、この後で検討する制作フロー云々が、動的生成の難易度に大きくかかわってきます。

制作フローを確認する

サイト内でFlashLiteを入れ込む範囲が見えたら、そのコンテンツ(SWF)の制作フローを確認します。サイトの運用(コンテンツ更新)まで見据えて、「誰が(Who)」「いつ(When)、どれくらいの頻度で(How often)」制作するかを確認し、見通しを立てます。

サービス開発時に、企画、デザイナ(というのは抵抗があるんですが)、開発者という3役割があるとすれば、恐らく、多くの場合において、SWF を制作するのはデザイナであると思います。たぶん、以下のようなフローになるような気がします。(ここでは、前の項の「input/output/What」の検討を含めたフローを書きます。)

  1. SWF への入出力(input/output)に見通しを立てる (全員で)
  2. Flash IDE でプロトタイプの fla ファイルを制作し、SWF でパブリッシュ (デザイナ)
  3. SWF 中の何(What)を、どのように動的にいじりたいかを整理 (全員で) (ここまでが前の項)
  4. 動的にいじる手段を選択 (主に開発者で)
  5. 決定した手段に応じて、SWF への入出力を決定 (主に開発者とデザイナで)
  6. fla の制作ルールを決める (主に開発者とデザイナで)
  7. 上の制作ルールに基づいて Flash IDE で fla ファイルを制作し、本番用の SWF をパブリッシュ (デザイナ)
  8. 制作した SWF を必要に応じてテンプレート化する (開発者もしくはデザイナで)
  9. テンプレート化した SWF をいじるアプリケーションを実装する (開発者)
  10. できあがり。運用時の更新は、7〜8〜9の繰り返し

ここでは、たとえば「毎週火曜日に」「毎月初に」などの SWF の定常更新があると想定し、更新フローまで考えてみましたが、サイトの性質によっては、サービス開始時にひとつ SWF のテンプレートをつくってしまえば、SWF の更新が必要ない場合もあるかもしれません。

ここでのポイントは、4 の「動的にいじる手段を選択」する部分と、それ以降のフローを作成する部分にあると思います。上記の全体のフローをなんとなく踏まえて、次の項でこれを検討してみます。

SWFを動的にいじる手段を選択する

ここでは、これまでの検討材料を受けて、実際に SWF をどのように(How)動的にいじっていくかを検討していきます。まずは、比較的大きな意思決定として、

  • 有償の SWF 動的生成ソフトウェアあるいは ASP を購入/契約し、導入する
  • OSS を併用するなどしながら、自社開発する

のどちらかを選ぶ事になると思います。これの判断材料を整理するのはむずかしいのですが、僕の感覚的には、次のいずれかに当てはまるようであれば、有償のものを検討した方が良いような気がします。

  • ここまでの項の検討が思うように進まない、あるいは、わからない
  • ここまでの項で検討した結果、ぴったり要件に当てはまるプロダクト/サービスが既にあって、自社でつくるよりもどう考えても安く、さらに、自社戦略的にその仕組みを自社でつくっておく必要もなさそう
  • 組織や開発体制の都合で、前項で検討したような制作フローの後半 = SWF の制作ルールやフローの検討に各担当者を巻き込んでいくのが難しい

恐らく、ここのブログを読む人は、「FlashLite 動的生成」などのキーワードで来られてるのではないかな、と思いますが、有償のプロダクト/サービスを検討する際は、検索ワードに「エンジン」あるいは「ASP」と追加してみると、プロダクトっぽいものが引っかかりやすいようです。ここで、特定の有償プロダクトを紹介する事はしませんが、最近はそこそこの月額コストで簡単に利用できるものもありますし、ASP やソフトウェアパッケージでありながらもコンサルティングサポートや簡単なカスタマイズに対応してくれる場合もあるようです。

いっぽう、有償のプロダクト/サービスを導入した場合は、以下のようなリスク/デメリットもあります。

  • サービスがトラブったときに、手を出しにくい (とくにブラックボックスの場合)
  • 比較的自由度が低いため、サービス仕様に対応できない場合や、運用開始後の仕様変更/サービス追加に対応できない場合がある

これらのリスク/デメリットや前項までに検討した input/output/What/When/How often を鑑みた結果、OSS を併用しながら自社開発する、という選択もあると思います。また、先の What を検討した際、SWF のいじくりたい部分が多様で複雑になった場合は、有償プロダクトで対応できない、いずれのプロダクトにも要件を満たせるものが無い、ということにもなったかもしれません。その場合は、大きく分けて、次の選択肢から選ぶ事になるような気がします。

  1. SWF バイナリ構造を理解し、スクラッチで所期の SWF いじくり処理を実装する
  2. ming を使って、プログラムから SWF を作成する
  3. flasm を使ったプログラムを実装し、ActionScript 部分だけ書き換える
  4. swfmill を使ったプログラムを実装し、SWF の中身を置き換える

ここでは、1 は長くなりそうなので説明しません。やってみると面白いんですけどね。ただし、ちょっとした工夫で、手間はほとんどかけずに所期の動的生成の要件を達成する事ができるケースもあります。これは、機会があれば書きます。

2 についてですが、ming って、プログラムから SWF を作るには便利なんですけど、既にある SWF をいじくるのにはあんまし向いてないように思います。(ming 派の方がいらっしゃったら教えて欲しい点でもありますが。)

3 は、わりとやってる人多いみたいな気がします。が、僕は SWF の画像をごりごりいじるところから入った人なので、あまり詳しくありません。

ということで、ActionScript もがんばれば書き換えできるし、かつ、SWF 中の任意の要素をいじくることができる、4 の swfmill を使う方法について、今後書いていこうと思います。

ちなみに、ActionScript を書き換える場合は mtasc という選択肢もあるのですが、mtasc は FlashLite1.1 コンテンツに対応していませんので、ここでは除外しています。あと、swfmill でダンプされた ActionScript コードは若干操作しにくいですので、ActionScript は flasm、それ以外は swfmill という合わせ技もアリかもしれません。

ちなみに、お気づきかもしれませんが、ここでは、「FlashLiteコンテンツを動的に生成したい」というニーズを、「既にあるSWFに含まれる何かを入れ替えてユーザ端末に送信したい」というニーズに置き換えて話を進めてきました。これも僕の感覚なので、全然違うかもなんですけど、多くの場合、「FlashLite 動的生成」を探してる人は、こういうニーズであるような気がします。

では、次回は、swfmill を使った SWF の動的生成と、これをケータイサイトのシステムに組み込んでいく場合の流れ(前項の 5 以降のステップ)について、書いていければと思います。期待せずにお待ちくださいませ (__)

Tagged with:
3月 16

Shibuya.abc #1に行ってきた(080315)

ActionScript コメントは受け付けていません。

BeInteractive! の yossy さんの呼びかけで始まった、変態さんたちの集いに行ってきました。参加しただけで、しゃべるネタが用意できなくてごめんなさい。でも、皆さんのお話や飲み会での会話は、思ってた以上に楽しくて、思う存分ニヤニヤできました。ニヤニヤ。

では、例によってメモを転記。

BeInteractive! yossyさん

  • Shibuya.abc 誕生の理由
  • AVM2, FlexSDK オープン化の話
  • たまりんと戯れる話
    • ビルド。ソース入手。
    • zlib のパスを Makefile にいれとく
    • avmplus できる。
    • asc ひろってくる。ビルトインのabcをパスの通ったとこにおく
    • as プログラムかく。クラス単位である必要なし。
    • コマンドライン引数を取得するテスト
      • 引数は — をつけてやらないといけないらしい。
    • 標準入力を取得するテスト
    • 直接実行できるようにするテスト。binfmt_misc つーので avmplus へ渡せるとかなんとか@linux
    • – で引数書かなくてすむように、ラッパーのシェルスクリプトを書いてやるテスト
  • ServerSide AS3 .. CGI で動くようにする
    • GET引数はQueryStringに入る。でもenvが取れない。
      • AVM2 を拡張する。SystemClass に getEnv() 追加。内部的には getenv システム関数を呼ぶ
      • ビルド方法がむずかしそう。ながい
      • 同様にPOSTもとれる。取り出すときは、Content-Length とかちゃんとチェックしてやる。
    • 独自のWebフレームワークを使って、ゲストブックを作る
      • javac のときに -AS3 フラグが要るらしい
  • Flashと連携する。BlaseDSを使う。AMF通信。移植したらしい。なんと。
  • swfassist もサーバサイドで動いたとな

クジラ飛行机さん

  • FlashLite でうごく言語をつくる
    • 言語を作ると出勤が週2でよくなることもある
    • 電車でつくるプログラミング言語
    • FL2.0 をつかった。パーサジェネレータで自動生成。コンパイルはサーバサイドでやる。アセンブラだけつくる
    • swfmill, flasm, kmyacc .. swfmill は simple モードを使う
    • flasm は swf の中のアクションを書き換えるのに使う
    • swfmillでテンプレートswfを作る。kmyaccでパーサを作る。flasmでアクションを書き換える
    • kmyacc で文法を作る。calc.phpy っていうサンプルを改造していく
      • 実行コードの中に、計算結果を返す代わりに、flasm のアセンブラ表記に書き換える形にする
      • PRINT をサポートさせる。字句解析ルールを追加。
      • サーバサイド処理を作る。ソース入力に対してyyparse()を実行して、flmの中身を書き換えてアセンブルする
  • 「葵」.. FLashベース開発環境
  • 八角研究所で情報公開中。AIRの本も書いてるそうです

鴨志田さん

  • A=ord(“d”) でニヤニヤする話
  • よりコンパクトに
    • 直接 値を書くよりも、何か評価した結果を値にもっていくことで、その命令セットと合わせてもちっちゃくなるばあいがある
    • substring(A,1,1) よりも chr(ord(A))
    • 変数名を短くする。コンスタントプールが使えない FL1.1 では重要
    • eval で数字やら制御文字を渡してやって変数名にする事もできる。そうすると使える一文字変数の数がふえる!eval(“t”) = 123; とか。
    • FL1.x で $_VARSION みると、5 系っぽい。試してみたら 5 のアクションも使えた。Increment とか使えた。SWFヘッダは4にしとく必要あり。
    • 複数の値をいっぺんに Push して、Push のヘッダ部分を節約する話 .. FL1.x 系でもいけたらしい
      • 変数が入る場合はgetVarも必要。交換法則が適用できるかどうかチェック必要
    • if で || やら && を使うと、コードサイズが2の冪乗でコードサイズが増える。
      • 各論理値を他方の式に対してそれぞれ重複して生成してしまうためらしい。A || A || A || .. ってたくさんかくだけで swf が 100K こえる
  • より高速に
    • SetRegister した値をすぐ使う場合は、直後の pop, push は要らない
    • 1万回の push[null] からオーバヘッドを測定。ヘッダ部分で 1.5μsec くらい
    • サイズが減る=アクション数が減る場合は、たいてい高速になる

TAKESAKO さん

  • Flashアンチリバースエンジニアリング
    • ライセンス。オープンにされている情報の話
    • swf を頭から読んでいく話。可変長タグの「データが無ければ飛ばされる」データを節約してファイルサイズを下げる話
    • 境界ジャンプを使う。逆コンパイラがジャンプのフローを解析できないものが多い。ジャンプ先のコードが正しく読めない
      • このテクニックを自動化するツール as2lock

gyuque さん

  • Gnash ぐなっしゅの話。オープン実装の Flash プレイヤー
  • ubuntu だとパッケージで入るらしい。でもビルドする。gtk いれとかないと mozilla 対応できない
  • 実験台swfアニメーション: アニメーションは完璧ぽい。BGM が変
  • ゲームをやってみる。クリック効かない。gotoAndPlay 追加して強制スタート。ぐちゃぐちゃになった。
  • Gnash は youtube を意識している?Youtube 再生結構完璧にいける。シークできない。バッファリングできない。
  • ソースを覗く。ソースツリーの解説。
    • swf.h に AVM2 のオペコードの実装が進んでるぽい形跡が
    • ASHander.cpp に各アクションの実装。動く仕様書というかんじ。
  • AVM を書いてみる。命令の解釈や実行スコープ管理を俺実装するデモ。それ以外は既存のVMに渡す
    • mtasc でコンパイルして defineFunction2 を置き換える
    • VM の教科書として最適?

nitoyon さん

  • avmplus how-to
  • irb みたいのがほしい。いちいちコンパイルがめんどくさい
    • ソースの中に AVMPLUS_INTERACTIVE てのが。コメントとってリビルドすると使えるようになった。おおおおお
    • でも、実行毎の状態は保持できない.. 内部的には毎回コンパイルして実行してるみたい。
    • class Hoge() {} に失敗。Object のビルトインが読み込まれてないためらしい。.import でビルトインのabcを呼んでやればOK
    • Windows でしか動かないみたい
  • winQuery .. Windows で jQuery 、みたいな Windows アプリ。
    • $(“explorer.exe”).close() みたくやりたい
    • as3Query をベースにする。
    • Window の構造を DOM として捉えるとできるんじゃないか?という仮説。nodeName=window名、className=プロセス名みたいにしてみる
    • print($(“.explorer:root:visible”)) とかで、見えてはいけないウィンドウまで見えちゃってニヤニヤ
    • ウィンドウのパーツを取得して動的に書き換えるとか。
    • 裏側では Win32 な関数をいっぱい書いてる。avmplus ってスクリプトエンジンとしても使えるんですね

こんなかんじ。wiki の方には nishio さんが Ust 中継された動画もあるみたいですので、そちらもどうぞー。

yossy さん、お声がけありがとうございました。おかげで楽しめました :)
yossy さんとは、前に amachang さん繋がりの勉強会 で会っていたと思うんだけど、今回はお話するタイミングを逸してしまった。残念。

それから、休日にもかかわらず、勉強会の場所を提供いただけるサイボウズラボさんには感謝です。TAKESAKO さん、飲み会の取りまとめまで、ありがとうございました。

ではでは、次回 Shibuya.abc[d-z]+ を楽しみにしております!

Tagged with: