ActionScript3で、TrueTypeフォントを外部swfにして動的に呼び出す

Feb 27 2008

TTFをswfに埋め込む方法はmx:Styleなどを使えば簡単なのだが、例えば100種類フォントを使おうとするとひどく重いswfが出来上がってしまう。必要なフォントだけ動的にHTTP越しに取得できないかやってみた。

環境はFlex3。結果的に成功しましたが、ずいぶんややこしい実装になってしまいました。もっと簡単にやる方法があったら教えてくださいー。ActionScriptをいじるのは初めてなので思わぬ盲点がありそう。。

コードはcodereposに上げました。BSDライセンスで。
http://coderepos.org/share/browser/lang/actionscript/misc/myfont/trunk
svn checkout http://svn.coderepos.org/share/lang/actionscript/misc/myfont myfont


AS3で埋め込みフォントを使ってみる
出発点になったのが上記のページ。これだとswfをコンパイルしたときにTTFが埋め込まれ(TTF分のファイルサイズがswfに加わる)1つのフォントに1つクラスが出来上がる。100個作れば100のクラス名があるわけだが、まずそもそも任意のクラスをnewする方法がわからなかった。PHPだとこんな感じで複数あるクラスの中から1つをnewするのは簡単。

$className = 'anythingOK';
$c = new $className;

AS3では惜しいところまでいったのだが、コンパイルは通っても実行されない。下記のコメントアウトした方だとうまくいったがこれだとソースにハードコーディングせざるをえず、MyFontLabelの部分を動的に変えられない。

var classRef:Class = getDefinitionByName("MyFontLabel") as Class;
var myFont:Object = new classRef("hogehoge", 20);
//var myFont:Object = new classRef("hogehoge", 20) as MyFontLabel;

さらにもう1つ問題がある。外部swfにしたいクラスのメソッドを呼び出すコードが、親swfにあると、コンパイルしたときに外部swfのファイルサイズが親swfに加わってしまう。

基礎講座 SWFLoaderコントロール
がソースも見れてわかりやすい。
具体的にはここ。
LoadSWF(loadedSM.application).setInputData(input.text);
http://www.ebizsolution.jp/column/flex/src/SWFLoaderTest2.html

このsetInputDataはSWFLoaderで外部swfにしたクラス内に実装があるわけだが、コンパイル時に外部swfのasファイルが必須であり、呼び出し元のswfのファイルサイズが増えてしまう。フォントのように重いと外部swfにする意味がない。

八方塞がりかとも思われたが、同じソースの中の
loadedSM.application["indata"].text = input.text;
としている箇所は、コンパイル時にasファイルを要求されず、呼び出し元のswfのファイルサイズはそのままでいけた。出来上がったものも、これを使っている。

この辺り、僕が勘違いしているだけのような気もします。解決策ありそう。


さてここからはcodereposに上げたソースを元に。

app.mxml、FontListComboBox.mxmlはデモ用。MyFont.asが本体。binに前処理用のPHPスクリプト。

Top 100 | dafont.com
からダウンロードした約100個のフリーフォントを使っている。fontsディレクトリにTTFファイルを展開。

READMEにあるように、bin/makefontswf.phpを使って100個のswfを生成。asとmxmlの2つのファイルを生成してmxmlcでコンパイルしている。
やっつけでパスなどハードコーディングしてしまった箇所があるので適宜変えてください。あと、FreeFont_*.mxmlの、のXY座標をいい加減な位置にしているのとフォントサイズとカラーを指定できないのが気持ち悪い。this['indata'].textをXMLのように書式化してパースすれば後者の問題は解決するはず。

READMEの2行目のコマンドでデモ用に、bin/makefontlist.phpを使ってフォント一覧のComboBoxを生成するmxmlファイルを作っておく。

app.mxmlで呼び出しているMyFontクラスが本体。SWFLoaderを使って外部swfを呼び出し、application["indata"].dataを書き換えることで外部swf(自動生成されたFreeFont_*.mxml)にあるdataChangeから内部のメソッドを呼び出す、という怪しげな手段を取っている。

ハマったのがMyFont.asの30行目のaddEventListener。最初はEvent.COMPLETEでやっていたのだが、コールバック関数内でloadedSM.applicationがnullだ、と怒られてしまう。Timerで無理矢理時間差を作れば動いたので、COMPLETE時にはswfの初期化がまだ終わっていないことが判明。APPLICATION_COMPLETEというイベントを発見して無事解決。

そんなこんなでコンパイルできたswfはこれ。テキストボックスに入れた文字列がComboBoxで選択中のフォントで表示される。フォントの関係で英字のみ。
http://zuzara.org/pub/myfont/app.swf

app.swf自体は233KBで各フォントは100〜1000KB。
swfはフォントごとに読みにいくようになっています。

AS3というよりActionScript自体初めてで結構苦労しました。。何に使うんだよ、という気もしますが参考になれば。

追記
高速にタイプするとchangeで呼び出しているメソッド内でエラーが出ます。解決策がわからない。。

2 responses so far

  1. Flya用に、ちょうどテロップを作っていたのですが、
    この方法だと回避していた問題がクリアできちゃいそうです。

    日本語の場合、埋め込みたい部分的な所だけを動的に扱うのはどうなんでしょう?

  2. ロードが終わるまでプログレスバーを出すなどの処理は必要そうですね。
    でもどうしても、でないならシステムフォントを使った方が軽くていいような気がします。

    あるいは元のTTFから常用漢字&サイズ限定で抽出して軽くできるとよさげです。

Leave a Reply