Exempel på filtrering av visningsobjekt: Filter WorkbenchFlash Player 9 och senare, Adobe AIR 1.0 och senare I Filter Workbench finns ett användargränssnitt som du kan använda för att tillämpa olika filter på bilder och annat visuellt innehåll och se den kod som kan användas för att skapa samma effekt med ActionScript. Förutom ett verktyg för experimentering med filter, demonstrerar det här programmet följande tekniker:
Programfilerna för det här exemplet finns på www.adobe.com/go/learn_programmingAS3samples_flash_se. Programfilerna för Filter Workbench finns i mappen Samples/FilterWorkbench. Programmet består av följande filer:
Experimentera med ActionScript-filterProgrammet Filter Workbench är utformat för att hjälpa dig att experimentera med olika filtereffekter och generera relevant ActionScript-kod för den effekten. Programmet gör att du kan välja på tre olika filer med visuellt innehåll, inklusive bitmappsbilder och en animering som har skapats i Flash, och tillämpa åtta olika ActionScript-filter på den valda bilden, antingen var för sig eller i kombination med andra filter. Programmet innehåller följande filter:
När en användare har valt en bild och ett filter att tillämpa på den bilden visar programmet en panel med kontroller med vilka användaren kan ställa in det valda filtrets egenskaper. I följande bild visas programmet med avfasningsfiltret valt: När användaren ändrar filteregenskaperna uppdateras förhandsvisningen i realtid. Användaren kan också tillämpa flera filter genom att anpassa ett filter, klicka på Tillämpa, anpassa ett filter till, klicka på Tillämpa igen, o.s.v. Det finns några funktioner och begränsningar på programmets filterpaneler:
Skapa filterinstanserI Filter Workbench finns en uppsättning klasser, en för varje tillgängligt filter. Klasserna används på de olika panelerna för att skapa filtren. När en användare väljer ett filter skapas en instans av filterfabriksklassen av den ActionScript-kod som är kopplad till den filterpanelen. (Klasserna kallas fabriksklasser eftersom deras syfte är att skapa instanser av andra objekt, på ungefär samma sätt som en fabrik skapar enskilda produkter.) Varje gång en användare ändrar ett egenskapsvärde på panelen anropas motsvarande metod i fabriksklassen av panelkoden. Varje fabriksklass innehåller specifika metoder som används av panelen för att skapa motsvarande filterinstans. Om användaren till exempel väljer oskärpefiltret skapas en BlurFactory-instans. I klassen BlurFactory finns metoden modifyFilter() som tar tre parametrar: blurX, blurY och quality. Tillsammans används de för att skapa BlurFilter-instansen: private var _filter:BlurFilter; public function modifyFilter(blurX:Number = 4, blurY:Number = 4, quality:int = 1):void { _filter = new BlurFilter(blurX, blurY, quality); dispatchEvent(new Event(Event.CHANGE)); } Om användaren i stället väljer faltningsfiltret, får han eller hon ett filter med mycket större flexibilitet och därmed fler egenskaper att ställa in. I klassen ConvolutionFactory anropas följande kod när användaren väljer ett annat värde på filterpanelen: private var _filter:ConvolutionFilter; public function modifyFilter(matrixX:Number = 0, matrixY:Number = 0, matrix:Array = null, divisor:Number = 1.0, bias:Number = 0.0, preserveAlpha:Boolean = true, clamp:Boolean = true, color:uint = 0, alpha:Number = 0.0):void { _filter = new ConvolutionFilter(matrixX, matrixY, matrix, divisor, bias, preserveAlpha, clamp, color, alpha); dispatchEvent(new Event(Event.CHANGE)); } Observera, att varje gång filtervärdena ändras, skickas en Event.CHANGE-händelse för att meddela avlyssnarna att filtrets värden har ändrats. Klassen FilterWorkbenchController, som är den klass som faktiskt tillämpar filtren på det filtrerade innehållet, avlyssnar den händelsen för att veta när den ska hämta en ny version av filtret och tillämpa den på det filtrerade innehållet. Klassen FilterWorkbenchController behöver inte de specifika detaljerna i varje filterfabriksklass. Den behöver bara veta att filtret har ändrats och kunna komma åt en kopia av filtret. För att detta ska fungera innehåller programmet ett gränssnitt, IFilterFactory, som definierar vilket beteende en filterfabriksklass behöver ha för att programmets FilterWorkbenchController-instans ska kunna utföra sin uppgift. IFilterFactory definierar den getFilter()-metod som används i klassen FilterWorkbenchController: function getFilter():BitmapFilter; Observera att gränssnittsmetoden getFilter() definierar att den returnerar en BitmapFilter-instans och inte en viss typ av filter. Klassen BitmapFilter definierar inte en viss typ av filter. I stället är den en basklass som alla filterklasser bygger på. Varje filterfabriksklass definierar en viss implementering av metoden getFilter(). I den returneras en referens till filterobjektet som skapats av filterfabriksklassen. Här följer till exempel en förkortad version av källkoden för klassen ConvolutionFactory: public class ConvolutionFactory extends EventDispatcher implements IFilterFactory { // ------- Private vars ------- private var _filter:ConvolutionFilter; ... // ------- IFilterFactory implementation ------- public function getFilter():BitmapFilter { return _filter; } ... } I klassen ConvolutionFactorys implementering av metoden getFilter() returneras en ConvolutionFilter-instans, med det registreras inte nödvändigtvis av alla objekt som anropar getFilter(). Enligt den definition av metoden getFilter() som ConvolutionFactory följer måste alla BitmapFilter-instanser returneras. Det kan vara en instans av vilken som helst av ActionScript-filterklasserna. Tillämpa filter på visningsobjektSom förklarats i tidigare används en instans av klassen FilterWorkbenchController (kallas hädanefter ”kontrollenhetsinstansen”) i programmet Filter Workbench. Det är kontrollenhetsinstansen som faktiskt tillämpar filter på det valda visningsobjektet. Innan kontrollenhetsinstansen kan tillämpa ett filter måste den ha information om vilken bild eller vilket visuellt innehåll filtret ska tillämpas på. När användaren väljer en bild anropas metoden setFilterTarget() i klassen FilterWorkbenchController och en av konstanterna som definierats i klassen ImageType skickas som parameter: public function setFilterTarget(targetType:ImageType):void { ... _loader = new Loader(); ... _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, targetLoadComplete); ... } Med den informationen läser kontrollenhetsinstansen in den angivna filen och sparar den i en instansvariabel med namnet _currentTarget när den har lästs in: private var _currentTarget:DisplayObject; private function targetLoadComplete(event:Event):void { ... _currentTarget = _loader.content; ... } När användaren väljer ett filter, anropar programmet kontrollenhetsinstansens setFilter()-metod och skickar en referens till det relevanta filterfabriksobjektet till kontrollenhetsinstansen. Referensen sparas sedan i en instansvariabel med namnet _filterFactory. private var _filterFactory:IFilterFactory; public function setFilter(factory:IFilterFactory):void { ... _filterFactory = factory; _filterFactory.addEventListener(Event.CHANGE, filterChange); } Observera, att enligt beskrivningen ovan vet inte kontrollenhetsinstansen vilken specifik datatyp filterfabriksinstansen har. Den vet bara att objektet implementerar IFilterFactory-instansen, vilket innebär att den har en getFilter()-metod och att händelsen change (Event.CHANGE) skickas när filtret ändras. När användaren ändrar filtrets egenskaper på filterpanelen, registrerar kontrollenhetsinstansen att filtret har ändrats eftersom filterfabriksinstansens change-händelse anropar kontrollenhetsinstansens filterChange()-metod. Den metoden anropar i sin tur metoden applyTemporaryFilter(): private function filterChange(event:Event):void { applyTemporaryFilter(); } private function applyTemporaryFilter():void { var currentFilter:BitmapFilter = _filterFactory.getFilter(); // Add the current filter to the set temporarily _currentFilters.push(currentFilter); // Refresh the filter set of the filter target _currentTarget.filters = _currentFilters; // Remove the current filter from the set // (This doesn't remove it from the filter target, since // the target uses a copy of the filters array internally.) _currentFilters.pop(); } Arbetet med att tillämpa filtret på visningsobjektet görs i metoden applyTemporaryFilter(). Först får kontrollenheten en referens till filterobjektet genom att filterfabrikinstansens getFilter()-metod anropas. var currentFilter:BitmapFilter = _filterFactory.getFilter(); Kontrollenhetsinstansen har en Array-instansvariabel som heter _currentFilters. I den sparas alla filter som har tillämpats på visningsobjektet. Nästa steg är att lägga till det nyuppdaterade filtret i den arrayen: _currentFilters.push(currentFilter); Sedan tilldelar koden filterarrayen till visningsobjektets filters-egenskap som tillämpar filtren på bilden: _currentTarget.filters = _currentFilters; Slutligen, eftersom det senast tillagda filtret fortfarande är ”arbetsfiltret” ska det inte tillämpas permanent på visningsfiltret. Därför tas det bort från arrayen _currentFilters: _currentFilters.pop(); Att filtret tas bort från arrayen påverkar inte det filtrerade visningsobjektet eftersom ett visningsobjekt skapar en kopia av filterarrayen när det tilldelas till egenskapen filters. I visningsobjektet används den interna arrayen i stället för den ursprungliga. Det innebär att ändringar som görs i en filterarray inte påverkar visningsobjektet förrän arrayen åter tilldelas visningsobjektets filters-egenskap. |
|