上の例では、まず、Swf#movieclips により、ふたつの SWF に含まれるムービークリップの ID 体系を確認しています。ムービークリップの ID を確認する際は、実用上は、そのうしろの行にあるような、Swf#movieclip_ids_named が便利かもしれません。これにより、ステージ上に置かれる際に付与されたインスタンス名を指定し、対象のムービークリップの ID が確認できます。
実際の入れ替えは、上のように、ハッシュを操作するような形式でおこなえます。ムービークリップは、内部で各種形状(シェイプ)や画像(ビットマップ)、テキスト情報などを参照していますが、入れ替え自体は、上のようなハッシュへの代入操作一発で、参照関係にあるリソースを丸ごと入れ替える事ができます。また、このとき、単純に上書きしてしまうと、内部で使用している ID が重複してしまうなど、ID 体系が狂ってしまうことになるので、Swf#write (のなかで呼ばれる Swf#regenerate) したタイミングで、よしなに ID の体系を調整(adjust)する処理が走るようになっています。
入れ替えのための事前処理として、ムービークリップをテンプレートパーツ化しておけるようにした
これは、FlashLite コンテンツの動的生成サイトを作ろうとした際、実用上必要になる事が多いので、ちょっと強引に作ってみた機能です。実際に、前節のようにムービークリップの入れ替えをおこなうと、内部的には SWF を XML に戻し、XML を書き換えて、XML を SWF に戻す、ということをやることになるため、Swfmill プロセスの起動コストがかさんでしまいます。また、ムービークリップの入れ替えでは、関連するリソースも一気に処理対象になるため、前節最後で書いたような、入れ替え後におこなう ID 体系の調整コストも無視できなくなってきてしまいます。
を表しています。真ん中のふたつは、上記の前半で得られるような、SWF の調査結果をもとに指定します。最後の引数は、明らかに重複の無い大きめの値をバッファを持って指定しておくと良いと思います。なお、引数を何も指定しなければ、テンプレート化の際に ID の調整はおこないませんので、regenerate の際に調整する必要が出てきます。
なお、ここでは、テンプレート化されたムービークリップは XML 化してファイルで永続化していますが、DB に突っ込んだり、容量が許すなら memcache などのキャッシュに載せておいたりという手を使っても良いと思います。
こんなかんじで作成したテンプレートを、以下のようなコードで差し込みます。ここでは、あらかじめ Swfmill#swf2xml した xml から初期化することで、元の SWF を読み込む際に Swfmill 起動が必要ないようにしています。
require '../lib/swfmill_util'
require 'pp'
#################################################################################
# test to regenerate swf using template movieclip
# initialize original swf by preserved xml generated by Swfmill::swf2xml.
# avoid analysing swf's structure using "template_mode".
swf = SwfmillUtil::Swf.parseXml(File.open("data/sample_template.xml").read, true)
# initialize template movieclip by preserved xml generated by Swf#templatize
# avoid analysing swf's structure using "template_mode".
animation = SwfmillUtil::DefineSprite.parseXml(File.open("data/animation_template.xml").read, true)
# check a target object_id
pp swf.movieclip_ids_named("animation") #=> ["5"]
# change movieclip
swf.movieclips["5"] = animation
# write swf changed movieclip.
# avoid adjusting object_id using "adjustment=false"
swf.write("data/regenerated.swf", false)
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
最近のコメント