Flashムービー内に読み込んだ画像ファイルのサイズを変更したり,加工を加えるには,“適切なタイミング”で処理を行うコツが必要です。今回はMovieClipLoaderクラスのイベントを利用して,適切なタイミングで処理を行う方法をご紹介します。

読み込んだ画像を加工する

 図1は,画像を読み込んでリサイズし,フィルタ効果をかけるムービーです。このムービーで読み込んでいる画像「photo001.jpg」は,ムービー内で表示しているものよりも少々大きく,図2のものです。

図1:画像を読み込むムービー(クリックするとムービーを表示します)

図2:実際に読み込んでいる画像(photo001.jpg)

この画像を読み込んで,大きさを変更し,さらにフィルタ効果を付加しているわけですね。

よくある間違い

 では,実際に画像を読み込んでリサイズしてみましょう。前回ご紹介したMovieClipLoaderクラスを使って,「photo001.jpg」という名前の画像ファイルを,インスタンス「photoFrame」に読み込むコードは,
//MovieClipLoaderクラスを生成
var mcLoader:MovieClipLoader = new MovieClipLoader();
//画像を読み込む
mcLoader.loadClip("photo001.jpg", photoFrame);
というものでしたね。

 では,もともとの大きさが横120×縦160の大きさのインスタンスに,横240×縦320の画像を読み込むとどうなるでしょうか? 実際にやってみましょう(図3)。

図3:単純に読み込む(クリックするとムービーを表示します)

結果はインスタンス「photoFrame」のあった位置に,元の画像の大きさのままで表示されますね。実はMovieClipLoaderクラスを使って任意のムービーや画像を読み込んだインスタンスは,読み込み完了後には元のインスタンスの位置,回転,および拡大・縮小の各プロパティの値以外は全部クリアされてしまうのです。つまり,大きさも読み込む画像の大きさに自動的に変更されてしまうというわけです。

 それならば,読み込み完了後にあらためて大きさを設定してあげればよさそうです。今度はコードに次のように2行のステートメントを追加してみました。

//MovieClipLoaderクラスを生成
var mcLoader:MovieClipLoader = new MovieClipLoader();
//画像を読み込む
mcLoader.loadClip("photo001.jpg", photoFrame);
photoFrame._width=160;  //幅を160に再設定
photoFrame._height=120; //高さを120に再設定

 今度はどうでしょうか?(図4

図4:loadClip直後に大きさを再設定(クリックするとムービーを表示します)

またダメでした。やっぱり意図したような大きさにはなってくれません。

 こうした失敗がなぜ起きるかというと,画像の読み込みまでにタイムラグがあるからなのです(図5)。

図5:タイムラグ

 外部の画像を読み込むような処理には,「読み込みが完了するまでの待ち時間」が発生します。ActionScriptでは,その読み込みの完了まで待つことをしないで,どんどん次のコードを実行していきます。このため,前述のコードでは「読み込みが完了し,読込画像の大きさにリサイズされる前に,大きさの再設定を済ませてしまっている」状態となります*1。つまり,きちんと「読み込みが完了した」事を確認する処理を作成し,確認ができた時点ではじめて大きさの再設定をしなくてはいけないというわけですね。

onLoadInitイベントハンドラ

 MovieClipLoaderには,この「画像の読み込みを完了した」ことを知らせるためのイベントハンドラが用意されています。MouseクラスやKeyクラスでおなじみですね。MovieClipLoaderクラスに用意されたイベントは,次の五つです(表1)。

表1:MovieClipLoaderクラスのイベントハンドラ
イベントハンドラ説明
onLoadInit読み込みが完了し,初期設定が行える状態になったときに発生
onLoadComplete読み込み完了時に発生。まだ大きさや幅などを取得/設定はできない
onLoadError読み込みエラーが発生したときに発生
onLoadStart読み込み開始時に発生
onLoadProgress読み込みプロセス中に発生

 このうち,「読み込みが完了した」ことを知らせるイベントハンドラは,「onLoadCompleteイベントハンドラ」です。さすが“コンプリート”の名前を持つイベントハンドラ,と言いたいところなのですが,実はこのイベントハンドラは,本当に「ファイル的に」読み込み完了した時点で発生します。その後に“Flashムービー的”に読み込んだムービーや画像の大きさ等を更新する処理があるのですが,その前に発生してしまうため,今回の目的である画像の大きさを再設定するのには向きません。

 Flashムービー的にインスタンスの大きさ等を取得/設定できる準備が完了したタイミングで処理を実行したい場合には「onLoadInitイベントハンドラ」*2を使用します。この仕組みを使ってサイズを再設定するコードは次のようになります。

//MovieClipLoaderクラスを生成
var mcLoader:MovieClipLoader = new MovieClipLoader();
//リスナーオブジェクトを作成
var listenerObject:Object = new Object();
//「onLoadInit」という名前の関数を作成し,初期化処理を記述
listenerObject.onLoadInit = function() {
  photoFrame._width = 120;
  photoFrame._height = 160;
};
//リスナーオブジェクトを登録
mcLoader.addListener(listenerObject);
//画像を読み込む
mcLoader.loadClip("photo001.jpg", photoFrame);

図6:onLoadInitイベントハンドラで大きさを再設定(クリックするとムービーを表示します)

今度はきちんと意図した大きさになってくれましたね。読み込んだムービーや画像の大きさを取得/変更したい場合には,このようにonLoadInitイベントハンドラを使用すればOKです。

 onLoadInitイベントハンドラはイベントハンドラ・メソッドの引数として,初期化処理の準備が完了したインスタンスへの参照を渡します。この仕組みを使うと,上記のコードのイベントハンドラ・メソッドの定義部分は,次のように書き換えることができます。

listenerObject.onLoadInit = function(m:MovieClip) {
  m._width = 120;
  m._height = 160;
};

 複数の画像を複数のMovieClipLoaderクラスを使って読み込む場合でも,同じリスナーオブジェクトを使って初期化処理を行うこともできますね。

//一つのリスナーオブジェクトを作成
var listenerObject:Object = new Object();
listenerObject.onLoadInit = function(m:MovieClip) {
  m._width = 90;
  m._height = 120;
};
//三つのインスタンスに読み込み開始
//初期化処理は共通のリスナーオブジェクトを使う
var mcLoader:MovieClipLoader
for(var i:Number=1;i<4;i++){
  mcLoader = new MovieClipLoader()
  mcLoader.addListener(listenerObject) //共通のリスナーオブジェクトを設定
  mcLoader.loadClip("photo00"+String(i)+".jpg", _root["photoFrame"+i])
}

 今回はMovieClipLoaderクラスのonLoadInitイベントハンドラを使った,読み込みを行ったインスタンスの初期化処理をご紹介しました。次回は,同じくMovieClipLoaderクラスの「onLoadProgress」イベントを使った,読み込み状況の把握方法をご紹介します。

【コーヒーブレイク】フィルタの設定でラクをする方法

 今回,最初にご紹介したムービーでは,写真を読み込み,サイズを調整し,さらにフィルタかけています。このフィルタをかける部分,正攻法で行くのならば,「flash.filters」内の各クラスをインポートし,フィルタの設定をする必要があり,少々面倒な処理となります。

 そこで,この処理を簡単に済ましてしまう方法をご紹介します。手順は簡単。ステージ上にひな型となるフィルタの設定を行ったインスタンスを一つ用意しておき,そのフィルタ設定を任意のインスタンスへとコピーするだけです(図A

図A:フィルタ設定を行ってあるインスタンスを用意しておく

ひな型となるインスタンスは,実行時には見えないようにステージ外へ配置したり,マスクを使って隠しておけば良いでしょう。あるいは_visibleプロパティを「false」に設定して非表示にしておいても構いません。

 外部からの画像を読み込み,初期化処理内で,インスタンスのフィルタ設定を管理している「filtersプロパティ」の値をそのままコピーすれば,簡単にFlash上であらかじめ用意しておいたフィルタの設定を適用することができます。

 例えば,フィルタを設定してあるインスタンスのインスタンス名が「f1」のときには,次のようなコードでフィルタの設定をコピーして適用できます。

//MovieClipLoaderクラスを生成
var mcLoader:MovieClipLoader = new MovieClipLoader();
//初期化処理
function onLoadInit(){
  m._width=120; //幅を設定
  m._height=160;  //高さを設定
  //インスタンス「f1」に適用しておいたフィルタを適用
  m.filters = f1.filters;
}
これなら,Flashでのオーサリング時に自分の目でフィルタの状態を確かめながらフィルタ効果を作成できますね。コードからフィルタを適用するのがちょっと苦手だ,という方は一度お試しください。簡単ですよ。


*1 ものすごい速さで読み込みが完了すると,奇跡的にサイズの再設定が間に合うかもしれませんが,通常はそんなことはまずありえません。

*2 「init」とは,初期化を表す「イニシャライズ(Initialize)」の略語だと思われます。昔からプログラムの世界では,初期化を行う処理の名前にこの「init」を使っているのです。「function init(){}」というコードがあれば「お,ここに初期化の処理をまとめてあるんだな。どれどれ」といった感じでわかりやすいのです。forステートメントのループカウンタ用の変数に「i」を使うのと同じような慣習ですね。