フィルターの作成と適用

Flash Player 9 以降、Adobe AIR 1.0 以降

フィルターを使用すると、ドロップシャドウからベベルやぼかしまでの一連の効果を、ビットマップオブジェクトや表示オブジェクトに適用することができます。 各フィルターはクラスとして定義されています。したがって、フィルターを適用するにはフィルターオブジェクトのインスタンスを作成する必要がありますが、他のオブジェクトを作成する場合との違いはありません。 フィルターオブジェクトのインスタンスを作成した後は、表示オブジェクトの filters プロパティを使用して、そのインスタンスを表示オブジェクトに簡単に適用できます。BitmapData オブジェクトの場合は、applyFilter() メソッドを使用して簡単に適用することができます。

フィルターの作成

フィルターオブジェクトは、適切なフィルタークラスのコンストラクターメソッドを呼び出すだけで作成できます。例えば、DropShadowFilter オブジェクトを作成するには次のコードを使用します。

import flash.filters.DropShadowFilter; 
var myFilter:DropShadowFilter = new DropShadowFilter();

ここでは示していませんが、どのフィルタークラスのコンストラクターもそうであるように、DropShadowFilter() コンストラクターも、フィルター効果の外観のカスタマイズに使用可能ないくつかの任意指定のパラメーターを受け入れます。

フィルターの適用

フィルターオブジェクトを作成した後には、そのオブジェクトを表示オブジェクトまたは BitmapData オブジェクトに適用することができます。フィルターの適用方法は、フィルターを適用するオブジェクトによって異なります。

表示オブジェクトへのフィルターの適用

フィルター効果を表示オブジェクトに適用する場合、filters プロパティを使用して適用します。表示オブジェクトの filters プロパティは Array インスタンスであり、このインスタンスのエレメントは、その表示オブジェクトに適用されるフィルターオブジェクトです。表示オブジェクトにフィルターを 1 つだけ適用する場合は、次のように、フィルターインスタンスを作成して Array インスタンスに追加した後、その Array オブジェクトを表示オブジェクトの filters プロパティに割り当てます。

import flash.display.Bitmap; 
import flash.display.BitmapData; 
import flash.filters.DropShadowFilter; 
 
// Create a bitmapData object and render it to screen 
var myBitmapData:BitmapData = new BitmapData(100,100,false,0xFFFF3300); 
var myDisplayObject:Bitmap = new Bitmap(myBitmapData); 
addChild(myDisplayObject); 
 
// Create a DropShadowFilter instance. 
var dropShadow:DropShadowFilter = new DropShadowFilter(); 
 
// Create the filters array, adding the filter to the array by passing it as  
// a parameter to the Array() constructor. 
var filtersArray:Array = new Array(dropShadow); 
 
// Assign the filters array to the display object to apply the filter. 
myDisplayObject.filters = filtersArray;

オブジェクトに複数のフィルターを割り当てる場合は、単純にすべてのフィルターを Array インスタンスに追加します。その後で、filters プロパティにそのインスタンスを割り当てます。複数のオブジェクトを配列に追加するには、配列のコンストラクターにそれらをパラメーターとして渡します。 例えば、次のコードでは、既に作成されている表示オブジェクトにベベルフィルターとグローフィルターを適用します。

import flash.filters.BevelFilter; 
import flash.filters.GlowFilter; 
 
// Create the filters and add them to an array. 
var bevel:BevelFilter = new BevelFilter(); 
var glow:GlowFilter = new GlowFilter(); 
var filtersArray:Array = new Array(bevel, glow); 
 
// Assign the filters array to the display object to apply the filter. 
myDisplayObject.filters = filtersArray;

フィルターを含む配列を作成するときには、前の例に示したように、new Array() コンストラクターを使用して作成することができます。また、フィルターを角括弧([])で囲んで、配列リテラルシンタックスを使用することもできます。例えば、次のようなコード行があるとします。

var filters:Array = new Array(dropShadow, blur); 

この行の実行結果は次のコード行と同じになります。

var filters:Array = [dropShadow, blur];

複数のフィルターを表示オブジェクトに適用すると、それらのフィルターは順番に従って累積的に適用されます。 例えば、あるフィルター配列に 2 つのエレメントがあるとします。エレメントとしては、ベベルフィルターが最初に追加され、ドロップシャドウフィルターが 2 番目に追加されています。この場合、ドロップシャドウフィルターはベベルフィルターと表示オブジェクトの両方に適用されます。 これは、フィルター配列内でドロップシャドウフィルターの位置が 2 番目であるためです。フィルターを非累積的に適用する場合は、各フィルターを別個に表示オブジェクトの新しいコピーに適用します。

単一またはごく少数のフィルターを表示オブジェクトに適用する場合には、フィルターインスタンスの作成とオブジェクトへの適用を 1 つのステートメントで行うことができます。例えば、次のコード行は、myDisplayObject という名前の表示オブジェクトにぼかしフィルターを適用するものです。

myDisplayObject.filters = [new BlurFilter()];

上記のコードでは、配列リテラルシンタックス(角括弧)を使用して Array インスタンスを作成し、その Array のエレメントとして BlurFilter インスタンスを作成しています。さらに、myDisplayObject という名前の表示オブジェクトの filters プロパティに、その Array を割り当てています。

表示オブジェクトからのフィルターの削除

表示オブジェクトからすべてのフィルターを削除する操作は、次のように、filters プロパティに null 値を割り当てるだけの簡単な操作です。

myDisplayObject.filters = null;

オブジェクトに複数のフィルターを適用しており、それらのフィルターのうち 1 つだけを削除する必要がある場合には、複数の手順を実行して filters プロパティ内の配列を変更する必要があります。詳しくは、フィルター操作の潜在的な問題を参照してください。

BitmapData オブジェクトへのフィルターの適用

BitmapData オブジェクトにフィルターを適用するには、次のように BitmapData オブジェクトの applyFilter() メソッドを使用する必要があります。

var rect:Rectangle = new Rectangle(); 
var origin:Point = new Point(); 
myBitmapData.applyFilter(sourceBitmapData, rect, origin, new BlurFilter());

applyFilter() メソッドは、ソース BitmapData オブジェクトにフィルターを適用して、フィルター適用済みのイメージを新しく作成します。このメソッドによって元のソースイメージが変更されることはありません。その代わりに、ソースイメージにフィルターを適用した結果が、この applyFilter() メソッドが呼び出された BitmapData インスタンスに格納されます。

フィルターのしくみ

表示オブジェクトのフィルター処理は、元のオブジェクトのコピーを透明なビットマップとしてキャッシュするしくみになっています。

フィルターが表示オブジェクトに適用されると、そのオブジェクトに有効なフィルターリストがある限り、そのオブジェクトがビットマップとしてキャッシュされます。このソースビットマップは、それ以降に適用されるすべてのフィルター効果の元イメージとして使用されます。

通常、表示オブジェクトにはそれぞれ 2 つのビットマップがあります。1 つはフィルター適用前の元の表示オブジェクトのビットマップで、もう 1 つはフィルター適用後の最終イメージのビットマップです。 最終イメージはレンダリング時に使用されます。 表示オブジェクトが変更されない限り、最終イメージを更新する必要はありません。

フィルター操作の潜在的な問題

フィルターを操作する際には、混乱やトラブルの原因になる可能性があるため注意を必要とする事項がいくつかあります。

フィルターとビットマップキャッシュ

表示オブジェクトにフィルターを適用するには、そのオブジェクトのビットマップキャッシュを有効にする必要があります。 cacheAsBitmap プロパティが false に設定されている表示オブジェクトにフィルターを適用すると、オブジェクトの cacheAsBitmap プロパティが自動的に true に設定されます。表示オブジェクトのすべてのフィルターを削除すると、cacheAsBitmap プロパティは現在の設定値の直前の設定値にリセットされます。

実行時のフィルターの変更

表示オブジェクトに 1 つ以上のフィルターが既に適用されている場合、filters プロパティ配列にフィルターを追加したり、配列からフィルターを削除したりして、フィルターのセットを変更することはできません。その代わり、適用されているフィルターのセットを追加または変更するには、独立した配列に対して変更を行い、その配列を表示オブジェクトの filters プロパティに割り当てて、フィルターをオブジェクトに適用する必要があります。その最も簡単な方法は、filters プロパティ配列を Array 変数に読み込み、この一時配列に対して修正を行うことです。 次に、この配列を表示オブジェクトの filters プロパティに再度割り当てます。 さらに複雑な場合には、独立したマスタフィルター配列の保持が必要になる場合があります。マスタフィルター配列に対して変更を行い、変更ごとにマスタ配列を表示オブジェクトの filters プロパティに再度割り当てます。

フィルターの追加

次のコードは、1 つ以上のフィルターが既に適用されている表示オブジェクトにフィルターを追加するプロセスを示しています。まず、グローフィルターが myDisplayObject という名前の表示オブジェクトに適用されます。その後、この表示オブジェクトがクリックされたときに、関数 addFilters() が呼び出されます。この関数では、2 つの追加フィルターが myDisplayObject に適用されます。

import flash.events.MouseEvent; 
import flash.filters.*; 
 
myDisplayObject.filters = [new GlowFilter()]; 
 
function addFilters(event:MouseEvent):void 
{ 
    // Make a copy of the filters array. 
    var filtersCopy:Array = myDisplayObject.filters; 
 
    // Make desired changes to the filters (in this case, adding filters). 
    filtersCopy.push(new BlurFilter()); 
    filtersCopy.push(new DropShadowFilter()); 
 
    // Apply the changes by reassigning the array to the filters property. 
    myDisplayObject.filters = filtersCopy; 
} 
 
myDisplayObject.addEventListener(MouseEvent.CLICK, addFilters);

フィルターセットからのフィルターの削除

表示オブジェクトに複数のフィルターが適用されており、そのうち 1 つのフィルターを削除する一方、他のフィルターはオブジェクトに適用し続ける必要がある場合には、フィルターを一時配列にコピーし、不要なフィルターをその配列から削除して、表示オブジェクトの filters プロパティに一時配列を再度割り当てます。 配列から 1 つ以上の要素を削除する方法については、値の取得と配列要素の削除で説明します。

最も簡単なのは、オブジェクトの一番上のフィルター(オブジェクトに最後に適用されたフィルター)を削除する場合です。Array クラスの pop() メソッドを使用して、配列からフィルターを削除します。

// Example of removing the top-most filter from a display object  
// named "filteredObject". 
 
var tempFilters:Array = filteredObject.filters; 
 
// Remove the last element from the Array (the top-most filter). 
tempFilters.pop(); 
 
// Apply the new set of filters to the display object. 
filteredObject.filters = tempFilters;

同様に、一番下のフィルター(オブジェクトに最初に適用されたフィルター)を削除するには、Array クラスの pop() メソッドを shift() メソッドに置き換える以外は同じコードを使用します。

フィルターの配列の中間(配列に 3 つ以上のフィルターがあると仮定)からフィルターを削除するには、splice() メソッドを使用します。 削除するフィルターのインデックス(配列内の位置)を確認しておく必要があります。 例えば、次のコードでは、表示オブジェクトから 2 番目のフィルター(インデックス 1 のフィルター)を削除します。

// Example of removing a filter from the middle of a stack of filters 
// applied to a display object named "filteredObject". 
 
var tempFilters:Array = filteredObject.filters; 
 
// Remove the second filter from the array. It's the item at index 1  
// because Array indexes start from 0. 
// The first "1" indicates the index of the filter to remove; the  
// second "1" indicates how many elements to remove. 
tempFilters.splice(1, 1); 
 
// Apply the new set of filters to the display object. 
filteredObject.filters = tempFilters;

フィルターのインデックスの確認

フィルターのインデックスを確認するには、どのフィルターを配列から削除するのかを知っておく必要があります。削除するフィルターのインデックスを確認する(アプリケーションの設計方法による)か、または計算する必要があります。

最良の方法は、削除するフィルターが常にフィルターのセット内の同じ位置にくるように、アプリケーションを設計することです。例えば、畳み込みフィルターとドロップシャドウフィルターを(この順序で)1 つの表示オブジェクトに適用し、ドロップシャドウフィルターを削除する一方、畳み込みフィルターを保持する場合、どの Array メソッドが使用されるのか(この場合、ドロップシャドウフィルターを削除する Array.pop())を事前に確認できるように、フィルターは既知の位置(一番上のフィルター)にあります。

削除するフィルターが常に一定の種類だが、フィルターのセット内で常に同じ位置にあるとは限らない場合、配列内の各フィルターのデータ型を確認してどのフィルターを削除するのかを調べることができます。例えば、次のコードでは、フィルターのどのセットがグローフィルターであるかを調べ、そのフィルターをセットから削除しています。

// Example of removing a glow filter from a set of filters, where the 
//filter you want to remove is the only GlowFilter instance applied  
// to the filtered object. 
 
var tempFilters:Array = filteredObject.filters; 
 
// Loop through the filters to find the index of the GlowFilter instance. 
var glowIndex:int; 
var numFilters:int = tempFilters.length; 
for (var i:int = 0; i < numFilters; i++) 
{ 
    if (tempFilters[i] is GlowFilter) 
    { 
        glowIndex = i; 
        break; 
    } 
} 
 
// Remove the glow filter from the array. 
tempFilters.splice(glowIndex, 1); 
 
// Apply the new set of filters to the display object. 
filteredObject.filters = tempFilters;

さらに複雑な場合で、例えば削除するフィルターが実行時に選択される場合、最良の方法は、フィルターのマスタリストとして機能するフィルター配列の独立した永続コピーを保持することです。フィルターのセットを変更するときは必ず、マスタリストを変更し、そのフィルター配列を表示オブジェクトの filters プロパティとして適用します。

例えば、次のコードでは、複数の畳み込みフィルターが表示オブジェクトに適用されて、様々な視覚効果が作成されます。さらに、アプリケーションの後半では、これらのフィルターのうちの 1 つが削除され、他のフィルターは保持されます。この場合、コードでは、フィルター配列のマスタコピーおよび削除するフィルターへの参照が保持されます。特定のフィルターの検索および削除の方法は、フィルター配列の一時コピーを作成する代わりに、マスタコピーが操作された後に表示オブジェクトに適用されることを除いて、前述の方法に似ています。

// Example of removing a filter from a set of  
// filters, where there may be more than one  
// of that type of filter applied to the filtered  
// object, and you only want to remove one. 
 
// A master list of filters is stored in a separate, 
// persistent Array variable. 
var masterFilterList:Array; 
 
// At some point, you store a reference to the filter you 
// want to remove. 
var filterToRemove:ConvolutionFilter; 
 
// ... assume the filters have been added to masterFilterList, 
// which is then assigned as the filteredObject.filters: 
filteredObject.filters = masterFilterList; 
 
// ... later, when it's time to remove the filter, this code gets called: 
 
// Loop through the filters to find the index of masterFilterList. 
var removeIndex:int = -1; 
var numFilters:int = masterFilterList.length; 
for (var i:int = 0; i < numFilters; i++) 
{ 
    if (masterFilterList[i] == filterToRemove) 
    { 
        removeIndex = i; 
        break; 
    } 
} 
 
if (removeIndex >= 0) 
{ 
    // Remove the filter from the array. 
    masterFilterList.splice(removeIndex, 1); 
 
    // Apply the new set of filters to the display object. 
    filteredObject.filters = masterFilterList; 
}

この方法では(格納されたフィルター参照をフィルター配列の項目と比較して削除対象のフィルターを調べる場合)、フィルター配列の独立したコピーを保持する必要があります。なぜなら、格納されたフィルター参照を、表示オブジェクトの filters プロパティからコピーした一時配列内の要素と比較する場合、コードが機能しないからです。これは、配列を filters プロパティに割り当てる際に、内部でランタイムによって配列内の各フィルターオブジェクトのコピーが作成されるからです。これらのコピー(元のオブジェクトではなく)が表示オブジェクトに適用され、filters プロパティが一時配列に読み込まれると、その一時配列には、元のフィルターオブジェクトへの参照ではなく、コピーされたフィルターオブジェクトへの参照が含まれます。 その結果、前述の例では、プロパティを一時フィルター配列のフィルターと比較することによって、filterToRemove のインデックスを調べることができます。

フィルターとオブジェクト変形

ドロップシャドウなどのフィルター処理された領域のうち、表示オブジェクトの境界ボックスの矩形よりも外側にある部分は、ヒット検出の対象サーフェスの一部と見なされません。ヒット検出は、インスタンス同士の重なりや交差があるかどうかを判定する処理です。DisplayObject クラスのヒット検出メソッドはベクターベースであるため、ビットマップとして生成された結果に対してヒット検出を実行することはできません。例えば、ベベルフィルターをボタンインスタンスに適用した場合、そのインスタンスのベベル部分ではヒット検出を使用できません。

フィルターでは拡大/縮小、回転、および傾斜がサポートされません。フィルター処理した表示オブジェクト自体を拡大/縮小しても、すなわち scaleXscaleY を 100 %以外にしても、フィルター効果はインスタンスと共に拡大/縮小されません。つまり、インスタンスの元のシェイプを回転、拡大/縮小、または傾斜しても、そのインスタンスと共にフィルターも回転、拡大/縮小、または傾斜するわけではありません。

フィルターを適用してインスタンスをアニメーション化すると、リアルな効果を生成できます。インスタンスをネスト化し、BitmapData クラスを使用してフィルターをアニメーション化しても、同じ効果を実現できます。

フィルターとビットマップオブジェクト

BitmapData オブジェクトにフィルターを適用すると、cacheAsBitmap プロパティが自動的に true に設定されます。このようにして、実際には元のオブジェクトではなくオブジェクトのコピーにフィルターが適用されます。

このコピーは、その後、メイン表示で元のオブジェクトに重ねて配置され、最も近いピクセルに可能な限り近付けられます。 元のビットマップの境界が変化すると、フィルターが適用されたコピーのビットマップは、伸縮または歪曲されるのではなく、元のビットマップから再作成されます。

ビットマップオブジェクトのフィルターをすべてクリアすると、cacheAsBitmap プロパティは、フィルター適用前の値にリセットされます。