Przykład filtrowania obiektów wyświetlanych: Filter Workbench

Flash 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:

  • Tworzenie instancji różnych filtrów

  • Zastosowanie różnych filtrów do obiektu wyświetlanego

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:

File

Opis

com/example/programmingas3/filterWorkbench/FilterWorkbenchController.as

Klasa udostępniająca podstawowe funkcjonalności aplikacji, w tym przełączanie zawartości, na którą nakładane są filtry, oraz samą funkcjonalność ich nakładania.

com/example/programmingas3/filterWorkbench/IFilterFactory.as

Interfejs definiujący typowe metody implementowane przez każdą z klas produkcyjnych filtru. Interfejs ten definiuje typowe funkcjonalności wykorzystywane przez klasę FilterWorkbenchController do interakcji z poszczególnymi klasami produkcyjnymi filtru.

w folderze com/example/programmingas3/filterWorkbench/:

BevelFactory.as

BlurFactory.as

ColorMatrixFactory.as

ConvolutionFactory.as

DropShadowFactory.as

GlowFactory.as

GradientBevelFactory.as

GradientGlowFactory.as

Zestaw klas, z których każda implementuje interfejs IFilterFactory. Każda z tych klas udostępnia funkcjonalność tworzenia i ustawiania wartości dla pojedynczego typu filtru. Panele właściwości filtru w aplikacji wykorzystują te klasy produkcyjne do tworzenia instancji poszczególnych filtrów, które klasa FilterWorkbenchController pobiera i nakłada na treść obrazu.

com/example/programmingas3/filterWorkbench/IFilterPanel.as

Interfejs definiujący typowe metody implementowane przez klasy definiujące panele interfejsu użytkownika używane do manipulowania wartościami filtru w aplikacji.

com/example/programmingas3/filterWorkbench/ColorStringFormatter.as

Klasa narzędzi obejmująca metodę konwersji wartości numerycznych koloru na heksadecymalny format String.

com/example/programmingas3/filterWorkbench/GradientColor.as

Klasa pełniąca rolę obiektu wartości, łącząca się w pojedynczy obiekt z trzema wartościami (kolor, alfa i współczynnik) skojarzonymi z poszczególnymi kolorami w GradientBevelFilter i GradientGlowFilter

Interfejs użytkownika (Flex)

FilterWorkbench.mxml

Główny plik definiujący interfejs użytkownika aplikacji.

flexapp/FilterWorkbench.as

Klasa udostępniające funkcjonalność dla interfejsu użytkownika aplikacji głównej; klasa ta jest używana jako klasa z kodem oddzielonym dla pliku MXML aplikacji.

W folderze flexapp/filterPanels:

BevelPanel.mxml

BlurPanel.mxml

ColorMatrixPanel.mxml

ConvolutionPanel.mxml

DropShadowPanel.mxml

GlowPanel.mxml

GradientBevelPanel.mxml

GradientGlowPanel.mxml

Zestaw składników MXML udostępniających funkcjonalności dla każdego panelu używanego do ustawiania opcji dla pojedynczego filtru.

flexapp/ImageContainer.as

Obiekt ekranowy działający jako kontener obrazu wczytywanego na ekran.

flexapp/controls/BGColorCellRenderer.as

Niestandardowy mechanizm renderujący komórki służący do zmiany koloru tła w składniku DataGrid

flexapp/controls/QualityComboBox.as

Niestandardowy element sterujący definiujący pole kombi, które może być używane jako ustawienie jakości w kilku panelach filtru.

flexapp/controls/TypeComboBox.as

Niestandardowy element sterujący definiujący pole kombi, które może być używane jako ustawienie typu w kilku panelach filtru.

Interfejs użytkownika (Flash)

FilterWorkbench.fla

Główny plik definiujący interfejs użytkownika aplikacji.

flashapp/FilterWorkbench.as

Klasa udostępniające funkcjonalność dla interfejsu użytkownika aplikacji głównej; klasa ta jest używana jako klasa dokumentu dla pliku FLA aplikacji.

W folderze flashapp/filterPanels:

BevelPanel.as

BlurPanel.as

ColorMatrixPanel.as

ConvolutionPanel.as

DropShadowPanel.as

GlowPanel.as

GradientBevelPanel.as

GradientGlowPanel.as

Zestaw klas udostępniających funkcjonalności dla każdego panelu używanego do ustawiania opcji dla pojedynczego filtru.

Dla każdej z klas w bibliotece pliku FLA aplikacji głównej istnieje również skojarzony symbol MovieClip, którego nazwa odpowiada nazwie klasy (na przykład symbol „BlurPanel” jest połączony z klasą zdefiniowaną w pliku BlurPanel.as). Składniki składające się na interfejs użytkownika, przyjmują nazwy i położenia w zakresie określonym tymi symbolami.

flashapp/ImageContainer.as

Obiekt wyświetlany działający jako kontener obrazu ładowanego na ekran.

flashapp/BGColorCellRenderer.as

Własny mechanizm renderujący komórki służący do zmieniania koloru tła w składniku DataGrid

flashapp/ButtonCellRenderer.as

Niestandardowy mechanizm renderujący komórki służący do uwzględniania składnika w postaci przycisku w komórce w składniku DataGrid

Zawartość filtrowanego obrazu

com/example/programmingas3/filterWorkbench/ImageType.as

Klasa ta stanowi wartość obiektową zawierającą typ i adres URL pojedynczego pliku obrazu, który aplikacja może załadować i nałożyć nań filtry. Ponadto klasa ta obejmuje również zestaw stałych reprezentujących rzeczywiste dostępne pliki obrazów.

images/sampleAnimation.swf,

images/sampleImage1.jpg,

images/sampleImage2.jpg

Obrazy oraz pozostała treść wizualna w aplikacji, na którą nakładane są filtry.

Eksperymentowanie z filtrami ActionScript

Aplikacja 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:

  • Ukośny (flash.filters.BevelFilter)

  • Rozmycie (flash.filters.BlurFilter)

  • Macierz kolorów (flash.filters.ColorMatrixFilter)

  • Konwolucja (flash.filters.ConvolutionFilter)

  • Cień (flash.filters.DropShadowFilter)

  • Blask (flash.filters.GlowFilter)

  • Faza gradientu (flash.filters.GradientBevelFilter)

  • Blask gradientu (flash.filters.GradientGlowFilter)

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:

  • Filtr macierz kolorów obejmuje zestaw elementów sterujących do bezpośredniej manipulacji typowymi właściwościami obrazu, takimi jak jasność, kontrast, nasycenie i barwa. Ponadto w macierzy kolorów można podać wartości niestandardowe.

  • Filtr konwolucji, który jest dostępny wyłącznie za pośrednictwem języka ActionScript, obejmuje zestaw powszechnie stosowanych wartości macierzy; ponadto istnieje możliwość określenia wartości niestandardowych. Mimo jednak że klasa ConvolutionFilter przyjmuje macierze o dowolnym rozmiarze, aplikacja Filter Workbench korzysta wyłącznie z macierzy o ustalonym rozmiarze 3 x 3, najczęściej stosowanym.

  • Filtr mapy przemieszczeń oraz filtr cieniujący, dostępne wyłącznie za pośrednictwem języka ActionScript, nie są dostępne w aplikacji Filter Workbench.

Tworzenie instancji filtra

Aplikacja 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świetlane

Zgodnie 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.