Przykład filtrowania obiektów wyświetlanych: Filter WorkbenchFlash Player 9 i nowsze wersje, Adobe AIR 1.0 i nowsze wersje Aplikacja Filter Workbench udostępnia interfejs użytkownika umożliwiający nakładanie różnych filtrów na obrazy oraz pozostałe treści wizualne, pozwalając przy tym na wgląd do uzyskanego kodu i wykorzystanie go do wygenerowania takiego samego efektu w języku ActionScript. Poza udostępnieniem narzędzia do eksperymentowania z filtrami aplikacja stanowi ilustrację następujących technik:
Aby pobrać pliki tej przykładowej aplikacji, należy przejść na stronę www.adobe.com/go/learn_programmingAS3samples_flash_pl. Pliki aplikacji Filter Workbench można znaleźć w folderze Samples/FilterWorkbench. Aplikacja składa się z następujących plików:
Eksperymentowanie z filtrami ActionScriptAplikacja Filter Workbench ma stanowić pomoc w eksperymentowaniu z efektami działania różnych filtrów oraz generowaniu kodu w języku ActionScript odpowiadającego za te efekty. Aplikacja umożliwia wybór spośród trzech różnych plików zawierających treść wizualną, w tym obrazów bitmapowych oraz animacji utworzonych przez program Flash, oraz nakładanie ośmiu różnych filtrów ActionScript na wybrany obraz, z osobna lub w połączeniu z innymi filtrami. Aplikacja obejmuje następujące filtry:
Po wybraniu przez użytkownika obrazu i nałożeniu na ten obraz filtru aplikacja wyświetla panel z elementami sterującymi specyficznymi właściwościami wybranego filtru. Na przykład, na poniższym obrazie widoczna jest aplikacja z wybranym filtrem Ukośny: W miarę, jak użytkownik dostosowuje właściwości filtru, podgląd jest aktualizowany w czasie rzeczywistym. Użytkownik może również zastosować wiele filtrów przez dostosowanie jednego z nich, kliknięcie przycisku Zastosuj, dostosowanie kolejnego filtru, kolejne kliknięcie przycisku Zastosuj itd. W panelu filtrów aplikacji obowiązują pewne ograniczenia i zasady:
Tworzenie instancji filtraAplikacja Filter Workbench obejmuje zestaw klas, po jednej dla każdego z dostępnych filtrów, które służą do tworzenia filtrów w poszczególnych panelach. W przypadku wybrania filtra przez użytkownika kod ActionScript skojarzony z panelem filtra tworzy instancję odpowiedniej klasy produkcyjnej filtra. (Klasy te są znane pod nazwą klas produkcyjnych, ponieważ ich celem jest tworzenie instancji innych obiektów, co przypomina w pewnym sensie produkcję przez zakład poszczególnych produktów). Za każdym razem po zmianie przez użytkownika wartości właściwości w panelu kod panelu wywołuje odpowiednią metodę w klasie produkcyjnej. Każda klasa produkcyjna obejmuje specyficzne metody, z których panel korzysta podczas tworzenia odpowiedniej instancji filtru. Na przykład, wybranie przez użytkownika filtru rozmycie powoduje utworzenie przez aplikację instancji BlurFactory. Klasa BlurFactory obejmuje metodę modifyFilter() przyjmującą trzy parametry: blurX, blurY oraz quality, które użyte razem tworzą żądaną instancję BlurFilter: 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));
}
Z drugiej strony wybór filtru Konwolucja oferuje większą elastyczność, a co za tym idzie, wiąże się również ze sterowaniem większym zakresem właściwości. W klasie ConvolutionFactory po wybraniu przez użytkownika innej wartości dla panelu filtra wywoływany jest następujący kod: 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));
}
Należy zauważyć, że w każdym przypadku po zmianie wartości filtra obiekt produkcyjny dysponuje zdarzenie Event.CHANGE w celu powiadomienia modułów wykrywania zdarzeń o zmianie wartości filtra. Klasa FilterWorkbenchController, która faktycznie odpowiada za nałożenie filtrów na filtrowaną treść, wykrywa to zdarzenie, co pozwala na stwierdzenie potrzeby pobrania nowej kopii filtra i ponownego zastosowania jej wobec filtrowanej treści. Klasa FilterWorkbenchController nie wymaga konkretnych, szczegółowych informacji o każdej z klas fabrycznych filtra — wymaga ona jedynie informacji o tym, czy filtr uległ zmianie oraz czy możliwe jest uzyskanie dostępu do jego kopii. W tym celu aplikację wyposażono w interfejs, IFilterFactory, który definiuje wymagane zachowanie klasy fabrycznej filtra tak, aby instancja FilterWorkbenchController aplikacji spełniała swoją rolę. Interfejs IFilterFactory definiuje metodę getFilter() używaną w klasie FilterWorkbenchController: function getFilter():BitmapFilter; Należy pamiętać, że definicja metody interfejsu getFilter() stanowi, że zwracany jest nie specyficzny typ filtra, a instancja BitmapFilter. Klasa BitmapFilter nie definiuje specyficznego typu filtra. Klasa BitmapFilter jest raczej klasą bazowa, na podstawie której konstruowane są wszystkie klasy filtrów. Każda klasa produkcyjna filtra definiuje specyficzną implementację metody getFilter(), w której zwracane jest odwołanie do skonstruowanego filtra obiektowego. Oto przykładowa skrócona wersja kodu źródłowego klasy ConvolutionFactory: public class ConvolutionFactory extends EventDispatcher implements IFilterFactory
{
// ------- Private vars -------
private var _filter:ConvolutionFilter;
...
// ------- IFilterFactory implementation -------
public function getFilter():BitmapFilter
{
return _filter;
}
...
}
W implementacji klasy ConvolutionFactory metody getFilter() zwraca ona instancję ConvolutionFilter, mimo że żaden obiekt wywołujący metodę getFilter() nie musi (zgodnie z definicją metody getFilter(), którą spełnia klasa ConvolutionFactory) dysponować informacją, że wymagane jest zwrócenie dowolnej instancji BitmapFilter, która może być instancją dowolnej klasy filtra ActionScript. Nakładanie filtrów na obrazy wyświetlaneZgodnie z poprzednimi objaśnieniami aplikacja Filter Workbench korzysta z instancji klasy FilterWorkbenchController (dalej zwanej „instancją kontrolera”), która przeprowadza faktyczne zadanie nakładania filtrów na wybrany obiekt wizualny. Zanim możliwe będzie nałożenie filtra przez instancję kontrolera, musi ona dysponować informacją, na jaki obraz lub treść wizualną ma zostać nałożony filtr. Po wybraniu obrazu przez użytkownika wywoływana jest metoda setFilterTarget() w klasie FilterWorkbenchController i przekazywana jest jedna ze stałych zdefiniowanych w klasie ImageType: public function setFilterTarget(targetType:ImageType):void
{
...
_loader = new Loader();
...
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, targetLoadComplete);
...
}
Korzystając z tych informacji, instancja kontrolera ładuje oznaczony plik, zapisując go w zmiennej instancji pod nazwą _currentTarget po jej załadowaniu: private var _currentTarget:DisplayObject;
private function targetLoadComplete(event:Event):void
{
...
_currentTarget = _loader.content;
...
}
Po wybraniu filtru przez użytkownika aplikacja wywołuje metodę setFilter() instancji kontrolera, udostępniając kontrolerowi odwołanie do odpowiedniego obiektu produkcyjnego filtra, przechowywanego w zmiennej instancji pod nazwą _filterFactory. private var _filterFactory:IFilterFactory;
public function setFilter(factory:IFilterFactory):void
{
...
_filterFactory = factory;
_filterFactory.addEventListener(Event.CHANGE, filterChange);
}
Należy zwrócić uwagę, że jak podano powyżej, instancja kontrolera nie zna specyficznego typu danych danej instancji produkcyjnej filtra; dysponuje ona tylko informacją, że obiekt implementuje instancję IFilterFactory, co oznacza że ma on metodę getFilter() i dysponuje zdarzenie change (Event.CHANGE) po zmianie filtra. Po zmianie przez użytkownika właściwości filtra w panelu filtra instancja kontrolera stwierdza, że filtr został zmieniony przez zdarzenie produkcyjne change filtra, które wywołuje metodę filterChange() instancji kontrolera. Ta metoda z kolei wywołuje metodę 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();
}
Faktyczna operacja nakładania filtra na obiekt wyświetlany odbywa się w metodzie applyTemporaryFilter(). Po pierwsze, sterownik pobiera odwołanie do filtru obiektowego przez wywołanie metody getFilter() filtra produkcyjnego. var currentFilter:BitmapFilter = _filterFactory.getFilter(); Instancja sterownika ma zmienną instancji Array o nazwie _currentFilters, w której zapisywane są wszystkie filtry, które zostały nałożone na obiekt wyświetlany. Kolejnym krokiem jest dodanie nowego zaktualizowanego filtra do tej tablicy: _currentFilters.push(currentFilter); Następnie kod przypisuje tablicę filtrów do właściwości filters obiektu wyświetlanego, co w rzeczywistości powoduje nałożenie filtrów na obraz: _currentTarget.filters = _currentFilters; Wreszcie, ponieważ ten najpóźniej dodany filtr jest nadal filtrem roboczym, nie powinien zostać nałożony na obiekt wyświetlany na stałe, jest zatem usuwany z tablicy _currentFilters: _currentFilters.pop(); Usunięcie tego filtra z tablicy nie wpływa na filtrowany obiekt wyświetlany, ponieważ obiekt wyświetlany tworzy kopię tablicy filtrów przypisaniu jej do właściwości filters, a następnie używa tej wewnętrzne tablicy, nie zaś tablicy oryginalnej. Z tego względu wszelkie zmiany dokonywane w tablicy filtrów nie mają wpływu na obiekt wyświetlany, dopóki tablica ta nie zostanie ponownie przypisana do właściwości filters obiektu wyświetlanego. |
|