Skapa och tillämpa filter

Flash Player 9 och senare, Adobe AIR 1.0 och senare

Med filter kan du tillämpa en mängd effekter på bitmappsbilder och visningsobjekt, från skuggor till avfasning och oskärpa. Varje filter definieras som en klass. När du tillämpar filter måste du därför skapa instanser av filterobjekt på samma sätt som när du skapar andra objekt. När du har skapat en instans av ett filterobjekt kan det enkelt tillämpas på ett visningsobjekt med objektets filters-egenskap, eller för ett BitmapData-objekt, med metoden applyFilter().

Skapa ett filter

Om du vill skapa ett filterobjekt anropar du bara konstruktormetoden hos den filterklass du har valt. Om du till exempel vill skapa ett DropShadowFilter-objekt använder du följande kod:

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

Konstruktorn DropShadowFilter() visas inte här, men den (liksom alla filterklassers konstruktorer) tar flera valfria parametrar som kan användas för att anpassa filtereffektens utseende.

Tillämpa ett filter

När du har skapat ett filterobjekt med konstruktorn kan du tillämpa det på ett visningsobjekt eller ett BitmapData-objekt. Hur du tillämpar filtret beror på vilket objekt du tillämpar det på.

Tillämpa ett filter på ett visningsobjekt

När du tillämpar filtereffekter på ett visningsobjekt gör du det med egenskapen filters. Egenskapen filters i ett visningsobjekt är en Array-instans vars element är de filterobjekt som tillämpas på visningsobjektet. Om du vill tillämpa ett enda filter på ett visningsobjekt skapar du filterinstansen, lägger till den i en Array-instans och tilldelar Array-objektet till visningsobjektets filters-egenskap:

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;

Om du vill tilldela flera filter till objektet lägger du bara till dem i Array-instansen innan du tilldelar den till egenskapen filters. Du kan lägga till flera objekt i en Array genom att skicka dem som parametrar till dess konstruktor. I följande kod tillämpas till exempel ett avfasningsfilter och ett glödfilter på det visningsobjekt som skapats tidigare:

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;

När du skapar arrayen som innehåller filtren kan du skapa den med konstruktorn new Array() (vilket visas i de föregående exemplen) eller också kan du använda litteral Array-syntax och placera filtren inom hakparenteser ([]). Till exempel gör följande kodrad:

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

samma sak som den här kodraden:

var filters:Array = [dropShadow, blur];

Om du tillämpar flera filter på visningsobjekt tillämpas de kumulativt ett i taget. Om en filterarray till exempel har två element, ett avfasningsfilter som läggs till först och ett skuggfilter som läggs till därefter, tillämpas skuggfiltret på både avfasningsfiltret och visningsobjektet. Detta beror på att skuggfiltret kommer efter avfasningsfiltret i filterarrayen. Om du inte vill tillämpa filtren kumulativt måste du tillämpa varje filter på en ny kopia av visningsobjektet.

Om du bara tilldelar ett eller ett fåtal filter till ett visningsobjekt kan du skapa filterinstansen och tilldela den till objektet med en enda programsats. Följande kodrad tillämpar till exempel ett oskärpefilter på ett visningsobjekt med namnet myDisplayObject:

myDisplayObject.filters = [new BlurFilter()];

I ovanstående kod skapas en Array-instans med litteral Array-syntax (hakparenteser), en BlurFilter-instans skapas som ett element i arrayen och arrayen tilldelas till egenskapen filters i visningsobjektet myDisplayObject.

Ta bort filter från ett visningsobjekt

Att ta bort alla filter från ett visningsobjekt är enkelt. Tilldela bara värdet null till egenskapen filters:

myDisplayObject.filters = null;

Om du har tillämpat flera filter på ett objekt och bara vill ta bort ett av dem måste du gå igenom flera steg för att ändra filters-egenskapens array. Mer information finns i Potentiella problem vid arbete med filter.

Tillämpa ett filter på ett BitmapData-objekt

För att kunna tillämpa ett filter på ett BitmapData-objekt måste du använda BitmapData-objektets applyFilter()-metod:

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

Metoden applyFilter() tillämpar ett filter på ett BitmapData-källobjekt, vilket ger en ny, filtrerad bild. Metoden ändrar inte originalkällbilden. I stället gör filtret att källbilden sparas i BitmapData-instansen, som metoden applyFilter() sedan anropas för.

Så fungerar filter

Filtrering av visningsobjekt fungerar genom att en kopia av originalobjektet sparas i cache-minnet som en genomskinlig bitmappsbild.

När ett filter har använts på ett visningsobjekt cachelagras objektet som en bitmapp så länge objektet har en giltig filterlista. Källbitmappsbilden används sedan som originalbild för alla efterföljande filtereffekter som tillämpas.

Varje visningsobjekt har vanligtvis två bitmappsbilder: en med det ursprungliga ofiltrerade källvisningsobjektet och en för den slutliga bilden efter filtrering. Den slutliga bilden används för rendering. Så länge visningsobjektet inte ändras behöver den slutgiltiga bilden inte uppdateras.

Potentiella problem vid arbete med filter

Det finns flera saker som kan skapa förvirring eller problem och som du bör tänka på när du arbetar med filter.

Filter och bitmappscache-lagring

För att ett filter ska kunna tillämpas på ett visningsobjekt måste bitmappscache-lagring vara aktiverad för det objektet. När du använder ett filter på ett visningsobjekt vars cacheAsBitmap-egenskap är inställd på false anges objektets cacheAsBitmap-egenskap automatiskt till true. Om du senare tar bort alla filter från visningsobjektet återställs egenskapen cacheAsBitmap till sitt senaste värde.

Ändra filter vid körning

Om ett eller flera filter redan tillämpas på ett visningsobjekt kan du inte ändra uppsättningen filter genom att lägga till fler filter eller ta bort filter från filters-egenskapens array. Om du vill lägga till eller ändra uppsättningen filter som tillämpas måste du i stället göra ändringarna i en separat array, och sedan tilldela denna array till visningsobjektets filters-egenskap så att filtren tillämpas på objektet. Det enklaste sättet att göra detta är att läsa in filters-egenskapens array till en Array-variabel och göra ändringarna i denna tillfälliga array. Sedan tilldelar du om denna array tillbaka till visningsobjektets filters-egenskap. I mer komplicerade fall kanske du behöver ha en separat huvudarray med filter. Du kan göra ändringarna i denna huvudfilterarray, och sedan tilldela om huvudarrayen till visningsobjektets filters-egenskap efter varje ändring.

Lägga till fler filter

I följande kod visas hur du lägger till ett till filter för ett visningsobjekt där ett eller flera filter redan tillämpas. Först tillämpas ett glödfilter på visningsobjektet myDisplayObject. När användaren sedan klickar på visningsobjektet anropas funktionen addFilters(). I den här funktionen läggs ytterligare två filter till i 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);

Ta bort ett filter från en uppsättning filter

Om flera filter tillämpas på ett visningsobjekt, och du vill ta bort ett av filtren medan de andra fortfarande ska användas, kopierar du filtren till en tillfällig array, tar bort filtret du inte vill ha från arrayen och tilldelar sedan om den tillfälliga arrayen tillbaka till visningsobjektets filters-egenskap. Olika sätt att ta bort ett eller flera element från en array beskrivs i Hämta värden och ta bort arrayelement.

Det enklaste är att ta bort det översta filtret för objektet (det som tillämpats senast på objektet). Du tar bort filtret från arrayen med klassens Arrays pop()-metod:

// 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;

När du tar bort det understa filtret (det första som tillämpats på objektet) använder du samma kod, men använder klassen Arrays shift()-metod i stället för metoden pop().

Om du vill ta bort ett filter från mitten av en array med filter (förutsatt att arrayen har fler än två filter) kan du använda metoden splice(). Du måste känna till indexet (placeringen i arrayen) för filtret som du vill ta bort. Följande kod tar till exempel bort det andra filtret (filtret vid index 1) från ett visningsobjekt:

// 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;

Ta reda på ett filters index

Du måste veta vilket filter som du vill ta bort från arrayen, så att du vet filtrets index. Du måste antingen känna till (genom hur programmet är designat), eller beräkna indexet för filtret som ska tas bort.

Det bästa är att designa programmet så att filtret som du vill ta bort alltid finns på samma plats i uppsättningen med filter. Om du till exempel har ett enda visningsobjekt med ett faltningsfilter och ett skuggfilter (i den ordningen), och du vill ta bort skuggfiltret men behålla faltningsfiltret, finns filtret i en känd position (det översta filtret) så att du i förväg vet vilken Array-metod som ska användas (i det här fallet Array.pop() för att ta bort skuggfiltret).

Om filtret som du vill ta bort alltid är av en viss typ, men inte nödvändigtvis finns i samma position i uppsättningen med filter, kan du kontrollera datatypen för filtren i arrayen när du vill ta reda på vilket som ska tas bort. Följande kod tar till exempel reda på vilket filter i en uppsättning som är ett glödfilter, och tar bort det filtret från uppsättningen.

// 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;

I ett mer komplicerat fall, till exempel om filtret som ska tas bort väljs under körning, är det bäst att ha en separat, beständig kopia av filterarrayen som fungerar som huvudlista för filtren. När du vill ändra i uppsättningen med filter ändrar du huvudlistan och tillämpar sedan den filterarrayen som visningsobjektets filters-egenskap.

I följande kodexempel tillämpas flera faltningsfilter på ett visningsobjekt för att skapa olika visuella effekter. Vid en senare punkt i programmet tas ett av dessa filter bort medan de andra finns kvar. I det här fallet behåller koden både en huvudkopia av filterarrayen och en referens till filtret som ska tas bort. Att söka efter och ta bort ett speciellt filter påminner om det tidigare tillvägagångssättet, men i stället för att skapa en tillfällig kopia av filterarrayen ändras huvudkopian och den tillämpas sedan på visningsobjektet.

// 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; 
}

I det här fallet (när du jämför en lagrad filterreferens med objekten i filterarrayen för att ta reda på vilket filter som ska tas bort), måste du behålla en separat kopia av filterarrayen. Koden fungerar inte om du jämför den lagrade filterreferensen med elementen i en tillfällig array som kopieras från visningsobjektets filters-egenskap. Detta har interna orsaker. När du tilldelar en array till egenskapen filters skapas automatiskt en kopia av varje filterobjekt i arrayen. Dessa kopior (och inte de ursprungliga objekten) tillämpas på visningsobjektet. När du läser in egenskapen filters till en tillfällig array innehåller den tillfälliga arrayen referenser till de kopierade filterobjekten i stället för referenser till de ursprungliga filterobjekten. Om du i föregående exempel försöker att ta reda på indexet för filterToRemove genom att jämföra det med filtren i en tillfällig filterarray, hittas därför inga matchningar.

Filter och objektomformningar

Inget filterområde (till exempel skugga) utanför visningsobjektets begränsningsram anses vara del av ytan när det gäller att identifiera en träff (avgöra om en instans överlappar eller korsar en annan instans). Eftersom klassen DisplayObjects träffidentifiering är vektorbaserad, kan den inte utföras på ett bitmappsresultat. Exempel: Om du använder ett avfasningsfilter på en knappinstans, är träffidentifieringen inte tillgänglig på avfasningsdelen i instansen.

Skalning, rotering och skevning stöds inte av filter. Om själva visningsobjektet som filtreras är skalat (om scaleX och scaleY inte är 100 %), skalas inte filtereffekten med instansen. Det betyder att den ursprungliga formen i instansen roteras, skalas eller skevas. Däremot roteras, skalas eller skevas inte filtret med instansen.

Du kan animera en instans med ett filter för att skapa realistiska effekter eller kapsla in instanser och använda klassen BitmapData för att animera filter och få den här effekten.

Filter och bitmappsobjekt

Om du använder ett filter på ett BitmapData-objekt ställs egenskapen cacheAsBitmap automatiskt in på true. Det innebär att filtret i själva verket tillämpas på kopian av objektet i stället för på originalet.

Kopian placeras sedan på huvudvisningsobjektet (över det ursprungliga objektet) så nära närmsta pixel som möjligt. Om den ursprungliga bitmappens gränser ändras, skapas den filtrerade kopian av bitmappen om från originalet i stället för att sträckas ut eller förvrängas.

Om du tar bort alla filter för ett visningsobjekt återställs egenskapen cacheAsBitmap till den inställning den hade innan filtret tillämpades.