建立與套用濾鏡

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 實體,當中的元素就是套用至顯示物件中的濾鏡物件。若要將單一濾鏡套用至顯示物件,首先要建立濾鏡實體、將它加入 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;

如果您想要為物件指定多個濾鏡,只需在為 filters 屬性指定濾鏡之前,先將所有的濾鏡加入 Array 實體即可。您可以將多個物件當做參數傳遞至其建構函式,藉以將這些物件加入 Array 實體中。例如,下列程式碼將一個斜角濾鏡與一個光暈濾鏡套用至先前所建立的顯示物件上:

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() 建構函式 (如上一個範例所示) 來建立,或者使用 Array 常值語法,以方括弧 ( [] ) 括住這些濾鏡。例如,下列這行程式碼:

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

與接下來的程式碼作用相同:

var filters:Array = [dropShadow, blur];

如果您將多個濾鏡套用至顯示物件,則這些濾鏡會以累加、連續的方式來套用。例如,假設某個濾鏡陣列具有兩個元素,則會先加入斜角濾鏡,再加入投影濾鏡,而投影濾鏡會同時套用至斜角濾鏡與顯示物件上。這是因為投影濾鏡位於濾鏡陣列的第二個位置。如果您想要以非累加的方式來套用濾鏡,請將每個濾鏡分別套用到新的顯示物件副本。

如果您只是單純地將一或幾個濾鏡指定給顯示物件,則可以先建立濾鏡實體,並以單一陳述式將它指定給物件。例如,下列這一行程式碼會將模糊濾鏡套用至名為 myDisplayObject 的顯示物件:

myDisplayObject.filters = [new BlurFilter()];

上一段程式碼採用 Array 常值語法 (方括弧) 來建立 Array 實體,並建立一個 BlurFilter 實體做為 Array 的元素,接著將該 Array 指定給名為 myDisplayObject 之顯示物件的 filters 屬性。

移除顯示物件上的濾鏡

移除顯示物件上的所有濾鏡,作法與指定一個 null 值給 filters 屬性一樣容易:

myDisplayObject.filters = null;

如果您已經將好幾個濾鏡套用至物件上,而且只想要移除其中一個濾鏡,則必須透過幾個步驟,變更 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 實體。

濾鏡的運作方式

顯示物件會藉由將原始物件的副本快取為透明點陣圖來加上濾鏡。

一旦將濾鏡套用至顯示物件,只要物件包含有效的濾鏡清單,執行階段就會將物件快取為點陣圖。接著,這個來源點陣圖就會被當成所有後續套用之濾鏡效果的原始影像來使用。

每個顯示物件通常包含兩個點陣圖:其中一個是原始、未經濾鏡處理的來源顯示物件,另一個是經過濾鏡處理後的最終影像。顯示影像時是使用最終影像。只要不變更顯示物件,就不需要更新最終影像。

使用濾鏡的潛在問題

使用濾鏡時,請注意幾點可能讓您混淆或困擾的問題成因。

濾鏡和點陣圖快取

若要將濾鏡套用至顯示物件,必須啟用該物件的點陣圖快取功能。若您套用濾鏡的物件,其 cacheAsBitmap 屬性設為 false ,則該物件的 cacheAsBitmap 屬性會自動設為 true 。若您稍後從顯示物件移除所有濾鏡, cacheAsBitmap 屬性會重設為原本的設定。

在執行階段變更濾鏡

如果顯示物件已經套用了一個或多個濾鏡,您就不可以將其它濾鏡加入 filters 屬性陣列中,或從中移除濾鏡來變更濾鏡組。若要加入或變更要套用的濾鏡組,您必須變更個別的陣列,然後將該陣列指定給顯示物件的 filters 屬性,才能讓濾鏡套用到物件上。最簡單的方式是將 filters 屬性陣列讀入 Array 變數,然後修改這個暫存陣列。接著,您可以將此陣列重新指定給顯示物件的 filters 屬性。在較為複雜的案例中,您可能需要保留濾鏡的個別主陣列。請對該主濾鏡陣列進行任何變更,然後在每個變更後,將主陣列重新指定給顯示物件的 filters 屬性。

加入其它濾鏡

下列程式碼示範將其它濾鏡加入已經套用一或多個濾鏡之顯示物件的程序。首先,將光暈濾鏡套用至名為 myDisplayObject 的顯示物件;之後,每當按一下顯示物件時,就呼叫 addFilters() 函數。兩個額外的濾鏡就會透過這個函數套用至 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);

從一組濾鏡移除一個濾鏡

如果顯示物件已經套用多個濾鏡,而且您想要在繼續將其它濾鏡套用到該物件時移除其中一個濾鏡,您可以將濾鏡複製到暫存陣列、從該陣列移除不想要的濾鏡,然後將暫存陣列重新指定給顯示物件的 filters 屬性。從任何陣列移除一個或多個元素的數種方式詳述於 擷取值以及移除陣列元素 中。

最直接的方式,便是移除物件最上層的濾鏡 (套用到物件的最後一個濾鏡)。您可以使用 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 類別的 shift() 方法來取代 pop() 方法。

若要從濾鏡陣列的中間移除濾鏡 (假設該陣列有兩個以上的濾鏡),您可以使用 splice() 方法。您必須知道要移除之濾鏡的索引 (陣列中的位置)。例如,下列程式碼會從顯示物件移除第二個濾鏡 (索引 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;

判斷濾鏡的索引

您必須知道要從陣列移除哪個濾鏡,才會知道該濾鏡的索引。此外,您也需要知道 (根據設計應用程式的方式) 或計算要移除的濾鏡索引。

最好的方法是在設計您的應用程式時,讓您要移除的濾鏡永遠位於濾鏡組中的相同位置。例如,如果所擁有的單一顯示物件已套用迴旋濾鏡與投影濾鏡 (以該順序),而且您想要移除投影濾鏡但保留迴旋濾鏡,濾鏡會位於已知的位置 (最上層的濾鏡),因此您可以事先知道要使用的 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 屬性。

例如,下面列出的程式碼會將多個迴旋濾鏡套用至顯示物件來建立不同的視覺效果,並在稍後於應用程式中移除其中一個濾鏡,而保留其它的濾鏡。在此案例中,程式碼會保留濾鏡陣列的主副本,以及要移除之濾鏡的參考。尋找並移除特定的濾鏡與前述方法類似,但是不會製作濾鏡陣列的暫存副本,而是直接操作主副本,然後套用到顯示物件。

// 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 類別的感應區偵測方法屬於向量架構,您無法在點陣圖結果上執行感應區偵測。例如,如果您將斜角濾鏡套用到按鈕實體,實體的斜角部分就沒有感應區偵測作用。

濾鏡不支援縮放、旋轉和傾斜;當有濾鏡的顯示物件本身縮放時 ( scaleX scaleY 不是 100%),濾鏡效果並不會跟著實體一起縮放。這表示實體的原始形狀會旋轉、縮放或傾斜,但是濾鏡並未跟著實體一起旋轉、縮放或傾斜。

您可以將含有濾鏡的實體做成動畫以建立具真實感的特效,或巢狀放置實體並使用 BitmapData 類別進行濾鏡的動畫以達到此效果。

濾鏡和點陣圖物件

當您將任何濾鏡套用至 BitmapData 物件時, cacheAsBitmap 屬性就會自動設為 true 。這樣一來,濾鏡會實際套用至物件副本上,而不是套用至原始物件上。

接著,此副本會放置到主要顯示中 (於原始物件上) 且儘可能地接近最靠近的像素。如果原始點陣圖的邊界變更,就會從原始物件重新建立含濾鏡的點陣圖副本,而不是加以延伸或扭曲。

如果您清除了顯示物件的所有濾鏡,會將 cacheAsBitmap 屬性重設為套用濾鏡之前的屬性。